blob: 6ddb436ecf92aa028862a3504476cf30c7459985 [file] [log] [blame]
Brian Carlstromf867b6f2011-09-16 12:17:25 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni_internal.h"
18#include "class_linker.h"
19#include "object.h"
Elliott Hughes418d20f2011-09-22 14:00:39 -070020#include "reflection.h"
Brian Carlstromf867b6f2011-09-16 12:17:25 -070021
22#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
23
24namespace art {
25
26namespace {
27
Brian Carlstromf867b6f2011-09-16 12:17:25 -070028// We move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
29// position, because the callers of this function are trying to convey
30// the "traditional" meaning of the flags to their callers.
31uint32_t FixupMethodFlags(uint32_t access_flags) {
32 access_flags &= ~kAccSynchronized;
33 if ((access_flags & kAccDeclaredSynchronized) != 0) {
34 access_flags |= kAccSynchronized;
35 }
36 return access_flags & kAccMethodFlagsMask;
37}
38
39jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) {
40 return FixupMethodFlags(Decode<Object*>(env, jmethod)->AsMethod()->GetAccessFlags());
41}
42
Elliott Hughes418d20f2011-09-22 14:00:39 -070043jobject Method_invokeNative(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs, jclass javaDeclaringClass, jobject javaParams, jclass, jint, jboolean) {
44 Thread* self = Thread::Current();
45 ScopedThreadStateChange tsc(self, Thread::kRunnable);
46
47 jmethodID mid = env->FromReflectedMethod(javaMethod);
48 Method* m = reinterpret_cast<Method*>(mid);
49 Object* receiver = NULL;
50 if (!m->IsStatic()) {
51 // Check that the receiver is non-null and an instance of the field's declaring class.
52 receiver = Decode<Object*>(env, javaReceiver);
53 Class* declaringClass = Decode<Class*>(env, javaDeclaringClass);
54 if (!VerifyObjectInClass(env, receiver, declaringClass)) {
55 return NULL;
56 }
57
58 // Find the actual implementation of the virtual method.
59 m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
60 }
61
62 // Get our arrays of arguments and their types, and check they're the same size.
63 ObjectArray<Object>* objects = Decode<ObjectArray<Object>*>(env, javaArgs);
64 ObjectArray<Class>* classes = Decode<ObjectArray<Class>*>(env, javaParams);
65 int32_t arg_count = (objects != NULL) ? objects->GetLength() : 0;
66 if (arg_count != classes->GetLength()) {
67 self->ThrowNewException("Ljava/lang/IllegalArgumentException;",
68 "wrong number of arguments; expected %d, got %d",
69 classes->GetLength(), arg_count);
70 return NULL;
71 }
72
73 // Translate javaArgs to a jvalue[].
74 UniquePtr<jvalue[]> args(new jvalue[arg_count]);
75 JValue* decoded_args = reinterpret_cast<JValue*>(args.get());
76 for (int32_t i = 0; i < arg_count; ++i) {
77 Object* arg = objects->Get(i);
78 Class* dst_class = classes->Get(i);
79 if (dst_class->IsPrimitive()) {
80 if (!UnboxPrimitive(env, arg, dst_class, decoded_args[i])) {
81 return NULL;
82 }
83 } else {
84 args[i].l = AddLocalReference<jobject>(env, arg);
85 }
86 }
87
88 // Invoke the method.
89 JValue value = InvokeWithJValues(env, javaReceiver, mid, args.get());
90
91 // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early.
92 if (self->IsExceptionPending()) {
93 jthrowable th = env->ExceptionOccurred();
94 env->ExceptionClear();
95 jclass exception_class = env->FindClass("java/lang/reflect/InvocationTargetException");
96 jmethodID mid = env->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V");
97 jobject exception_instance = env->NewObject(exception_class, mid, th);
98 env->Throw(reinterpret_cast<jthrowable>(exception_instance));
99 return NULL;
100 }
101
102 // Box if necessary and return.
103 BoxPrimitive(env, m->GetReturnType(), value);
104 return AddLocalReference<jobject>(env, value.l);
105}
106
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700107static JNINativeMethod gMethods[] = {
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700108 NATIVE_METHOD(Method, getMethodModifiers, "(Ljava/lang/Class;Ljava/lang/reflect/AccessibleObject;I)I"),
Elliott Hughes418d20f2011-09-22 14:00:39 -0700109 NATIVE_METHOD(Method, invokeNative, "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"),
Brian Carlstromf867b6f2011-09-16 12:17:25 -0700110};
111
112} // namespace
113
114void register_java_lang_reflect_Method(JNIEnv* env) {
115 jniRegisterNativeMethods(env, "java/lang/reflect/Method", gMethods, NELEM(gMethods));
116}
117
118} // namespace art