Throw useful detail messages when Method.invoke fails.
Part of my general push for better exceptions.
(Cherry-pick from dalvik-dev of https://android-git.corp.google.com/g/83287.)
Change-Id: I0cd47b492fbdc52db2eef8e2a02f31bda2a086eb
diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c
index 9d8f719..b0aad81 100644
--- a/vm/interp/Stack.c
+++ b/vm/interp/Stack.c
@@ -637,6 +637,20 @@
dvmPopFrame(self);
}
+static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected,
+ DataObject* arg)
+{
+ char* expectedClassName = dvmHumanReadableDescriptor(expected->descriptor);
+ char* actualClassName = (arg != NULL)
+ ? dvmHumanReadableDescriptor(arg->obj.clazz->descriptor)
+ : strdup("null");
+ dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
+ "argument %d should have type %s, got %s",
+ argIndex + 1, expectedClassName, actualClassName);
+ free(expectedClassName);
+ free(actualClassName);
+}
+
/*
* Invoke a method, using the specified arguments and return type, through
* one of the reflection interfaces. Could be a virtual or direct method
@@ -666,10 +680,9 @@
else
argListLength = 0;
if (argListLength != (int) params->length) {
- LOGI("invoke: expected %d args, received %d args\n",
+ dvmThrowExceptionFmt("Ljava/lang/IllegalArgumentException;",
+ "wrong number of arguments; expected %d, got %d",
params->length, argListLength);
- dvmThrowException("Ljava/lang/IllegalArgumentException;",
- "wrong number of arguments");
return NULL;
}
@@ -706,15 +719,9 @@
width = dvmConvertArgument(*args++, *types++, ins);
if (width < 0) {
- if (*(args-1) != NULL) {
- LOGV("invoke: type mismatch on arg %d ('%s' '%s')\n",
- i, (*(args-1))->obj.clazz->descriptor,
- (*(types-1))->descriptor);
- }
dvmPopFrame(self); // throw wants to pull PC out of stack
needPop = false;
- dvmThrowException("Ljava/lang/IllegalArgumentException;",
- "argument type mismatch");
+ throwArgumentTypeMismatch(i, *(types-1), *(args-1));
goto bail;
}
diff --git a/vm/native/InternalNative.c b/vm/native/InternalNative.c
index 12c8d0f..9dc61d8 100644
--- a/vm/native/InternalNative.c
+++ b/vm/native/InternalNative.c
@@ -149,21 +149,30 @@
/*
* Verify that "obj" is non-null and is an instance of "clazz".
+ * Used to implement reflection on fields and methods.
*
* Returns "false" and throws an exception if not.
*/
bool dvmVerifyObjectInClass(Object* obj, ClassObject* clazz)
{
+ const char* exceptionClass = NULL;
if (obj == NULL) {
- dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ exceptionClass = "Ljava/lang/NullPointerException;";
+ } else if (!dvmInstanceof(obj->clazz, clazz)) {
+ exceptionClass = "Ljava/lang/IllegalArgumentException;";
+ }
+ if (exceptionClass != NULL) {
+ char* expectedClassName = dvmHumanReadableDescriptor(clazz->descriptor);
+ char* actualClassName = (obj != NULL)
+ ? dvmHumanReadableDescriptor(obj->clazz->descriptor)
+ : strdup("null");
+ dvmThrowExceptionFmt(exceptionClass,
+ "expected receiver of type %s, not %s",
+ expectedClassName, actualClassName);
+ free(expectedClassName);
+ free(actualClassName);
return false;
}
- if (!dvmInstanceof(obj->clazz, clazz)) {
- dvmThrowException("Ljava/lang/IllegalArgumentException;",
- "object is not an instance of the class");
- return false;
- }
-
return true;
}
diff --git a/vm/native/java_lang_reflect_Field.c b/vm/native/java_lang_reflect_Field.c
index 9a0986e..15cb84a 100644
--- a/vm/native/java_lang_reflect_Field.c
+++ b/vm/native/java_lang_reflect_Field.c
@@ -124,10 +124,6 @@
*/
if (!dvmVerifyObjectInClass(obj, declaringClass)) {
assert(dvmCheckException(dvmThreadSelf()));
- if (obj != NULL) {
- LOGD("Wrong object type for field access: %s is not a %s\n",
- obj->clazz->descriptor, declaringClass->descriptor);
- }
return NULL;
}
}