diff options
author | Elliott Hughes <enh@google.com> | 2011-09-23 19:30:41 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2011-09-25 10:29:48 -0700 |
commit | 2a20cfd0b7fc81099f5de0da782ebcc1cb262792 (patch) | |
tree | ef9b496f2ea83edce5cbe4a427dbaafd710bff16 /src/reflection.cc | |
parent | 65ca077378935beb113bb5aec5e890054ca3286e (diff) | |
download | art-2a20cfd0b7fc81099f5de0da782ebcc1cb262792.zip art-2a20cfd0b7fc81099f5de0da782ebcc1cb262792.tar.gz art-2a20cfd0b7fc81099f5de0da782ebcc1cb262792.tar.bz2 |
Implement java.lang.reflect.Constructor.constructNative.
Change-Id: Iefa92ad1bd89073d4bfa9a80b9e4f0dea90a5849
Diffstat (limited to 'src/reflection.cc')
-rw-r--r-- | src/reflection.cc | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/src/reflection.cc b/src/reflection.cc index 3edb9f7..c560053 100644 --- a/src/reflection.cc +++ b/src/reflection.cc @@ -48,6 +48,75 @@ void InitBoxingMethods(JNIEnv* env) { InitBoxingMethod(env, gShort_valueOf, JniConstants::shortClass, "(S)Ljava/lang/Short;"); } +jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jobject javaParams) { + Thread* self = Thread::Current(); + ScopedThreadStateChange tsc(self, Thread::kRunnable); + + jmethodID mid = env->FromReflectedMethod(javaMethod); + Method* m = reinterpret_cast<Method*>(mid); + + Class* declaring_class = m->GetDeclaringClass(); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true)) { + return NULL; + } + + 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); + if (!VerifyObjectInClass(env, receiver, declaring_class)) { + 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); +} + bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) { if (o == NULL) { jniThrowNullPointerException(env, "receiver for non-static field access was null"); |