ART: Change behavior for rethrowing init failures (2)

Always store the pending exception when making a class erroneous.
Instead of filtering by ExceptionInInitializerError, add an option
to the rethrow that enforces a NoClassDefFoundError, which is required
by the specification.

Use the libcore companion change to add the stored error (if any) as
a cause to the NoClassDefFoundError, which should significantly help
tracking down issues.

Fix run-test 008 to expect spec-compliant behavior. Test that a cause
has been set.

Bug: 25445103
Change-Id: I6a0dc54e78312283faf23415887eff387531407f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 6053469..cdb7712 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -153,7 +153,7 @@
   self->AssertPendingException();
 }
 
-void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c) {
+void ClassLinker::ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def) {
   // The class failed to initialize on a previous attempt, so we want to throw
   // a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
   // failed in verification, in which case v2 5.4.1 says we need to re-throw
@@ -178,10 +178,15 @@
     self->SetException(pre_allocated);
   } else {
     if (c->GetVerifyError() != nullptr) {
+      // Rethrow stored error.
       HandleEarlierVerifyError(self, this, c);
-    } else {
-      self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
-                              PrettyDescriptor(c).c_str());
+    }
+    if (c->GetVerifyError() == nullptr || wrap_in_no_class_def) {
+      // If there isn't a recorded earlier error, or this is a repeat throw from initialization,
+      // the top-level exception must be a NoClassDefFoundError. The potentially already pending
+      // exception will be a cause.
+      self->ThrowNewWrappedException("Ljava/lang/NoClassDefFoundError;",
+                                     PrettyDescriptor(c).c_str());
     }
   }
 }
@@ -3423,7 +3428,7 @@
 
     // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
-      ThrowEarlierClassFailure(klass.Get());
+      ThrowEarlierClassFailure(klass.Get(), true);
       VlogClassInitializationFailure(klass);
       return false;
     }