Check interface assignability strictly for check-cast elision.

Objects are assignable to interfaces in the verifier as described in the long
RegType::ClassJoin comment. Using IsAssignableFrom therefore brought about
a bug where all check-casts where the cast type was an interface were being
elided. Introduce a new strict is assignable from routine that follows the
runtime rather than the verifier is assignable from behavior.

Change-Id: Iac30f71ce9116f2ef16c22acd73eea1c19c79d89
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 1bb163a..8ca5b82 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -3352,7 +3352,7 @@
     RegisterLine* line = reg_table_.GetLine(dex_pc);
     const RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
     const RegType& cast_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
-    if (cast_type.IsAssignableFrom(reg_type)) {
+    if (cast_type.IsStrictlyAssignableFrom(reg_type)) {
       if (mscs.get() == NULL) {
         mscs.reset(new MethodSafeCastSet());
       }
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 8111db6..1c61a29 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -708,54 +708,62 @@
   : ConstantType(constat, cache_id) {
 }
 
-bool RegType::IsAssignableFrom(const RegType& src) const {
-  if (Equals(src)) {
+static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (lhs.Equals(rhs)) {
     return true;
   } else {
-    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();
+    if (lhs.IsBoolean()) {
+      return rhs.IsBooleanTypes();
+    } else if (lhs.IsByte()) {
+      return rhs.IsByteTypes();
+    } else if (lhs.IsShort()) {
+      return rhs.IsShortTypes();
+    } else if (lhs.IsChar()) {
+      return rhs.IsCharTypes();
+    } else if (lhs.IsInteger()) {
+      return rhs.IsIntegralTypes();
+    } else if (lhs.IsFloat()) {
+      return rhs.IsFloatTypes();
+    } else if (lhs.IsLongLo()) {
+      return rhs.IsLongTypes();
+    } else if (lhs.IsDoubleLo()) {
+      return rhs.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[]
-      } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
-          GetClass()->IsAssignableFrom(src.GetClass())) {
-        // We're assignable from the Class point-of-view
+      CHECK(lhs.IsReferenceTypes())
+          << "Unexpected register type in IsAssignableFrom: '"
+          << lhs << "' := '" << rhs << "'";
+      if (rhs.IsZero()) {
+        return true;  // All reference types can be assigned null.
+      } else if (!rhs.IsReferenceTypes()) {
+        return false;  // Expect rhs to be a reference type.
+      } else if (lhs.IsJavaLangObject()) {
+        return true;  // All reference types can be assigned to Object.
+      } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+        // If we're not strict allow assignment to any interface, see comment in ClassJoin.
         return true;
-      } else if (IsUnresolvedTypes()) {
-        // Unresolved types are only assignable for null and equality.
-        return src.IsZero();
+      } else if (lhs.IsJavaLangObjectArray()) {
+        return rhs.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
+      } else if (lhs.HasClass() && rhs.HasClass() &&
+                 lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
+        // We're assignable from the Class point-of-view.
+        return true;
       } else {
+        // Unresolved types are only assignable for null and equality.
         return false;
       }
     }
   }
 }
 
+bool RegType::IsAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, false);
+}
+
+bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, true);
+}
+
 int32_t ConstantType::ConstantValue() const {
   DCHECK(IsConstantTypes());
   return constant_;
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 424b071..9ac0eca 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -230,7 +230,14 @@
     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_);
+  // Note: Object and interface types may always be assigned to one another, see comment on
+  // ClassJoin.
+  bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't allow assignment to
+  // an interface from an Object.
+  bool IsStrictlyAssignableFrom(const RegType& src) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Are these RegTypes the same?
   bool Equals(const RegType& other) const {
@@ -241,23 +248,22 @@
   virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-    /*
-     * 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_);