Wrap non-Error throwables in ExceptionInInitializerError.

This doesn't fix test 084 because we still need the stub to ensure <clinit> is
run before static method invocation, but it gets us to the point where that's
the only failure in the test, and that's already being worked on.

Change-Id: I9835394a733421541d9687f66aeb3bef9f5dbb0e
diff --git a/src/class_linker.cc b/src/class_linker.cc
index a8703da..b4e332d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -18,6 +18,7 @@
 #include "monitor.h"
 #include "object.h"
 #include "runtime.h"
+#include "ScopedLocalRef.h"
 #include "space.h"
 #include "thread.h"
 #include "UniquePtr.h"
@@ -83,6 +84,35 @@
   }
 }
 
+void WrapExceptionInInitializer() {
+  JNIEnv* env = Thread::Current()->GetJniEnv();
+
+  ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
+  CHECK(cause.get() != NULL);
+
+  env->ExceptionClear();
+
+  // TODO: add java.lang.Error to JniConstants?
+  ScopedLocalRef<jclass> error_class(env, env->FindClass("java/lang/Error"));
+  CHECK(error_class.get() != NULL);
+  if (env->IsInstanceOf(cause.get(), error_class.get())) {
+    // We only wrap non-Error exceptions; an Error can just be used as-is.
+    env->Throw(cause.get());
+    return;
+  }
+
+  // TODO: add java.lang.ExceptionInInitializerError to JniConstants?
+  ScopedLocalRef<jclass> eiie_class(env, env->FindClass("java/lang/ExceptionInInitializerError"));
+  CHECK(eiie_class.get() != NULL);
+
+  jmethodID mid = env->GetMethodID(eiie_class.get(), "<init>" , "(Ljava/lang/Throwable;)V");
+  CHECK(mid != NULL);
+
+  ScopedLocalRef<jthrowable> eiie(env,
+      reinterpret_cast<jthrowable>(env->NewObject(eiie_class.get(), mid, cause.get())));
+  env->Throw(eiie.get());
+}
+
 }
 
 const char* ClassLinker::class_roots_descriptors_[] = {
@@ -1391,8 +1421,7 @@
     ObjectLock lock(klass);
 
     if (self->IsExceptionPending()) {
-      // TODO: if self->GetException() is not an Error,
-      // wrap in ExceptionInInitializerError
+      WrapExceptionInInitializer();
       klass->SetStatus(Class::kStatusError);
     } else {
       ++Runtime::Current()->GetStats()->class_init_count;
@@ -1415,11 +1444,7 @@
     // there's an exception pending (only possible if
     // "interruptShouldThrow" was set), bail out.
     if (self->IsExceptionPending()) {
-      // TODO: set cause of ExceptionInInitializerError to self->GetException()
-      self->ThrowNewExceptionF("Ljava/lang/ExceptionInInitializerError;",
-          "Exception %s thrown while initializing class %s",
-          PrettyTypeOf(self->GetException()).c_str(),
-          PrettyDescriptor(klass->GetDescriptor()).c_str());
+      WrapExceptionInInitializer();
       klass->SetStatus(Class::kStatusError);
       return false;
     }