Don't always mark array types as precise.

Array types are always final, as they cannot be sub-classed, they may be
assigned by types that aren't themselves, e.g. Object[] may be assigned a
String[]. Introduce CannotBeAssignedFromOtherTypes to capture this property
and use in the verifier instead of IsFinal to mark things as precise.

Change-Id: I34debd3164ca1b876be94b6722457cee6e1e9bd3
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 0661b42..16ca2bd 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -235,6 +235,23 @@
     return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
   }
 
+  // Can references of this type be assigned to by things of another type? For non-array types
+  // this is a matter of whether sub-classes may exist - which they can't if the type is final.
+  // For array classes, where all the classes are final due to there being no sub-classes, an
+  // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other
+  // types as the component is final.
+  bool CannotBeAssignedFromOtherTypes() const {
+    if (!IsArrayClass()) {
+      return IsFinal();
+    } else {
+      Class* component = GetComponentType();
+      if (component->IsPrimitive()) {
+        return false;
+      } else {
+        return component->CannotBeAssignedFromOtherTypes();
+      }
+    }
+  }
 
   String* GetName() const;  // Returns the cached name.
   void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);  // Sets the cached name.
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 8ca5b82..6338659 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -2613,7 +2613,8 @@
   const RegType& referrer = GetDeclaringClass();
   mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
   const RegType& result =
-      klass != NULL ? reg_types_.FromClass(descriptor, klass, klass->IsFinal())
+      klass != NULL ? reg_types_.FromClass(descriptor, klass,
+                                           klass->CannotBeAssignedFromOtherTypes())
                     : reg_types_.FromDescriptor(class_loader_, descriptor, false);
   if (result.IsConflict()) {
     Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -2829,8 +2830,9 @@
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
       mirror::Class* klass = res_method->GetDeclaringClass();
-      const RegType& res_method_class = reg_types_.FromClass(ClassHelper(klass).GetDescriptor(),
-                                                             klass, klass->IsFinal());
+      const RegType& res_method_class =
+          reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                               klass->CannotBeAssignedFromOtherTypes());
       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 << "'";
@@ -3085,7 +3087,7 @@
     mirror::Class* klass = field->GetDeclaringClass();
     const RegType& field_klass =
         reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
-                             klass, klass->IsFinal());
+                             klass, klass->CannotBeAssignedFromOtherTypes());
     if (obj_type.IsUninitializedTypes() &&
         (!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
             !field_klass.Equals(GetDeclaringClass()))) {
@@ -3300,7 +3302,8 @@
     const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
     if (mirror_method_ != NULL) {
       mirror::Class* klass = mirror_method_->GetDeclaringClass();
-      declaring_class_ = &reg_types_.FromClass(descriptor, klass, klass->IsFinal());
+      declaring_class_ = &reg_types_.FromClass(descriptor, klass,
+                                               klass->CannotBeAssignedFromOtherTypes());
     } else {
       declaring_class_ = &reg_types_.FromDescriptor(class_loader_, descriptor, false);
     }
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index a575f77..ce3e6f6 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -31,7 +31,17 @@
 
 static bool MatchingPrecisionForClass(RegType* entry, bool precise)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
+  if (entry->IsPreciseReference() == precise) {
+    // We were or weren't looking for a precise reference and we found what we need.
+    return true;
+  } else {
+    if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) {
+      // We weren't looking for a precise reference, as we're looking up based on a descriptor, but
+      // we found a matching entry based on the descriptor. Return the precise entry in that case.
+      return true;
+    }
+    return false;
+  }
 }
 
 void RegTypeCache::FillPrimitiveTypes() {
@@ -112,10 +122,13 @@
   if (entry->descriptor_ != descriptor) {
     return false;
   }
-  if (entry->HasClass() && MatchingPrecisionForClass(entry, precise)) {
-    return true;
+  if (entry->HasClass()) {
+    return MatchingPrecisionForClass(entry, precise);
   }
-  return entry->IsUnresolvedReference();
+  // There is no notion of precise unresolved references, the precise information is just dropped
+  // on the floor.
+  DCHECK(entry->IsUnresolvedReference());
+  return true;
 }
 
 mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) {
@@ -166,7 +179,7 @@
     // 2- Precise Flag passed as true.
     RegType* entry;
     // Create an imprecise type if we can't tell for a fact that it is precise.
-    if ((klass->IsFinal()) || precise) {
+    if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
       entry = new PreciseReferenceType(klass, descriptor, entries_.size());
@@ -193,6 +206,8 @@
 
 const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
   if (klass->IsPrimitive()) {
+    // Note: precise isn't used for primitive classes. A char is assignable to an int. All
+    // primitive classes are final.
     return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
   } else {
     // Look for the reference in the list of entries to have.
@@ -362,8 +377,9 @@
     entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
+    DCHECK(!klass->IsArrayClass());
     if(uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
-      // For uninitialized this reference look for reference types that are not precise.
+      // For uninitialized "this reference" look for reference types that are not precise.
       for (size_t i = primitive_count_; i < entries_.size(); i++) {
         RegType* cur_entry = entries_[i];
         if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
@@ -372,21 +388,22 @@
       }
       entry = new ReferenceType(klass, "", entries_.size());
     } else {
-        if (klass->IsFinal()) {
-          if (klass->IsInstantiable()) {
-            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;
-              }
+      if (klass->IsFinal()) {
+        if (klass->IsInstantiable()) {
+          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;
             }
-            // Precise type was not found , create one !
-            entry = new PreciseReferenceType(klass, "", entries_.size());
-          } else {
-            return Conflict();
           }
+          // Precise type was not found , create one !
+          entry = new PreciseReferenceType(klass, "", entries_.size());
+        } else {
+          return Conflict();
+        }
       } else {
-        // Not a final class, create an imprecise reference. Look up if we have it in the cache first.
+        // Not a final class, create an imprecise reference. Look up if we have it in the cache
+        // first.
         for (size_t i = primitive_count_; i < entries_.size(); i++) {
           RegType* cur_entry = entries_[i];
           if (cur_entry->IsReference() && !(cur_entry->IsPrecise()) &&
@@ -504,7 +521,8 @@
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
-    return FromClass(ClassHelper(klass).GetDescriptor(), klass, klass->IsFinal());
+    return FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                     klass->CannotBeAssignedFromOtherTypes());
   }
 }