blob: 6ddb436ecf92aa028862a3504476cf30c7459985 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "jni_internal.h"
#include "class_linker.h"
#include "object.h"
#include "reflection.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
namespace art {
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.
uint32_t FixupMethodFlags(uint32_t access_flags) {
access_flags &= ~kAccSynchronized;
if ((access_flags & kAccDeclaredSynchronized) != 0) {
access_flags |= kAccSynchronized;
}
return access_flags & kAccMethodFlagsMask;
}
jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
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;"),
};
} // namespace
void register_java_lang_reflect_Method(JNIEnv* env) {
jniRegisterNativeMethods(env, "java/lang/reflect/Method", gMethods, NELEM(gMethods));
}
} // namespace art