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;
}