Revert "ART: Remove VERIFY_ERROR_UNRESOLVED_CATCH"

This reverts commit 7a82acc7ee79b198f7b4638a15cb1c3d1625ab6c.

Reason for revert: NO_CLASS doesn't have the right semantics for the compiler

Bug: 121245951
Change-Id: I8dbeb7fbd6a697fe536535f1c696187041d7fcab
Test: m test-art-host
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 8396fe9..b644dba 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3829,13 +3829,12 @@
 
           // We need to post a failure. The compiler currently does not handle unreachable
           // code correctly.
-          Fail(VERIFY_ERROR_NO_CLASS, /*pending_exc=*/ false)
-              << "Unresolved catch handler, fail for compiler";
+          Fail(VERIFY_ERROR_UNRESOLVED_CATCH) << "Unresolved catch handler, fail for compiler";
 
           return std::make_pair(false, unresolved);
         }
         // Soft-fail, but do not handle this with a synthetic throw.
-        Fail(VERIFY_ERROR_NO_CLASS, /*pending_exc=*/ false) << "Unresolved catch handler";
+        Fail(VERIFY_ERROR_UNRESOLVED_CATCH) << "Unresolved catch handler";
         if (common_super != nullptr) {
           unresolved = &unresolved->Merge(*common_super, &reg_types_, this);
         }
@@ -5514,72 +5513,70 @@
   reg_types_.VisitRoots(visitor, root_info);
 }
 
