Implement reflective method invocation.
Change-Id: Ib3af9d7e00bf226398610b5ac6efbfe3eb2d15e8
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index 188614f..6ddb436 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -17,6 +17,7 @@
#include "jni_internal.h"
#include "class_linker.h"
#include "object.h"
+#include "reflection.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -24,7 +25,6 @@
namespace {
-
// We move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
// position, because the callers of this function are trying to convey
// the "traditional" meaning of the flags to their callers.
@@ -40,9 +40,73 @@
return FixupMethodFlags(Decode<Object*>(env, jmethod)->AsMethod()->GetAccessFlags());
}
+jobject Method_invokeNative(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jclass javaDeclaringClass, jobject javaParams, jclass, jint, jboolean) {
+ Thread* self = Thread::Current();
+ ScopedThreadStateChange tsc(self, Thread::kRunnable);
+
+ jmethodID mid = env->FromReflectedMethod(javaMethod);
+ Method* m = reinterpret_cast<Method*>(mid);
+ Object* receiver = NULL;
+ if (!m->IsStatic()) {
+ // Check that the receiver is non-null and an instance of the field's declaring class.
+ receiver = Decode<Object*>(env, javaReceiver);
+ Class* declaringClass = Decode<Class*>(env, javaDeclaringClass);
+ if (!VerifyObjectInClass(env, receiver, declaringClass)) {
+ return NULL;
+ }
+
+ // Find the actual implementation of the virtual method.
+ m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
+ }
+
+ // Get our arrays of arguments and their types, and check they're the same size.
+ ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
+ ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
+ int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
+ if (arg_count != classes->GetLength()) {
+ self->ThrowNewException("Ljava/lang/IllegalArgumentException;",
+ "wrong number of arguments; expected %d, got %d",
+ classes->GetLength(), arg_count);
+ return NULL;
+ }
+
+ // Translate javaArgs to a jvalue[].
+ UniquePtr<jvalue[]> args(new jvalue[arg_count]);
+ JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
+ for (int32_t i = 0; i < arg_count; ++i) {
+ Object* arg = objects->Get(i);
+ Class* dst_class = classes->Get(i);
+ if (dst_class->IsPrimitive()) {
+ if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i])) {
+ return NULL;
+ }
+ } else {
+ args[i].l = AddLocalReference<jobject>(env, arg);
+ }
+ }
+
+ // Invoke the method.
+ JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());
+
+ // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
+ if (self->IsExceptionPending()) {
+ jthrowable th = env->ExceptionOccurred();
+ env->ExceptionClear();
+ jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
+ jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
+ jobject exception_instance = env->NewObject(exception_class, mid, th);
+ env->Throw(reinterpret_cast<jthrowable>(exception_instance));
+ return NULL;
+ }
+
+ // Box if necessary and return.
+ BoxPrimitive(env, m->GetReturnType(), value);
+ return AddLocalReference<jobject>(env, value.l);
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Method, getMethodModifiers, "(Ljava/lang/Class;Ljava/lang/reflect/AccessibleObject;I)I"),
- //NATIVE_METHOD(Method, invokeNative, "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"),
+ NATIVE_METHOD(Method, invokeNative, "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"),
};
} // namespace