Allow soft failures at runtime and fix null referrer for ICCE and NSME.

Change-Id: I814369f4e41cebf37007cb514a8bf19cbaf17e94
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 41f14df..343c580 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2078,12 +2078,21 @@
           << " because: " << error_msg;
     }
     Thread::Current()->AssertNoPendingException();
-    CHECK(verifier_failure == verifier::MethodVerifier::kNoFailure ||
-          Runtime::Current()->IsCompiler());
-    // Make sure all classes referenced by catch blocks are resolved
+    // Make sure all classes referenced by catch blocks are resolved.
     ResolveClassExceptionHandlerTypes(dex_file, klass);
-    klass->SetStatus(verifier_failure == verifier::MethodVerifier::kNoFailure ?
-                     Class::kStatusVerified : Class::kStatusRetryVerificationAtRuntime);
+    if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
+      klass->SetStatus(Class::kStatusVerified);
+    } else {
+      CHECK_EQ(verifier_failure, verifier::MethodVerifier::kSoftFailure);
+      // 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()->IsCompiler()) {
+        klass->SetStatus(Class::kStatusRetryVerificationAtRuntime);
+      } else {
+        klass->SetStatus(Class::kStatusVerified);
+      }
+    }
     // Sanity check that a verified class has GC maps on all methods
     CheckMethodsHaveGcMaps(klass);
   } else {
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index c5ce4b3..572da97 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -148,10 +148,12 @@
   std::ostringstream msg;
   msg << "The method '" << PrettyMethod(method) << "' was expected to be of type "
       << expected_type << " but instead was found to be of type " << found_type;
-  ClassHelper kh(referrer->GetDeclaringClass());
-  std::string location(kh.GetLocation());
-  if (!location.empty()) {
-    msg << " (accessed from " << location << ")";
+  if (referrer != NULL) {
+    ClassHelper kh(referrer->GetDeclaringClass());
+    std::string location(kh.GetLocation());
+    if (!location.empty()) {
+      msg << " (accessed from " << location << ")";
+    }
   }
   Thread::Current()->ThrowNewException("Ljava/lang/IncompatibleClassChangeError;",
                                        msg.str().c_str());
@@ -163,10 +165,12 @@
   std::ostringstream msg;
   msg << "No " << type << " method " << name << signature
       << " in class " << kh.GetDescriptor() << " or its superclasses";
-  kh.ChangeClass(referrer->GetDeclaringClass());
-  std::string location(kh.GetLocation());
-  if (!location.empty()) {
-    msg << " (accessed from " << location << ")";
+  if (referrer != NULL) {
+    kh.ChangeClass(referrer->GetDeclaringClass());
+    std::string location(kh.GetLocation());
+    if (!location.empty()) {
+      msg << " (accessed from " << location << ")";
+    }
   }
   Thread::Current()->ThrowNewException("Ljava/lang/NoSuchMethodError;", msg.str().c_str());
 }
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 9c0e380..070c616 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -396,16 +396,14 @@
     case VERIFY_ERROR_ACCESS_METHOD:
     case VERIFY_ERROR_INSTANTIATION:
     case VERIFY_ERROR_CLASS_CHANGE:
-      if (Runtime::Current()->IsCompiler()) {
-        // 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;
-      }
+      // 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;
       break;
       // Indication that verification should be retried at runtime.
     case VERIFY_ERROR_BAD_CLASS_SOFT:
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 273552d..3e3154b 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -659,6 +659,7 @@
 
   friend struct art::ReferenceMap2Visitor; // for VerifyMethodAndDump
 };
+std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs);
 
 }  // namespace verifier
 }  // namespace art