-std::ostream& MethodVerifier::Fail(VerifyError error, bool pending_exc) {
+std::ostream& MethodVerifier::Fail(VerifyError error) {
   // Mark the error type as encountered.
   encountered_failure_types_ |= static_cast<uint32_t>(error);
 
-  if (pending_exc) {
-    switch (error) {
-      case VERIFY_ERROR_NO_CLASS:
-      case VERIFY_ERROR_NO_FIELD:
-      case VERIFY_ERROR_NO_METHOD:
-      case VERIFY_ERROR_ACCESS_CLASS:
-      case VERIFY_ERROR_ACCESS_FIELD:
-      case VERIFY_ERROR_ACCESS_METHOD:
-      case VERIFY_ERROR_INSTANTIATION:
-      case VERIFY_ERROR_CLASS_CHANGE:
-      case VERIFY_ERROR_FORCE_INTERPRETER:
-      case VERIFY_ERROR_LOCKING:
-        if (Runtime::Current()->IsAotCompiler() || !can_load_classes_) {
-          // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
-          // class change and instantiation errors into soft verification errors so that we
-          // re-verify at runtime. We may fail to find or to agree on access because of not yet
-          // available class loaders, or class loaders that will differ at runtime. In these cases,
-          // we don't want to affect the soundness of the code being compiled. Instead, the
-          // generated code runs "slow paths" that dynamically perform the verification and cause
-          // the behavior to be that akin to an interpreter.
-          error = VERIFY_ERROR_BAD_CLASS_SOFT;
-        } else {
-          // If we fail again at runtime, mark that this instruction would throw and force this
-          // method to be executed using the interpreter with checks.
-          flags_.have_pending_runtime_throw_failure_ = true;
+  switch (error) {
+    case VERIFY_ERROR_NO_CLASS:
+    case VERIFY_ERROR_NO_FIELD:
+    case VERIFY_ERROR_NO_METHOD:
+    case VERIFY_ERROR_ACCESS_CLASS:
+    case VERIFY_ERROR_ACCESS_FIELD:
+    case VERIFY_ERROR_ACCESS_METHOD:
+    case VERIFY_ERROR_INSTANTIATION:
+    case VERIFY_ERROR_CLASS_CHANGE:
+    case VERIFY_ERROR_FORCE_INTERPRETER:
+    case VERIFY_ERROR_LOCKING:
+      if (Runtime::Current()->IsAotCompiler() || !can_load_classes_) {
+        // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
+        // class change and instantiation errors into soft verification errors so that we re-verify
+        // at runtime. We may fail to find or to agree on access because of not yet available class
+        // loaders, or class loaders that will differ at runtime. In these cases, we don't want to
+        // affect the soundness of the code being compiled. Instead, the generated code runs "slow
+        // paths" that dynamically perform the verification and cause the behavior to be that akin
+        // to an interpreter.
+        error = VERIFY_ERROR_BAD_CLASS_SOFT;
+      } else {
+        // If we fail again at runtime, mark that this instruction would throw and force this
+        // method to be executed using the interpreter with checks.
+        flags_.have_pending_runtime_throw_failure_ = true;
 
-          // We need to save the work_line if the instruction wasn't throwing before. Otherwise
-          // we'll try to merge garbage.
-          // Note: this assumes that Fail is called before we do any work_line modifications.
-          // Note: this can fail before we touch any instruction, for the signature of a method. So
-          //       add a check.
-          if (work_insn_idx_ < dex::kDexNoIndex) {
-            const Instruction& inst = code_item_accessor_.InstructionAt(work_insn_idx_);
-            int opcode_flags = Instruction::FlagsOf(inst.Opcode());
+        // We need to save the work_line if the instruction wasn't throwing before. Otherwise we'll
+        // try to merge garbage.
+        // Note: this assumes that Fail is called before we do any work_line modifications.
+        // Note: this can fail before we touch any instruction, for the signature of a method. So
+        //       add a check.
+        if (work_insn_idx_ < dex::kDexNoIndex) {
+          const Instruction& inst = code_item_accessor_.InstructionAt(work_insn_idx_);
+          int opcode_flags = Instruction::FlagsOf(inst.Opcode());
 
-            if ((opcode_flags & Instruction::kThrow) == 0 &&
-                GetInstructionFlags(work_insn_idx_).IsInTry()) {
-              saved_line_->CopyFromLine(work_line_.get());
-            }
+          if ((opcode_flags & Instruction::kThrow) == 0 &&
+              GetInstructionFlags(work_insn_idx_).IsInTry()) {
+            saved_line_->CopyFromLine(work_line_.get());
           }
         }
-        break;
-
-        // Indication that verification should be retried at runtime.
-      case VERIFY_ERROR_BAD_CLASS_SOFT:
-        if (!allow_soft_failures_) {
-          flags_.have_pending_hard_failure_ = true;
-        }
-        break;
-
-        // Hard verification failures at compile time will still fail at runtime, so the class is
-        // marked as rejected to prevent it from being compiled.
-      case VERIFY_ERROR_BAD_CLASS_HARD: {
-        flags_.have_pending_hard_failure_ = true;
-        break;
       }
-    }
-  } else if (kIsDebugBuild) {
-    CHECK_NE(error, VERIFY_ERROR_BAD_CLASS_SOFT);
-    CHECK_NE(error, VERIFY_ERROR_BAD_CLASS_HARD);
-  }
+      break;
 
+      // Indication that verification should be retried at runtime.
+    case VERIFY_ERROR_BAD_CLASS_SOFT:
+      if (!allow_soft_failures_) {
+        flags_.have_pending_hard_failure_ = true;
+      }
+      break;
+
+      // Hard verification failures at compile time will still fail at runtime, so the class is
+      // marked as rejected to prevent it from being compiled.
+    case VERIFY_ERROR_BAD_CLASS_HARD: {
+      flags_.have_pending_hard_failure_ = true;
+      break;
+    }
+
+    case VERIFY_ERROR_UNRESOLVED_CATCH:
+      // Nothing to do, just remember the failure type.
+      break;
+  }
   failures_.push_back(error);
   std::string location(StringPrintf("%s: [0x%X] ", dex_file_->PrettyMethod(dex_method_idx_).c_str(),
                                     work_insn_idx_));
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 2b9a4bc..e3d0901 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -138,7 +138,7 @@
   }
 
   // Log a verification failure.
-  std::ostream& Fail(VerifyError error, bool pending_exc = true);
+  std::ostream& Fail(VerifyError error);
 
   // Log for verification information.
   ScopedNewLine LogVerifyInfo();
diff --git a/runtime/verifier/verifier_enums.h b/runtime/verifier/verifier_enums.h
index 96c98f9..0e96882 100644
--- a/runtime/verifier/verifier_enums.h
+++ b/runtime/verifier/verifier_enums.h
@@ -94,6 +94,9 @@
                                              // (sets a soft fail at compile time).
   VERIFY_ERROR_LOCKING =           1 << 11,  // Could not guarantee balanced locking. This should be
                                              // punted to the interpreter with access checks.
+  VERIFY_ERROR_UNRESOLVED_CATCH =  1 << 12,  // Error code necessary to have a synthetic soft fail
+                                             // that is not an exception, to let the compiler know
+                                             // that there is (unreachable) unverified code.
 };
 std::ostream& operator<<(std::ostream& os, const VerifyError& rhs);