Two exception-related tweaks: (1) Make the dynamic exception construction
mechanism be able to handle exception constructors that take Object instead
of String. (2) Add a convenience in JNIHelp to throw RuntimeExceptions.
Change-Id: Ie5ce680c30043a4b186e59d7c8883666648b2c87
diff --git a/libnativehelper/JNIHelp.c b/libnativehelper/JNIHelp.c
index aacecb6..748d8ff 100644
--- a/libnativehelper/JNIHelp.c
+++ b/libnativehelper/JNIHelp.c
@@ -55,7 +55,15 @@
}
/*
- * Throw a java.IO.IOException, generating the message from errno.
+ * Throw a java.lang.RuntimeException, with an optional message.
+ */
+int jniThrowRuntimeException(JNIEnv* env, const char* msg)
+{
+ return jniThrowException(env, "java/lang/RuntimeException", msg);
+}
+
+/*
+ * Throw a java.io.IOException, generating the message from errno.
*/
int jniThrowIOException(JNIEnv* env, int errnum)
{
@@ -85,4 +93,3 @@
return jniThrowException(env, "java/io/IOException", message);
}
-
diff --git a/libnativehelper/include/nativehelper/JNIHelp.h b/libnativehelper/include/nativehelper/JNIHelp.h
index 3982797..698cba7 100644
--- a/libnativehelper/include/nativehelper/JNIHelp.h
+++ b/libnativehelper/include/nativehelper/JNIHelp.h
@@ -53,7 +53,12 @@
int jniThrowException(C_JNIEnv* env, const char* className, const char* msg);
/*
- * Throw a java.IO.IOException, generating the message from errno.
+ * Throw a java.lang.RuntimeException, with an optional message.
+ */
+int jniThrowRuntimeException(JNIEnv* env, const char* msg);
+
+/*
+ * Throw a java.io.IOException, generating the message from errno.
*/
int jniThrowIOException(C_JNIEnv* env, int errnum);
diff --git a/vm/Exception.c b/vm/Exception.c
index 3a56cc3..808b0b2 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -338,6 +338,45 @@
}
/*
+ * Find and return an exception constructor method that can take the
+ * indicated parameters, or return NULL if no such constructor exists.
+ */
+static Method* findExceptionInitMethod(ClassObject* excepClass,
+ bool hasMessage, bool hasCause)
+{
+ if (hasMessage) {
+ Method* result;
+
+ if (hasCause) {
+ result = dvmFindDirectMethodByDescriptor(
+ excepClass, "<init>",
+ "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ } else {
+ result = dvmFindDirectMethodByDescriptor(
+ excepClass, "<init>", "(Ljava/lang/String;)V");
+ }
+
+ if (result != NULL) {
+ return result;
+ }
+
+ if (hasCause) {
+ return dvmFindDirectMethodByDescriptor(
+ excepClass, "<init>",
+ "(Ljava/lang/Object;Ljava/lang/Throwable;)V");
+ } else {
+ return dvmFindDirectMethodByDescriptor(
+ excepClass, "<init>", "(Ljava/lang/Object;)V");
+ }
+ } else if (hasCause) {
+ return dvmFindDirectMethodByDescriptor(
+ excepClass, "<init>", "(Ljava/lang/Throwable;)V");
+ } else {
+ return dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
+ }
+}
+
+/*
* Initialize an exception with an appropriate constructor.
*
* "exception" is the exception object to initialize.
@@ -418,43 +457,45 @@
* not #2. (Some might argue that the constructor is actually not #3,
* because it doesn't take the message string as an argument, but it
* has the same effect and we can work with it here.)
+ *
+ * java.lang.AssertionError is also a strange case -- it has a
+ * constructor that takes an Object, but not one that takes a String.
+ * There may be other cases like this, as well, so we generally look
+ * for an Object-taking constructor if we can't find one that takes
+ * a String.
*/
if (cause == NULL) {
if (msgStr == NULL) {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
+ initMethod = findExceptionInitMethod(excepClass, false, false);
initKind = kInitNoarg;
} else {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
- "(Ljava/lang/String;)V");
+ initMethod = findExceptionInitMethod(excepClass, true, false);
if (initMethod != NULL) {
initKind = kInitMsg;
} else {
/* no #2, try #3 */
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
- "(Ljava/lang/String;Ljava/lang/Throwable;)V");
- if (initMethod != NULL)
+ initMethod = findExceptionInitMethod(excepClass, true, true);
+ if (initMethod != NULL) {
initKind = kInitMsgThrow;
+ }
}
}
} else {
if (msgStr == NULL) {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
- "(Ljava/lang/Throwable;)V");
+ initMethod = findExceptionInitMethod(excepClass, false, true);
if (initMethod != NULL) {
initKind = kInitThrow;
} else {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
+ initMethod = findExceptionInitMethod(excepClass, false, false);
initKind = kInitNoarg;
needInitCause = true;
}
} else {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
- "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+ initMethod = findExceptionInitMethod(excepClass, true, true);
if (initMethod != NULL) {
initKind = kInitMsgThrow;
} else {
- initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
- "(Ljava/lang/String;)V");
+ initMethod = findExceptionInitMethod(excepClass, true, false);
initKind = kInitMsg;
needInitCause = true;
}