Brian Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 1 | /* |
| 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 Hughes | 418d20f | 2011-09-22 14:00:39 -0700 | [diff] [blame^] | 20 | #include "reflection.h" |
Brian Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 21 | |
| 22 | #include "JniConstants.h" // Last to avoid problems with LOG redefinition. |
| 23 | |
| 24 | namespace art { |
| 25 | |
| 26 | namespace { |
| 27 | |
Brian Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 28 | // 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. |
| 31 | uint32_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 | |
| 39 | jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, jobject jmethod, jint slot) { |
| 40 | return FixupMethodFlags(Decode<Object*>(env, jmethod)->AsMethod()->GetAccessFlags()); |
| 41 | } |
| 42 | |
Elliott Hughes | 418d20f | 2011-09-22 14:00:39 -0700 | [diff] [blame^] | 43 | jobject 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 Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 107 | static JNINativeMethod gMethods[] = { |
Brian Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 108 | NATIVE_METHOD(Method, getMethodModifiers, "(Ljava/lang/Class;Ljava/lang/reflect/AccessibleObject;I)I"), |
Elliott Hughes | 418d20f | 2011-09-22 14:00:39 -0700 | [diff] [blame^] | 109 | NATIVE_METHOD(Method, invokeNative, "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;"), |
Brian Carlstrom | f867b6f | 2011-09-16 12:17:25 -0700 | [diff] [blame] | 110 | }; |
| 111 | |
| 112 | } // namespace |
| 113 | |
| 114 | void register_java_lang_reflect_Method(JNIEnv* env) { |
| 115 | jniRegisterNativeMethods(env, "java/lang/reflect/Method", gMethods, NELEM(gMethods)); |
| 116 | } |
| 117 | |
| 118 | } // namespace art |