Add a kTypeChecksFailure.

This is to distinguish between a soft failure due to type checks, or a
soft failure due to other reasons.

A follow-up CL will start using that information and use the type checks
in the vdex file to perform fast verification at runtime.

Test: test.py
Bug: 176960283

Change-Id: I04bff9ff26033f41e9439d366667a9aec1f339a0
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index c0dd84c..7854eaa 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1351,7 +1351,7 @@
 }
 
 TEST_F(Dex2oatVerifierAbort, SoftFail) {
-  // Use VerifierDepsMulti as it has hard-failing classes.
+  // Use VerifierDepsMulti as it has soft-failing classes.
   std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDepsMulti"));
   std::string out_dir = GetScratchDir();
   const std::string base_oat_name = out_dir + "/base.oat";
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index 605953c..e23d1b0 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -2058,6 +2058,11 @@
           manager_->GetCompiler()->AddSoftVerifierFailure();
           break;
         }
+        case verifier::FailureKind::kTypeChecksFailure: {
+          // Don't record anything, we will do the type checks from the vdex
+          // file at runtime.
+          break;
+        }
         case verifier::FailureKind::kAccessChecksFailure: {
           manager_->GetCompiler()->RecordClassStatus(ref, ClassStatus::kVerifiedNeedsAccessChecks);
           break;
@@ -2118,7 +2123,8 @@
         } else if (klass->IsVerifiedNeedsAccessChecks()) {
           DCHECK_EQ(failure_kind, verifier::FailureKind::kAccessChecksFailure);
         } else if (klass->ShouldVerifyAtRuntime()) {
-          DCHECK_EQ(failure_kind, verifier::FailureKind::kSoftFailure);
+          DCHECK(failure_kind == verifier::FailureKind::kSoftFailure ||
+                 failure_kind == verifier::FailureKind::kTypeChecksFailure);
         } else {
           DCHECK_EQ(failure_kind, verifier::FailureKind::kHardFailure);
         }
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 58c1c4e..12d00ad 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -1630,6 +1630,7 @@
       return true;
     case art::verifier::FailureKind::kSoftFailure:
     case art::verifier::FailureKind::kAccessChecksFailure:
+    case art::verifier::FailureKind::kTypeChecksFailure:
       // Soft failures might require interpreter on some methods. It won't prevent redefinition but
       // it does mean we need to run the verifier again and potentially update method flags after
       // performing the swap.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d00c721..9cde319 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4655,12 +4655,14 @@
       }
     } else {
       CHECK(verifier_failure == verifier::FailureKind::kSoftFailure ||
+            verifier_failure == verifier::FailureKind::kTypeChecksFailure ||
             verifier_failure == verifier::FailureKind::kAccessChecksFailure);
       // Soft failures at compile time should be retried at runtime. Soft
       // failures at runtime will be handled by slow paths in the generated
       // code. Set status accordingly.
       if (Runtime::Current()->IsAotCompiler()) {
-        if (verifier_failure == verifier::FailureKind::kSoftFailure) {
+        if (verifier_failure == verifier::FailureKind::kSoftFailure ||
+            verifier_failure == verifier::FailureKind::kTypeChecksFailure) {
           mirror::Class::SetStatus(klass, ClassStatus::kRetryVerificationAtRuntime, self);
         } else {
           mirror::Class::SetStatus(klass, ClassStatus::kVerifiedNeedsAccessChecks, self);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 017846b..c2ad314 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -5176,6 +5176,7 @@
 // The AOT/JIT compiled code is not affected.
 static inline bool CanRuntimeHandleVerificationFailure(uint32_t encountered_failure_types) {
   constexpr uint32_t unresolved_mask =
+      verifier::VerifyError::VERIFY_ERROR_UNRESOLVED_TYPE_CHECK |
       verifier::VerifyError::VERIFY_ERROR_NO_CLASS |
       verifier::VerifyError::VERIFY_ERROR_CLASS_CHANGE |
       verifier::VerifyError::VERIFY_ERROR_INSTANTIATION |
@@ -5250,7 +5251,11 @@
         verifier.Dump(LOG_STREAM(INFO));
       }
       if (CanRuntimeHandleVerificationFailure(verifier.encountered_failure_types_)) {
-        result.kind = FailureKind::kAccessChecksFailure;
+        if (verifier.encountered_failure_types_ & VERIFY_ERROR_UNRESOLVED_TYPE_CHECK) {
+          result.kind = FailureKind::kTypeChecksFailure;
+        } else {
+          result.kind = FailureKind::kAccessChecksFailure;
+        }
       } else {
         result.kind = FailureKind::kSoftFailure;
       }
@@ -5565,7 +5570,7 @@
         // This will be reported to the runtime as a soft failure.
         break;
 
-        // Indication that verification should be retried at runtime.
+      // Indication that verification should be retried at runtime.
       case VERIFY_ERROR_BAD_CLASS_SOFT:
         if (!allow_soft_failures_) {
           flags_.have_pending_hard_failure_ = true;
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index e104d34..0fdc8c6 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -300,6 +300,7 @@
         break;
       }
       case verifier::FailureKind::kAccessChecksFailure:
+      case verifier::FailureKind::kTypeChecksFailure:
       case verifier::FailureKind::kNoFailure: {
         thread_deps->RecordClassVerified(dex_file, class_def);
         break;
diff --git a/runtime/verifier/verifier_enums.h b/runtime/verifier/verifier_enums.h
index e3c50aa..16bf004 100644
--- a/runtime/verifier/verifier_enums.h
+++ b/runtime/verifier/verifier_enums.h
@@ -33,6 +33,7 @@
 enum class FailureKind {
   kNoFailure,
   kAccessChecksFailure,
+  kTypeChecksFailure,
   kSoftFailure,
   kHardFailure,
 };
diff --git a/test/VerifierDepsMulti/MySoftVerificationFailure.smali b/test/VerifierDepsMulti/MySoftVerificationFailure.smali
index 6b56a3b..2bede45 100644
--- a/test/VerifierDepsMulti/MySoftVerificationFailure.smali
+++ b/test/VerifierDepsMulti/MySoftVerificationFailure.smali
@@ -17,8 +17,9 @@
 
 .method public final foo()V
   .registers 1
-  sget-object v0, LMySoftVerificationFailure;->error:LUnknownType;
+  sget-object v0, LMySoftVerificationFailure;->error:Ljava/lang/Object;
+  # Throwing a non-exception class is a soft failure.
   throw v0
 .end method
 
-.field public static error:LUnknownType;
+.field public static error:Ljava/lang/Object;