Add "class Throwable" and rewrite exception throwing to use JNI.
Change-Id: I79836075337eedfc5923ebff028176615ffd3598
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9aa23bb..0d46f29 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -218,9 +218,9 @@
if (ts.Env()->check_jni) {
size_t entry_count = locals.Capacity();
if (entry_count > 16) {
- std::string class_name(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+ std::string class_descriptor(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
LOG(WARNING) << "Warning: more than 16 JNI local references: "
- << entry_count << " (most recent was a " << class_name << ")";
+ << entry_count << " (most recent was a " << class_descriptor << ")";
locals.Dump();
// TODO: dvmDumpThread(dvmThreadSelf(), false);
// dvmAbort();
@@ -514,10 +514,10 @@
if (field == NULL) {
Thread* self = Thread::Current();
- std::string class_name(c->GetDescriptor()->ToModifiedUtf8());
+ std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8());
self->ThrowNewException("Ljava/lang/NoSuchFieldError;",
"no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
- name, class_name.c_str());
+ name, class_descriptor.c_str());
return NULL;
}
@@ -616,7 +616,7 @@
static jint Throw(JNIEnv* env, jthrowable java_exception) {
ScopedJniThreadState ts(env);
- Object* exception = Decode<Object*>(ts, java_exception);
+ Throwable* exception = Decode<Throwable*>(ts, java_exception);
if (exception == NULL) {
return JNI_ERR;
}
@@ -624,10 +624,32 @@
return JNI_OK;
}
- static jint ThrowNew(JNIEnv* env, jclass java_class, const char* msg) {
+ static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
ScopedJniThreadState ts(env);
- Class* c = Decode<Class*>(ts, java_class);
- ts.Self()->ThrowNewException(c, msg);
+ // TODO: check for a pending exception to decide what constructor to call.
+ jmethodID mid = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V");
+ if (mid == NULL) {
+ return JNI_ERR;
+ }
+ jstring s = env->NewStringUTF(msg);
+ if (s == NULL) {
+ return JNI_ERR;
+ }
+
+ jvalue args[1];
+ args[0].l = s;
+ jthrowable exception = reinterpret_cast<jthrowable>(env->NewObjectA(c, mid, args));
+ if (exception == NULL) {
+ return JNI_ERR;
+ }
+
+ LOG(INFO) << "Throwing " << PrettyType(Decode<Throwable*>(ts, exception))
+ << ": " << msg;
+ ts.Self()->SetException(Decode<Throwable*>(ts, exception));
+
+ env->DeleteLocalRef(exception);
+ env->DeleteLocalRef(s);
+
return JNI_OK;
}
@@ -1994,17 +2016,17 @@
}
if (method == NULL) {
Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
+ std::string class_descriptor(klass->GetDescriptor()->ToModifiedUtf8());
self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
"no method \"%s.%s%s\"",
- class_name.c_str(), name, sig);
+ class_descriptor.c_str(), name, sig);
return JNI_ERR;
} else if (!method->IsNative()) {
Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
+ std::string class_descriptor(klass->GetDescriptor()->ToModifiedUtf8());
self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
"method \"%s.%s%s\" is not native",
- class_name.c_str(), name, sig);
+ class_descriptor.c_str(), name, sig);
return JNI_ERR;
}
method->RegisterNative(methods[i].fnPtr);