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