diff options
| -rw-r--r-- | build/Android.common.mk | 1 | ||||
| -rw-r--r-- | src/class_linker.cc | 27 | ||||
| -rw-r--r-- | src/class_linker.h | 24 | ||||
| -rw-r--r-- | src/java_lang_Class.cc | 71 | ||||
| -rw-r--r-- | src/java_lang_reflect_Field.cc | 252 | ||||
| -rw-r--r-- | src/java_lang_reflect_Method.cc | 68 | ||||
| -rw-r--r-- | src/jni_internal.cc | 311 | ||||
| -rw-r--r-- | src/jni_internal.h | 3 | ||||
| -rw-r--r-- | src/oatdump.cc | 2 | ||||
| -rw-r--r-- | src/object.cc | 84 | ||||
| -rw-r--r-- | src/object.h | 19 | ||||
| -rw-r--r-- | src/reflection.cc | 275 | ||||
| -rw-r--r-- | src/reflection.h | 38 | ||||
| -rw-r--r-- | src/runtime.cc | 12 | ||||
| -rw-r--r-- | src/thread.cc | 5 |
15 files changed, 713 insertions, 479 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index 2031f30689..b92128112e 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -133,6 +133,7 @@ LIBART_COMMON_SRC_FILES := \ src/offsets.cc \ src/os_linux.cc \ src/reference_table.cc \ + src/reflection.cc \ src/runtime.cc \ src/signal_catcher.cc \ src/space.cc \ diff --git a/src/class_linker.cc b/src/class_linker.cc index be1de23756..6daa27ae75 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -72,9 +72,10 @@ void ThrowEarlierClassFailure(Class* c) { } -const char* ClassLinker::class_roots_descriptors_[kClassRootsMax] = { +const char* ClassLinker::class_roots_descriptors_[] = { "Ljava/lang/Class;", "Ljava/lang/Object;", + "[Ljava/lang/Class;", "[Ljava/lang/Object;", "Ljava/lang/String;", "Ljava/lang/reflect/Field;", @@ -153,6 +154,7 @@ ClassLinker::ClassLinker(InternTable* intern_table) array_iftable_(NULL), init_done_(false), intern_table_(intern_table) { + CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); } void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, @@ -167,6 +169,10 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, java_lang_Class->SetClassSize(sizeof(ClassClass)); // AllocClass(Class*) can now be used + // Class[] is used for reflection support. + Class* class_array_class = AllocClass(java_lang_Class, sizeof(Class)); + class_array_class->SetComponentType(java_lang_Class); + // java_lang_Object comes next so that object_array_class can be created Class* java_lang_Object = AllocClass(java_lang_Class, sizeof(Class)); CHECK(java_lang_Object != NULL); @@ -195,6 +201,7 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, // Backfill Class descriptors missing until this point java_lang_Class->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Class;")); java_lang_Object->SetDescriptor(intern_table_->InternStrong("Ljava/lang/Object;")); + class_array_class->SetDescriptor(intern_table_->InternStrong("[Ljava/lang/Class;")); object_array_class->SetDescriptor(intern_table_->InternStrong("[Ljava/lang/Object;")); java_lang_String->SetDescriptor(intern_table_->InternStrong("Ljava/lang/String;")); char_array_class->SetDescriptor(intern_table_->InternStrong("[C")); @@ -204,6 +211,7 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax); SetClassRoot(kJavaLangClass, java_lang_Class); SetClassRoot(kJavaLangObject, java_lang_Object); + SetClassRoot(kClassArrayClass, class_array_class); SetClassRoot(kObjectArrayClass, object_array_class); SetClassRoot(kCharArrayClass, char_array_class); SetClassRoot(kJavaLangString, java_lang_String); @@ -219,7 +227,7 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V", Class::kPrimVoid)); // Create array interface entries to populate once we can load system classes - array_interfaces_ = AllocObjectArray<Class>(2); + array_interfaces_ = AllocClassArray(2); array_iftable_ = AllocObjectArray<InterfaceEntry>(2); // Create int array type for AllocDexCache (done in AppendToBootClassPath) @@ -303,6 +311,9 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, SetClassRoot(kDoubleArrayClass, FindSystemClass("[D")); DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); + Class* found_class_array_class = FindSystemClass("[Ljava/lang/Class;"); + CHECK_EQ(class_array_class, found_class_array_class); + Class* found_object_array_class = FindSystemClass("[Ljava/lang/Object;"); CHECK_EQ(object_array_class, found_object_array_class); @@ -320,7 +331,9 @@ void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, array_iftable_->Set(0, AllocInterfaceEntry(array_interfaces_->Get(0))); array_iftable_->Set(1, AllocInterfaceEntry(array_interfaces_->Get(1))); - // Sanity check Object[]'s interfaces + // Sanity check Class[] and Object[]'s interfaces + CHECK_EQ(java_lang_Cloneable, class_array_class->GetInterface(0)); + CHECK_EQ(java_io_Serializable, class_array_class->GetInterface(1)); CHECK_EQ(java_lang_Cloneable, object_array_class->GetInterface(0)); CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1)); @@ -598,7 +611,7 @@ DexCache* ClassLinker::AllocDexCache(const DexFile& dex_file) { DexCache* dex_cache = down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::LengthAsArray())); dex_cache->Init(intern_table_->InternStrong(dex_file.GetLocation().c_str()), AllocObjectArray<String>(dex_file.NumStringIds()), - AllocObjectArray<Class>(dex_file.NumTypeIds()), + AllocClassArray(dex_file.NumTypeIds()), AllocObjectArray<Method>(dex_file.NumMethodIds()), AllocObjectArray<Field>(dex_file.NumFieldIds()), AllocCodeAndDirectMethods(dex_file.NumMethodIds()), @@ -908,7 +921,7 @@ void ClassLinker::LoadInterfaces(const DexFile& dex_file, Class* klass) { const DexFile::TypeList* list = dex_file.GetInterfacesList(dex_class_def); if (list != NULL) { - klass->SetInterfaces(AllocObjectArray<Class>(list->Size())); + klass->SetInterfaces(AllocClassArray(list->Size())); IntArray* interfaces_idx = IntArray::Alloc(list->Size()); klass->SetInterfacesTypeIdx(interfaces_idx); for (size_t i = 0; i < list->Size(); ++i) { @@ -1099,7 +1112,9 @@ Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor, Class* new_class = NULL; if (!init_done_) { // Classes that were hand created, ie not by FindSystemClass - if (descriptor == "[Ljava/lang/Object;") { + if (descriptor == "[Ljava/lang/Class;") { + new_class = GetClassRoot(kClassArrayClass); + } else if (descriptor == "[Ljava/lang/Object;") { new_class = GetClassRoot(kObjectArrayClass); } else if (descriptor == "[C") { new_class = GetClassRoot(kCharArrayClass); diff --git a/src/class_linker.h b/src/class_linker.h index 78be84b96d..083d641e88 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -1,4 +1,18 @@ -// Copyright 2011 Google Inc. All Rights Reserved. +/* + * Copyright (C) 2011 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. + */ #ifndef ART_SRC_CLASS_LINKER_H_ #define ART_SRC_CLASS_LINKER_H_ @@ -155,11 +169,16 @@ class ClassLinker { const DexFile& FindDexFile(const DexCache* dex_cache) const; DexCache* FindDexCache(const DexFile& dex_file) const; + // TODO: replace this with multiple methods that allocate the correct managed type. template <class T> ObjectArray<T>* AllocObjectArray(size_t length) { return ObjectArray<T>::Alloc(GetClassRoot(kObjectArrayClass), length); } + ObjectArray<Class>* AllocClassArray(size_t length) { + return ObjectArray<Class>::Alloc(GetClassRoot(kClassArrayClass), length); + } + ObjectArray<StackTraceElement>* AllocStackTraceElementArray(size_t length); void VerifyClass(Class* klass); @@ -295,6 +314,7 @@ class ClassLinker { enum ClassRoot { kJavaLangClass, kJavaLangObject, + kClassArrayClass, kObjectArrayClass, kJavaLangString, kJavaLangReflectField, @@ -345,7 +365,7 @@ class ClassLinker { class_roots_->Set(class_root, klass); } - static const char* class_roots_descriptors_[kClassRootsMax]; + static const char* class_roots_descriptors_[]; const char* GetClassRootDescriptor(ClassRoot class_root) { const char* descriptor = class_roots_descriptors_[class_root]; diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc index 9ca171b717..69ad9104a7 100644 --- a/src/java_lang_Class.cc +++ b/src/java_lang_Class.cc @@ -67,53 +67,43 @@ jclass Class_getComponentType(JNIEnv* env, jobject javaThis) { return AddLocalReference<jclass>(env, Decode<Class*>(env, javaThis)->GetComponentType()); } +bool MethodMatches(Method* m, String* name, const std::string& signature) { + if (!m->GetName()->Equals(name)) { + return false; + } + std::string method_signature = m->GetSignature()->ToModifiedUtf8(); + if (!StringPiece(method_signature).starts_with(signature)) { + return false; + } + m->InitJavaFields(); + return true; +} + jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass, - jclass jklass, jstring jname, jobjectArray jsignature) { - Class* klass = Decode<Class*>(env, jklass); - DCHECK(klass->IsClass()); - String* name = Decode<String*>(env, jname); - DCHECK(name->IsString()); - Object* signature_obj = Decode<Object*>(env, jsignature); - DCHECK(signature_obj->IsArrayInstance()); - // check that this is a Class[] by checking that component type is Class - // foo->GetClass()->GetClass() is an idiom for getting java.lang.Class from an arbitrary object - DCHECK(signature_obj->GetClass()->GetComponentType() == signature_obj->GetClass()->GetClass()); - ObjectArray<Class>* signature = down_cast<ObjectArray<Class>*>(signature_obj); - - std::string name_string = name->ToModifiedUtf8(); - std::string signature_string; - signature_string += "("; - for (int i = 0; i < signature->GetLength(); i++) { - Class* argument_class = signature->Get(0); - if (argument_class == NULL) { - UNIMPLEMENTED(FATAL) << "throw null pointer exception?"; - } - signature_string += argument_class->GetDescriptor()->ToModifiedUtf8(); + jclass javaClass, jstring javaName, jobjectArray javaSignature) { + Class* c = Decode<Class*>(env, javaClass); + String* name = Decode<String*>(env, javaName); + ObjectArray<Class>* signature_array = Decode<ObjectArray<Class>*>(env, javaSignature); + + std::string signature; + signature += "("; + for (int i = 0; i < signature_array->GetLength(); i++) { + signature += signature_array->Get(i)->GetDescriptor()->ToModifiedUtf8(); } - signature_string += ")"; + signature += ")"; - for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) { - Method* method = klass->GetVirtualMethod(i); - if (!method->GetName()->Equals(name)) { - continue; + for (size_t i = 0; i < c->NumVirtualMethods(); ++i) { + Method* m = c->GetVirtualMethod(i); + if (MethodMatches(m, name, signature)) { + return AddLocalReference<jobject>(env, m); } - std::string method_signature = method->GetSignature()->ToModifiedUtf8(); - if (!StringPiece(method_signature).starts_with(signature_string)) { - continue; - } - return AddLocalReference<jobject>(env, method); } - for (size_t i = 0; i < klass->NumDirectMethods(); ++i) { - Method* method = klass->GetDirectMethod(i); - if (!method->GetName()->Equals(name)) { - continue; - } - std::string method_signature = method->GetSignature()->ToModifiedUtf8(); - if (!StringPiece(method_signature).starts_with(signature_string)) { - continue; + for (size_t i = 0; i < c->NumDirectMethods(); ++i) { + Method* m = c->GetDirectMethod(i); + if (MethodMatches(m, name, signature)) { + return AddLocalReference<jobject>(env, m); } - return AddLocalReference<jobject>(env, method); } return NULL; @@ -326,7 +316,6 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, getEnclosingConstructor, "()Ljava/lang/reflect/Constructor;"), NATIVE_METHOD(Class, getEnclosingMethod, "()Ljava/lang/reflect/Method;"), //NATIVE_METHOD(Class, getInnerClassName, "()Ljava/lang/String;"), - //NATIVE_METHOD(Class, getInterfaces, "()[Ljava/lang/Class;"), //NATIVE_METHOD(Class, getModifiers, "(Ljava/lang/Class;Z)I"), NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), NATIVE_METHOD(Class, getSuperclass, "()Ljava/lang/Class;"), diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc index c6abe53741..5584da32d5 100644 --- a/src/java_lang_reflect_Field.cc +++ b/src/java_lang_reflect_Field.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. @@ -28,240 +29,6 @@ jint Field_getFieldModifiers(JNIEnv* env, jobject jfield, jclass javaDeclaringCl return Decode<Object*>(env, jfield)->AsField()->GetAccessFlags() & kAccFieldFlagsMask; } -// TODO: we'll need this for Method too. -bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) { - if (o == NULL) { - jniThrowNullPointerException(env, "receiver for non-static field access was null"); - return false; - } - if (!o->InstanceOf(c)) { - std::string expectedClassName(PrettyDescriptor(c->GetDescriptor())); - std::string actualClassName(PrettyTypeOf(o)); - jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", - "expected receiver of type %s, but got %s", - expectedClassName.c_str(), actualClassName.c_str()); - return false; - } - return true; -} - -/* - * Convert primitive, boxed data from "srcPtr" to "dstPtr". - * - * Section v2 2.6 lists the various conversions and promotions. We - * allow the "widening" and "identity" conversions, but don't allow the - * "narrowing" conversions. - * - * Allowed: - * byte to short, int, long, float, double - * short to int, long, float double - * char to int, long, float, double - * int to long, float, double - * long to float, double - * float to double - * Values of types byte, char, and short are "internally" widened to int. - * - * Returns the width in 32-bit words of the destination primitive, or - * -1 if the conversion is not allowed. - */ -bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst) { - Class::PrimitiveType srcType = src_class->GetPrimitiveType(); - Class::PrimitiveType dstType = dst_class->GetPrimitiveType(); - switch (dstType) { - case Class::kPrimBoolean: - case Class::kPrimChar: - case Class::kPrimByte: - if (srcType == dstType) { - dst.i = src.i; - return true; - } - break; - case Class::kPrimShort: - if (srcType == Class::kPrimByte || srcType == Class::kPrimShort) { - dst.i = src.i; - return true; - } - break; - case Class::kPrimInt: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { - dst.i = src.i; - return true; - } - break; - case Class::kPrimLong: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { - dst.j = src.i; - return true; - } else if (srcType == Class::kPrimLong) { - dst.j = src.j; - return true; - } - break; - case Class::kPrimFloat: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { - dst.f = src.i; - return true; - } else if (srcType == Class::kPrimLong) { - dst.f = src.j; - return true; - } else if (srcType == Class::kPrimFloat) { - dst.i = src.i; - return true; - } - break; - case Class::kPrimDouble: - if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || - srcType == Class::kPrimShort || srcType == Class::kPrimInt) { - dst.d = src.i; - return true; - } else if (srcType == Class::kPrimLong) { - dst.d = src.j; - return true; - } else if (srcType == Class::kPrimFloat) { - dst.d = src.f; - return true; - } else if (srcType == Class::kPrimDouble) { - dst.j = src.j; - return true; - } - break; - default: - break; - } - Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", - "invalid primitive conversion from %s to %s", - PrettyDescriptor(src_class->GetDescriptor()).c_str(), - PrettyDescriptor(dst_class->GetDescriptor()).c_str()); - return false; -} - -bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value) { - if (dst_class->GetPrimitiveType() == Class::kPrimNot) { - if (o != NULL && !o->InstanceOf(dst_class)) { - jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", - "expected object of type %s, but got %s", - PrettyDescriptor(dst_class->GetDescriptor()).c_str(), - PrettyTypeOf(o).c_str()); - return false; - } - unboxed_value.l = o; - return true; - } else if (dst_class->GetPrimitiveType() == Class::kPrimVoid) { - Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", - "can't unbox to void"); - return false; - } - - if (o == NULL) { - Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", - "null passed for boxed primitive type"); - return false; - } - - JValue boxed_value = { 0 }; - const String* src_descriptor = o->GetClass()->GetDescriptor(); - Class* src_class = NULL; - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Field* primitive_field = o->GetClass()->GetIFields()->Get(0); - if (src_descriptor->Equals("Ljava/lang/Boolean;")) { - src_class = class_linker->FindPrimitiveClass('Z'); - boxed_value.z = primitive_field->GetBoolean(o); - } else if (src_descriptor->Equals("Ljava/lang/Byte;")) { - src_class = class_linker->FindPrimitiveClass('B'); - boxed_value.b = primitive_field->GetByte(o); - } else if (src_descriptor->Equals("Ljava/lang/Character;")) { - src_class = class_linker->FindPrimitiveClass('C'); - boxed_value.c = primitive_field->GetChar(o); - } else if (src_descriptor->Equals("Ljava/lang/Float;")) { - src_class = class_linker->FindPrimitiveClass('F'); - boxed_value.f = primitive_field->GetFloat(o); - } else if (src_descriptor->Equals("Ljava/lang/Double;")) { - src_class = class_linker->FindPrimitiveClass('D'); - boxed_value.d = primitive_field->GetDouble(o); - } else if (src_descriptor->Equals("Ljava/lang/Integer;")) { - src_class = class_linker->FindPrimitiveClass('I'); - boxed_value.i = primitive_field->GetInt(o); - } else if (src_descriptor->Equals("Ljava/lang/Long;")) { - src_class = class_linker->FindPrimitiveClass('J'); - boxed_value.j = primitive_field->GetLong(o); - } else if (src_descriptor->Equals("Ljava/lang/Short;")) { - src_class = class_linker->FindPrimitiveClass('S'); - boxed_value.s = primitive_field->GetShort(o); - } else { - Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", - "%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str()); - return false; - } - - return ConvertPrimitiveValue(src_class, dst_class, boxed_value, unboxed_value); -} - -Method* gBoolean_valueOf; -Method* gByte_valueOf; -Method* gCharacter_valueOf; -Method* gDouble_valueOf; -Method* gFloat_valueOf; -Method* gInteger_valueOf; -Method* gLong_valueOf; -Method* gShort_valueOf; - -void InitBoxingMethod(JNIEnv* env, Method*& m, jclass c, const char* method_signature) { - m = DecodeMethod(env->GetStaticMethodID(c, "valueOf", method_signature)); -} - -void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value) { - if (!src_class->IsPrimitive()) { - return; - } - - Method* m = NULL; - UniquePtr<byte[]> args(new byte[8]); - memset(&args[0], 0, 8); - switch (src_class->GetPrimitiveType()) { - case Class::kPrimBoolean: - m = gBoolean_valueOf; - *reinterpret_cast<uint32_t*>(&args[0]) = value.z; - break; - case Class::kPrimByte: - m = gByte_valueOf; - *reinterpret_cast<uint32_t*>(&args[0]) = value.b; - break; - case Class::kPrimChar: - m = gCharacter_valueOf; - *reinterpret_cast<uint32_t*>(&args[0]) = value.c; - break; - case Class::kPrimDouble: - m = gDouble_valueOf; - *reinterpret_cast<double*>(&args[0]) = value.d; - break; - case Class::kPrimFloat: - m = gFloat_valueOf; - *reinterpret_cast<float*>(&args[0]) = value.f; - break; - case Class::kPrimInt: - m = gInteger_valueOf; - *reinterpret_cast<uint32_t*>(&args[0]) = value.i; - break; - case Class::kPrimLong: - m = gLong_valueOf; - *reinterpret_cast<uint64_t*>(&args[0]) = value.j; - break; - case Class::kPrimShort: - m = gShort_valueOf; - *reinterpret_cast<uint32_t*>(&args[0]) = value.s; - break; - default: - LOG(FATAL) << PrettyClass(src_class); - } - - Thread* self = Thread::Current(); - ScopedThreadStateChange tsc(self, Thread::kRunnable); - m->Invoke(self, NULL, args.get(), &value); -} - bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) { switch (f->GetType()->GetPrimitiveType()) { case Class::kPrimBoolean: @@ -305,7 +72,7 @@ bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) { } JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar targetDescriptor) { - Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField)); + Field* f = DecodeField(env->FromReflectedField(javaField)); // Check that the receiver is non-null and an instance of the field's declaring class. Object* o = Decode<Object*>(env, javaObj); @@ -406,7 +173,7 @@ void SetFieldValue(Object* o, Field* f, const JValue& new_value, bool allow_refe } void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jchar targetDescriptor, const JValue& new_value) { - Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField)); + Field* f = DecodeField(env->FromReflectedField(javaField)); // Check that the receiver is non-null and an instance of the field's declaring class. Object* o = Decode<Object*>(env, javaObj); @@ -478,7 +245,7 @@ void Field_setZField(JNIEnv* env, jobject javaField, jobject javaObj, jclass jav } void Field_setField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean, jobject javaValue) { - Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField)); + Field* f = DecodeField(env->FromReflectedField(javaField)); // Unbox the value, if necessary. Object* boxed_value = Decode<Object*>(env, javaValue); @@ -501,7 +268,7 @@ void Field_setField(JNIEnv* env, jobject javaField, jobject javaObj, jclass java } jobject Field_getField(JNIEnv* env, jobject javaField, jobject javaObj, jclass javaDeclaringClass, jclass, jint, jboolean) { - Field* f = reinterpret_cast<Field*>(env->FromReflectedField(javaField)); + Field* f = DecodeField(env->FromReflectedField(javaField)); // Check that the receiver is non-null and an instance of the field's declaring class. Object* o = Decode<Object*>(env, javaObj); @@ -549,14 +316,7 @@ static JNINativeMethod gMethods[] = { } // namespace void register_java_lang_reflect_Field(JNIEnv* env) { - InitBoxingMethod(env, gBoolean_valueOf, JniConstants::booleanClass, "(Z)Ljava/lang/Boolean;"); - InitBoxingMethod(env, gByte_valueOf, JniConstants::byteClass, "(B)Ljava/lang/Byte;"); - InitBoxingMethod(env, gCharacter_valueOf, JniConstants::characterClass, "(C)Ljava/lang/Character;"); - InitBoxingMethod(env, gDouble_valueOf, JniConstants::doubleClass, "(D)Ljava/lang/Double;"); - InitBoxingMethod(env, gFloat_valueOf, JniConstants::floatClass, "(F)Ljava/lang/Float;"); - InitBoxingMethod(env, gInteger_valueOf, JniConstants::integerClass, "(I)Ljava/lang/Integer;"); - InitBoxingMethod(env, gLong_valueOf, JniConstants::longClass, "(J)Ljava/lang/Long;"); - InitBoxingMethod(env, gShort_valueOf, JniConstants::shortClass, "(S)Ljava/lang/Short;"); + InitBoxingMethods(env); // TODO: move to Runtime? jniRegisterNativeMethods(env, "java/lang/reflect/Field", gMethods, NELEM(gMethods)); } diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc index 188614f484..6ddb436ecf 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 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. @@ -40,9 +40,73 @@ jint Method_getMethodModifiers(JNIEnv* env, jclass, jclass javaDeclaringClass, j 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 diff --git a/src/jni_internal.cc b/src/jni_internal.cc index e196c0c4e8..96b3b34492 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -111,6 +111,8 @@ template Class* Decode<Class*>(JNIEnv*, jobject); template ClassLoader* Decode<ClassLoader*>(JNIEnv*, jobject); template Object* Decode<Object*>(JNIEnv*, jobject); template String* Decode<String*>(JNIEnv*, jobject); +template ObjectArray<Class>* Decode<ObjectArray<Class>*>(JNIEnv*, jobject); +template ObjectArray<Object>* Decode<ObjectArray<Object>*>(JNIEnv*, jobject); template ObjectArray<StackTraceElement>* Decode<ObjectArray<StackTraceElement>*>(JNIEnv*, jobject); namespace { @@ -132,7 +134,8 @@ T Decode(ScopedJniThreadState& ts, jobject obj) { return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj)); } -byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) { +byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); size_t num_bytes = method->NumArgArrayBytes(); UniquePtr<byte[]> arg_array(new byte[num_bytes]); const String* shorty = method->GetShorty(); @@ -151,7 +154,7 @@ byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) { offset += 4; break; case 'L': { - Object* obj = Decode<Object*>(ts, va_arg(ap, jobject)); + Object* obj = Decode<Object*>(env, va_arg(ap, jobject)); *reinterpret_cast<Object**>(&arg_array[offset]) = obj; offset += sizeof(Object*); break; @@ -169,7 +172,8 @@ byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) { return arg_array.release(); } -byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, jvalue* args) { +byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); size_t num_bytes = method->NumArgArrayBytes(); UniquePtr<byte[]> arg_array(new byte[num_bytes]); const String* shorty = method->GetShorty(); @@ -188,7 +192,7 @@ byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, jvalue* args) { offset += 4; break; case 'L': { - Object* obj = Decode<Object*>(ts, args[i - 1].l); + Object* obj = Decode<Object*>(env, args[i - 1].l); *reinterpret_cast<Object**>(&arg_array[offset]) = obj; offset += sizeof(Object*); break; @@ -206,43 +210,39 @@ byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, jvalue* args) { return arg_array.release(); } -JValue InvokeWithArgArray(ScopedJniThreadState& ts, Object* receiver, - Method* method, byte* args) { +JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, byte* args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); JValue result; - method->Invoke(ts.Self(), receiver, args, &result); + method->Invoke(env->self, receiver, args, &result); return result; } -JValue InvokeWithJValues(ScopedJniThreadState& ts, jobject obj, jmethodID mid, jvalue* args) { - Object* receiver = Decode<Object*>(ts, obj); - Method* method = DecodeMethod(mid); - UniquePtr<byte[]> arg_array(CreateArgArray(ts, method, args)); - return InvokeWithArgArray(ts, receiver, method, arg_array.get()); -} - -JValue InvokeWithVarArgs(ScopedJniThreadState& ts, jobject obj, jmethodID mid, va_list args) { - Object* receiver = Decode<Object*>(ts, obj); +JValue InvokeWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); + Object* receiver = Decode<Object*>(env, obj); Method* method = DecodeMethod(mid); - UniquePtr<byte[]> arg_array(CreateArgArray(ts, method, args)); - return InvokeWithArgArray(ts, receiver, method, arg_array.get()); + UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args)); + return InvokeWithArgArray(env, receiver, method, arg_array.get()); } Method* FindVirtualMethod(Object* receiver, Method* method) { return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method); } -JValue InvokeVirtualOrInterfaceWithJValues(ScopedJniThreadState& ts, jobject obj, jmethodID mid, jvalue* args) { - Object* receiver = Decode<Object*>(ts, obj); +JValue InvokeVirtualOrInterfaceWithJValues(JNIEnv* public_env, jobject obj, jmethodID mid, jvalue* args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); + Object* receiver = Decode<Object*>(env, obj); Method* method = FindVirtualMethod(receiver, DecodeMethod(mid)); - UniquePtr<byte[]> arg_array(CreateArgArray(ts, method, args)); - return InvokeWithArgArray(ts, receiver, method, arg_array.get()); + UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args)); + return InvokeWithArgArray(env, receiver, method, arg_array.get()); } -JValue InvokeVirtualOrInterfaceWithVarArgs(ScopedJniThreadState& ts, jobject obj, jmethodID mid, va_list args) { - Object* receiver = Decode<Object*>(ts, obj); +JValue InvokeVirtualOrInterfaceWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); + Object* receiver = Decode<Object*>(env, obj); Method* method = FindVirtualMethod(receiver, DecodeMethod(mid)); - UniquePtr<byte[]> arg_array(CreateArgArray(ts, method, args)); - return InvokeWithArgArray(ts, receiver, method, arg_array.get()); + UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args)); + return InvokeWithArgArray(env, receiver, method, arg_array.get()); } // Section 12.3.2 of the JNI spec describes JNI class descriptors. They're @@ -298,6 +298,8 @@ jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* n return NULL; } + method->InitJavaFields(); + return EncodeMethod(method); } @@ -606,6 +608,14 @@ class Libraries { std::map<std::string, SharedLibrary*> libraries_; }; +JValue InvokeWithJValues(JNIEnv* public_env, jobject obj, jmethodID mid, jvalue* args) { + JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); + Object* receiver = Decode<Object*>(env, obj); + Method* method = DecodeMethod(mid); + UniquePtr<byte[]> arg_array(CreateArgArray(env, method, args)); + return InvokeWithArgArray(env, receiver, method, arg_array.get()); +} + class JNI { public: @@ -952,20 +962,20 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return AddLocalReference<jobject>(env, result.l); } static jobject CallObjectMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args); return AddLocalReference<jobject>(env, result.l); } static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - JValue result = InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args); + JValue result = InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args); return AddLocalReference<jobject>(env, result.l); } @@ -973,170 +983,170 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.z; } static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).z; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).z; } static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).z; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).z; } static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.b; } static jbyte CallByteMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).b; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).b; } static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).b; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).b; } static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.c; } static jchar CallCharMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).c; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).c; } static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).c; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).c; } static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.d; } static jdouble CallDoubleMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).d; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).d; } static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).d; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).d; } static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.f; } static jfloat CallFloatMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).f; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).f; } static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).f; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).f; } static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.i; } static jint CallIntMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).i; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).i; } static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).i; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).i; } static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.j; } static jlong CallLongMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).j; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).j; } static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).j; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).j; } static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); return result.s; } static jshort CallShortMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args).s; + return InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args).s; } static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args).s; + return InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args).s; } static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, ap); va_end(ap); } static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args); + InvokeVirtualOrInterfaceWithVarArgs(env, obj, mid, args); } static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args); + InvokeVirtualOrInterfaceWithJValues(env, obj, mid, args); } static jobject CallNonvirtualObjectMethod(JNIEnv* env, @@ -1144,7 +1154,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); jobject local_result = AddLocalReference<jobject>(env, result.l); va_end(ap); return local_result; @@ -1153,14 +1163,14 @@ class JNI { static jobject CallNonvirtualObjectMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - JValue result = InvokeWithVarArgs(ts, obj, mid, args); + JValue result = InvokeWithVarArgs(env, obj, mid, args); return AddLocalReference<jobject>(env, result.l); } static jobject CallNonvirtualObjectMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - JValue result = InvokeWithJValues(ts, obj, mid, args); + JValue result = InvokeWithJValues(env, obj, mid, args); return AddLocalReference<jobject>(env, result.l); } @@ -1169,7 +1179,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.z; } @@ -1177,13 +1187,13 @@ class JNI { static jboolean CallNonvirtualBooleanMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).z; + return InvokeWithVarArgs(env, obj, mid, args).z; } static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).z; + return InvokeWithJValues(env, obj, mid, args).z; } static jbyte CallNonvirtualByteMethod(JNIEnv* env, @@ -1191,7 +1201,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.b; } @@ -1199,13 +1209,13 @@ class JNI { static jbyte CallNonvirtualByteMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).b; + return InvokeWithVarArgs(env, obj, mid, args).b; } static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).b; + return InvokeWithJValues(env, obj, mid, args).b; } static jchar CallNonvirtualCharMethod(JNIEnv* env, @@ -1213,7 +1223,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.c; } @@ -1221,13 +1231,13 @@ class JNI { static jchar CallNonvirtualCharMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).c; + return InvokeWithVarArgs(env, obj, mid, args).c; } static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).c; + return InvokeWithJValues(env, obj, mid, args).c; } static jshort CallNonvirtualShortMethod(JNIEnv* env, @@ -1235,7 +1245,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.s; } @@ -1243,21 +1253,20 @@ class JNI { static jshort CallNonvirtualShortMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).s; + return InvokeWithVarArgs(env, obj, mid, args).s; } static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).s; + return InvokeWithJValues(env, obj, mid, args).s; } - static jint CallNonvirtualIntMethod(JNIEnv* env, - jobject obj, jclass clazz, jmethodID mid, ...) { + static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.i; } @@ -1265,13 +1274,13 @@ class JNI { static jint CallNonvirtualIntMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).i; + return InvokeWithVarArgs(env, obj, mid, args).i; } static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).i; + return InvokeWithJValues(env, obj, mid, args).i; } static jlong CallNonvirtualLongMethod(JNIEnv* env, @@ -1279,7 +1288,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.j; } @@ -1287,13 +1296,13 @@ class JNI { static jlong CallNonvirtualLongMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).j; + return InvokeWithVarArgs(env, obj, mid, args).j; } static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).j; + return InvokeWithJValues(env, obj, mid, args).j; } static jfloat CallNonvirtualFloatMethod(JNIEnv* env, @@ -1301,7 +1310,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.f; } @@ -1309,13 +1318,13 @@ class JNI { static jfloat CallNonvirtualFloatMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).f; + return InvokeWithVarArgs(env, obj, mid, args).f; } static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).f; + return InvokeWithJValues(env, obj, mid, args).f; } static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, @@ -1323,7 +1332,7 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, obj, mid, ap); + JValue result = InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); return result.d; } @@ -1331,13 +1340,13 @@ class JNI { static jdouble CallNonvirtualDoubleMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, obj, mid, args).d; + return InvokeWithVarArgs(env, obj, mid, args).d; } static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, obj, mid, args).d; + return InvokeWithJValues(env, obj, mid, args).d; } static void CallNonvirtualVoidMethod(JNIEnv* env, @@ -1345,20 +1354,20 @@ class JNI { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - InvokeWithVarArgs(ts, obj, mid, ap); + InvokeWithVarArgs(env, obj, mid, ap); va_end(ap); } static void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - InvokeWithVarArgs(ts, obj, mid, args); + InvokeWithVarArgs(env, obj, mid, args); } static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - InvokeWithJValues(ts, obj, mid, args); + InvokeWithJValues(env, obj, mid, args); } static jfieldID GetFieldID(JNIEnv* env, jclass c, const char* name, const char* sig) { @@ -1540,218 +1549,196 @@ class JNI { SET_PRIMITIVE_FIELD(SetShort, NULL, v); } - static jobject CallStaticObjectMethod(JNIEnv* env, - jclass clazz, jmethodID mid, ...) { + static jobject CallStaticObjectMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); jobject local_result = AddLocalReference<jobject>(env, result.l); va_end(ap); return local_result; } - static jobject CallStaticObjectMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jobject CallStaticObjectMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - JValue result = InvokeWithVarArgs(ts, NULL, mid, args); + JValue result = InvokeWithVarArgs(env, NULL, mid, args); return AddLocalReference<jobject>(env, result.l); } - static jobject CallStaticObjectMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jobject CallStaticObjectMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - JValue result = InvokeWithJValues(ts, NULL, mid, args); + JValue result = InvokeWithJValues(env, NULL, mid, args); return AddLocalReference<jobject>(env, result.l); } - static jboolean CallStaticBooleanMethod(JNIEnv* env, - jclass clazz, jmethodID mid, ...) { + static jboolean CallStaticBooleanMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.z; } - static jboolean CallStaticBooleanMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).z; + return InvokeWithVarArgs(env, NULL, mid, args).z; } - static jboolean CallStaticBooleanMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).z; + return InvokeWithJValues(env, NULL, mid, args).z; } static jbyte CallStaticByteMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.b; } - static jbyte CallStaticByteMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jbyte CallStaticByteMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).b; + return InvokeWithVarArgs(env, NULL, mid, args).b; } - static jbyte CallStaticByteMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jbyte CallStaticByteMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).b; + return InvokeWithJValues(env, NULL, mid, args).b; } static jchar CallStaticCharMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.c; } - static jchar CallStaticCharMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jchar CallStaticCharMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).c; + return InvokeWithVarArgs(env, NULL, mid, args).c; } - static jchar CallStaticCharMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jchar CallStaticCharMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).c; + return InvokeWithJValues(env, NULL, mid, args).c; } static jshort CallStaticShortMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.s; } - static jshort CallStaticShortMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jshort CallStaticShortMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).s; + return InvokeWithVarArgs(env, NULL, mid, args).s; } - static jshort CallStaticShortMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jshort CallStaticShortMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).s; + return InvokeWithJValues(env, NULL, mid, args).s; } static jint CallStaticIntMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.i; } - static jint CallStaticIntMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jint CallStaticIntMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).i; + return InvokeWithVarArgs(env, NULL, mid, args).i; } - static jint CallStaticIntMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jint CallStaticIntMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).i; + return InvokeWithJValues(env, NULL, mid, args).i; } static jlong CallStaticLongMethod(JNIEnv* env, jclass clazz, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.j; } - static jlong CallStaticLongMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jlong CallStaticLongMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).j; + return InvokeWithVarArgs(env, NULL, mid, args).j; } - static jlong CallStaticLongMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jlong CallStaticLongMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).j; + return InvokeWithJValues(env, NULL, mid, args).j; } static jfloat CallStaticFloatMethod(JNIEnv* env, jclass cls, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.f; } - static jfloat CallStaticFloatMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).f; + return InvokeWithVarArgs(env, NULL, mid, args).f; } - static jfloat CallStaticFloatMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).f; + return InvokeWithJValues(env, NULL, mid, args).f; } static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass cls, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - JValue result = InvokeWithVarArgs(ts, NULL, mid, ap); + JValue result = InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); return result.d; } - static jdouble CallStaticDoubleMethodV(JNIEnv* env, - jclass clazz, jmethodID mid, va_list args) { + static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass clazz, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - return InvokeWithVarArgs(ts, NULL, mid, args).d; + return InvokeWithVarArgs(env, NULL, mid, args).d; } - static jdouble CallStaticDoubleMethodA(JNIEnv* env, - jclass clazz, jmethodID mid, jvalue* args) { + static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass clazz, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - return InvokeWithJValues(ts, NULL, mid, args).d; + return InvokeWithJValues(env, NULL, mid, args).d; } static void CallStaticVoidMethod(JNIEnv* env, jclass cls, jmethodID mid, ...) { ScopedJniThreadState ts(env); va_list ap; va_start(ap, mid); - InvokeWithVarArgs(ts, NULL, mid, ap); + InvokeWithVarArgs(env, NULL, mid, ap); va_end(ap); } - static void CallStaticVoidMethodV(JNIEnv* env, - jclass cls, jmethodID mid, va_list args) { + static void CallStaticVoidMethodV(JNIEnv* env, jclass cls, jmethodID mid, va_list args) { ScopedJniThreadState ts(env); - InvokeWithVarArgs(ts, NULL, mid, args); + InvokeWithVarArgs(env, NULL, mid, args); } - static void CallStaticVoidMethodA(JNIEnv* env, - jclass cls, jmethodID mid, jvalue* args) { + static void CallStaticVoidMethodA(JNIEnv* env, jclass cls, jmethodID mid, jvalue* args) { ScopedJniThreadState ts(env); - InvokeWithJValues(ts, NULL, mid, args); + InvokeWithJValues(env, NULL, mid, args); } static jstring NewString(JNIEnv* env, const jchar* chars, jsize char_count) { diff --git a/src/jni_internal.h b/src/jni_internal.h index 392ad24a64..e5bcb75aba 100644 --- a/src/jni_internal.h +++ b/src/jni_internal.h @@ -18,6 +18,7 @@ namespace art { class ClassLoader; class Field; +union JValue; class Libraries; class Method; class Thread; @@ -58,6 +59,8 @@ inline jmethodID EncodeMethod(Method* method) { return reinterpret_cast<jmethodID>(method); } +JValue InvokeWithJValues(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args); + struct JavaVMExt : public JavaVM { JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options); ~JavaVMExt(); diff --git a/src/oatdump.cc b/src/oatdump.cc index 4602af9907..2a88e3d329 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -76,7 +76,7 @@ class OatDump { os << reinterpret_cast<void*>(image_header.GetBaseAddr()) << "\n\n"; os << "ROOTS:\n"; - CHECK(sizeof(image_roots_descriptions_)/(sizeof(char*)) == ImageHeader::kImageRootsMax); + CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax)); for (int i = 0; i < ImageHeader::kImageRootsMax; i++) { ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i); os << StringPrintf("%s: %p\n", diff --git a/src/object.cc b/src/object.cc index 12cd68d604..813abce452 100644 --- a/src/object.cc +++ b/src/object.cc @@ -321,6 +321,76 @@ void Method::ResetClass() { java_lang_reflect_Method_ = NULL; } +Class* ExtractNextClassFromSignature(ClassLinker* class_linker, const ClassLoader* cl, const char*& p) { + if (*p == '[') { + // Something like "[[[Ljava/lang/String;". + const char* start = p; + while (*p == '[') { + ++p; + } + if (*p == 'L') { + while (*p != ';') { + ++p; + } + } + ++p; // Either the ';' or the primitive type. + + StringPiece descriptor(start, (p - start)); + return class_linker->FindClass(descriptor, cl); + } else if (*p == 'L') { + const char* start = p; + while (*p != ';') { + ++p; + } + ++p; + StringPiece descriptor(start, (p - start)); + return class_linker->FindClass(descriptor, cl); + } else { + return class_linker->FindPrimitiveClass(*p++); + } +} + +void Method::InitJavaFieldsLocked() { + // Create the array. + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + size_t arg_count = GetShorty()->GetLength() - 1; + Class* array_class = class_linker->FindSystemClass("[Ljava/lang/Class;"); + ObjectArray<Class>* parameters = ObjectArray<Class>::Alloc(array_class, arg_count); + if (parameters == NULL) { + return; + } + + // Parse the signature, filling the array. + const ClassLoader* cl = GetDeclaringClass()->GetClassLoader(); + std::string signature(GetSignature()->ToModifiedUtf8()); + const char* p = signature.c_str(); + DCHECK_EQ(*p, '('); + ++p; + for (size_t i = 0; i < arg_count; ++i) { + Class* c = ExtractNextClassFromSignature(class_linker, cl, p); + if (c == NULL) { + return; + } + parameters->Set(i, c); + } + + DCHECK_EQ(*p, ')'); + ++p; + + java_parameter_types_ = parameters; + java_return_type_ = ExtractNextClassFromSignature(class_linker, cl, p); +} + +void Method::InitJavaFields() { + Thread* self = Thread::Current(); + ScopedThreadStateChange tsc(self, Thread::kRunnable); + MonitorEnter(self); + if (java_parameter_types_ == NULL || java_return_type_ == NULL) { + InitJavaFieldsLocked(); + } + MonitorExit(self); +} + ObjectArray<String>* Method::GetDexCacheStrings() const { return GetFieldObject<ObjectArray<String>*>( OFFSET_OF_OBJECT_MEMBER(Method, dex_cache_strings_), false); @@ -1304,9 +1374,17 @@ bool String::Equals(const char* modified_utf8) const { } bool String::Equals(const StringPiece& modified_utf8) const { - // TODO: do not assume C-string representation. For now DCHECK. - DCHECK_EQ(modified_utf8.data()[modified_utf8.size()], 0); - return Equals(modified_utf8.data()); + if (modified_utf8.size() != GetLength()) { + return false; + } + const char* p = modified_utf8.data(); + for (int32_t i = 0; i < GetLength(); ++i) { + uint16_t ch = GetUtf16FromUtf8(&p); + if (ch != CharAt(i)) { + return false; + } + } + return true; } // Create a modified UTF-8 encoded std::string from a java/lang/String object. diff --git a/src/object.h b/src/object.h index ffc8cafabd..2ee90fcac1 100644 --- a/src/object.h +++ b/src/object.h @@ -916,8 +916,7 @@ class MANAGED Method : public AccessibleObject { void SetCoreSpillMask(uint32_t core_spill_mask) { // Computed during compilation - SetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), - core_spill_mask, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), core_spill_mask, false); } uint32_t GetFpSpillMask() const { @@ -926,8 +925,7 @@ class MANAGED Method : public AccessibleObject { void SetFpSpillMask(uint32_t fp_spill_mask) { // Computed during compilation - SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), - fp_spill_mask, false); + SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), fp_spill_mask, false); } // Is this a hand crafted method used for something like describing callee saves? @@ -958,13 +956,16 @@ class MANAGED Method : public AccessibleObject { static Class* GetMethodClass() { return java_lang_reflect_Method_; } static void ResetClass(); + void InitJavaFields(); + private: uint32_t GetReturnTypeIdx() const; + void InitJavaFieldsLocked(); // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // the class we are a part of Class* declaring_class_; - ObjectArray<Class>* java_exception_types_; + ObjectArray<Class>* java_exception_types_; // TODO Object* java_formal_type_parameters_; Object* java_generic_exception_types_; Object* java_generic_parameter_types_; @@ -972,9 +973,9 @@ class MANAGED Method : public AccessibleObject { String* name_; + // Initialized by InitJavaFields. ObjectArray<Class>* java_parameter_types_; - - Class* java_return_type_; // Unused by ART + Class* java_return_type_; // Storage for code_ const ByteArray* code_array_; @@ -1728,7 +1729,7 @@ class MANAGED Class : public StaticStorageBase { } void SetInterface(uint32_t i, Class* f) { // TODO: uint16_t - DCHECK_NE(NumInterfaces(), 0U); + DCHECK_LT(i, NumInterfaces()); ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>( OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false); @@ -1736,7 +1737,7 @@ class MANAGED Class : public StaticStorageBase { } Class* GetInterface(uint32_t i) const { - DCHECK_NE(NumInterfaces(), 0U); + DCHECK_LT(i, NumInterfaces()); return GetInterfaces()->Get(i); } diff --git a/src/reflection.cc b/src/reflection.cc new file mode 100644 index 0000000000..3edb9f7fe6 --- /dev/null +++ b/src/reflection.cc @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2011 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 "reflection.h" + +#include "class_linker.h" +#include "jni_internal.h" +#include "object.h" + +#include "JniConstants.h" // Last to avoid problems with LOG redefinition. + +namespace art { + +Method* gBoolean_valueOf; +Method* gByte_valueOf; +Method* gCharacter_valueOf; +Method* gDouble_valueOf; +Method* gFloat_valueOf; +Method* gInteger_valueOf; +Method* gLong_valueOf; +Method* gShort_valueOf; + +void InitBoxingMethod(JNIEnv* env, Method*& m, jclass c, const char* method_signature) { + m = DecodeMethod(env->GetStaticMethodID(c, "valueOf", method_signature)); +} + +void InitBoxingMethods(JNIEnv* env) { + InitBoxingMethod(env, gBoolean_valueOf, JniConstants::booleanClass, "(Z)Ljava/lang/Boolean;"); + InitBoxingMethod(env, gByte_valueOf, JniConstants::byteClass, "(B)Ljava/lang/Byte;"); + InitBoxingMethod(env, gCharacter_valueOf, JniConstants::characterClass, "(C)Ljava/lang/Character;"); + InitBoxingMethod(env, gDouble_valueOf, JniConstants::doubleClass, "(D)Ljava/lang/Double;"); + InitBoxingMethod(env, gFloat_valueOf, JniConstants::floatClass, "(F)Ljava/lang/Float;"); + InitBoxingMethod(env, gInteger_valueOf, JniConstants::integerClass, "(I)Ljava/lang/Integer;"); + InitBoxingMethod(env, gLong_valueOf, JniConstants::longClass, "(J)Ljava/lang/Long;"); + InitBoxingMethod(env, gShort_valueOf, JniConstants::shortClass, "(S)Ljava/lang/Short;"); +} + +bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c) { + if (o == NULL) { + jniThrowNullPointerException(env, "receiver for non-static field access was null"); + return false; + } + if (!o->InstanceOf(c)) { + std::string expectedClassName(PrettyDescriptor(c->GetDescriptor())); + std::string actualClassName(PrettyTypeOf(o)); + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", + "expected receiver of type %s, but got %s", + expectedClassName.c_str(), actualClassName.c_str()); + return false; + } + return true; +} + +/* + * Convert primitive, boxed data from "srcPtr" to "dstPtr". + * + * Section v2 2.6 lists the various conversions and promotions. We + * allow the "widening" and "identity" conversions, but don't allow the + * "narrowing" conversions. + * + * Allowed: + * byte to short, int, long, float, double + * short to int, long, float double + * char to int, long, float, double + * int to long, float, double + * long to float, double + * float to double + * Values of types byte, char, and short are "internally" widened to int. + * + * Returns the width in 32-bit words of the destination primitive, or + * -1 if the conversion is not allowed. + */ +bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst) { + Class::PrimitiveType srcType = src_class->GetPrimitiveType(); + Class::PrimitiveType dstType = dst_class->GetPrimitiveType(); + switch (dstType) { + case Class::kPrimBoolean: + case Class::kPrimChar: + case Class::kPrimByte: + if (srcType == dstType) { + dst.i = src.i; + return true; + } + break; + case Class::kPrimShort: + if (srcType == Class::kPrimByte || srcType == Class::kPrimShort) { + dst.i = src.i; + return true; + } + break; + case Class::kPrimInt: + if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || + srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + dst.i = src.i; + return true; + } + break; + case Class::kPrimLong: + if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || + srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + dst.j = src.i; + return true; + } else if (srcType == Class::kPrimLong) { + dst.j = src.j; + return true; + } + break; + case Class::kPrimFloat: + if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || + srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + dst.f = src.i; + return true; + } else if (srcType == Class::kPrimLong) { + dst.f = src.j; + return true; + } else if (srcType == Class::kPrimFloat) { + dst.i = src.i; + return true; + } + break; + case Class::kPrimDouble: + if (srcType == Class::kPrimByte || srcType == Class::kPrimChar || + srcType == Class::kPrimShort || srcType == Class::kPrimInt) { + dst.d = src.i; + return true; + } else if (srcType == Class::kPrimLong) { + dst.d = src.j; + return true; + } else if (srcType == Class::kPrimFloat) { + dst.d = src.f; + return true; + } else if (srcType == Class::kPrimDouble) { + dst.j = src.j; + return true; + } + break; + default: + break; + } + Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", + "invalid primitive conversion from %s to %s", + PrettyDescriptor(src_class->GetDescriptor()).c_str(), + PrettyDescriptor(dst_class->GetDescriptor()).c_str()); + return false; +} + +void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value) { + if (!src_class->IsPrimitive()) { + return; + } + + Method* m = NULL; + UniquePtr<byte[]> args(new byte[8]); + memset(&args[0], 0, 8); + switch (src_class->GetPrimitiveType()) { + case Class::kPrimBoolean: + m = gBoolean_valueOf; + *reinterpret_cast<uint32_t*>(&args[0]) = value.z; + break; + case Class::kPrimByte: + m = gByte_valueOf; + *reinterpret_cast<uint32_t*>(&args[0]) = value.b; + break; + case Class::kPrimChar: + m = gCharacter_valueOf; + *reinterpret_cast<uint32_t*>(&args[0]) = value.c; + break; + case Class::kPrimDouble: + m = gDouble_valueOf; + *reinterpret_cast<double*>(&args[0]) = value.d; + break; + case Class::kPrimFloat: + m = gFloat_valueOf; + *reinterpret_cast<float*>(&args[0]) = value.f; + break; + case Class::kPrimInt: + m = gInteger_valueOf; + *reinterpret_cast<uint32_t*>(&args[0]) = value.i; + break; + case Class::kPrimLong: + m = gLong_valueOf; + *reinterpret_cast<uint64_t*>(&args[0]) = value.j; + break; + case Class::kPrimShort: + m = gShort_valueOf; + *reinterpret_cast<uint32_t*>(&args[0]) = value.s; + break; + case Class::kPrimVoid: + // There's no such thing as a void field, and void methods invoked via reflection return null. + value.l = NULL; + return; + default: + LOG(FATAL) << PrettyClass(src_class); + } + + Thread* self = Thread::Current(); + ScopedThreadStateChange tsc(self, Thread::kRunnable); + m->Invoke(self, NULL, args.get(), &value); +} + +bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value) { + if (dst_class->GetPrimitiveType() == Class::kPrimNot) { + if (o != NULL && !o->InstanceOf(dst_class)) { + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", + "expected object of type %s, but got %s", + PrettyDescriptor(dst_class->GetDescriptor()).c_str(), + PrettyTypeOf(o).c_str()); + return false; + } + unboxed_value.l = o; + return true; + } else if (dst_class->GetPrimitiveType() == Class::kPrimVoid) { + Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", + "can't unbox to void"); + return false; + } + + if (o == NULL) { + Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", + "null passed for boxed primitive type"); + return false; + } + + JValue boxed_value = { 0 }; + const String* src_descriptor = o->GetClass()->GetDescriptor(); + Class* src_class = NULL; + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Field* primitive_field = o->GetClass()->GetIFields()->Get(0); + if (src_descriptor->Equals("Ljava/lang/Boolean;")) { + src_class = class_linker->FindPrimitiveClass('Z'); + boxed_value.z = primitive_field->GetBoolean(o); + } else if (src_descriptor->Equals("Ljava/lang/Byte;")) { + src_class = class_linker->FindPrimitiveClass('B'); + boxed_value.b = primitive_field->GetByte(o); + } else if (src_descriptor->Equals("Ljava/lang/Character;")) { + src_class = class_linker->FindPrimitiveClass('C'); + boxed_value.c = primitive_field->GetChar(o); + } else if (src_descriptor->Equals("Ljava/lang/Float;")) { + src_class = class_linker->FindPrimitiveClass('F'); + boxed_value.f = primitive_field->GetFloat(o); + } else if (src_descriptor->Equals("Ljava/lang/Double;")) { + src_class = class_linker->FindPrimitiveClass('D'); + boxed_value.d = primitive_field->GetDouble(o); + } else if (src_descriptor->Equals("Ljava/lang/Integer;")) { + src_class = class_linker->FindPrimitiveClass('I'); + boxed_value.i = primitive_field->GetInt(o); + } else if (src_descriptor->Equals("Ljava/lang/Long;")) { + src_class = class_linker->FindPrimitiveClass('J'); + boxed_value.j = primitive_field->GetLong(o); + } else if (src_descriptor->Equals("Ljava/lang/Short;")) { + src_class = class_linker->FindPrimitiveClass('S'); + boxed_value.s = primitive_field->GetShort(o); + } else { + Thread::Current()->ThrowNewException("Ljava/lang/IllegalArgumentException;", + "%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str()); + return false; + } + + return ConvertPrimitiveValue(src_class, dst_class, boxed_value, unboxed_value); +} + +} // namespace art diff --git a/src/reflection.h b/src/reflection.h new file mode 100644 index 0000000000..7256754f90 --- /dev/null +++ b/src/reflection.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef ART_SRC_REFLECTION_H_ +#define ART_SRC_REFLECTION_H_ + +#include "jni.h" + +namespace art { + +class Class; +union JValue; +class Object; + +void InitBoxingMethods(JNIEnv* env); +void BoxPrimitive(JNIEnv* env, Class* src_class, JValue& value); +bool UnboxPrimitive(JNIEnv* env, Object* o, Class* dst_class, JValue& unboxed_value); + +bool ConvertPrimitiveValue(Class* src_class, Class* dst_class, const JValue& src, JValue& dst); + +bool VerifyObjectInClass(JNIEnv* env, Object* o, Class* c); + +} // namespace art + +#endif // ART_SRC_REFLECTION_H_ diff --git a/src/runtime.cc b/src/runtime.cc index 751e8da259..b1da77d350 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -440,17 +440,19 @@ void Runtime::InitNativeMethods() { Thread* self = Thread::Current(); JNIEnv* env = self->GetJniEnv(); - // Must be in the kNative state for JNI-based method registration. + // Must be in the kNative state for calling native methods (JNI_OnLoad code). ScopedThreadStateChange tsc(self, Thread::kNative); + // First set up JniConstants, which is used by both the runtime's built-in native + // methods and libcore. JniConstants::init(env); - // First set up the native methods provided by the runtime itself. + // Then set up the native methods provided by the runtime itself. RegisterRuntimeNativeMethods(env); - // Now set up libcore, which is just a JNI library with a JNI_OnLoad. - // Most JNI libraries can just use System.loadLibrary, but you can't - // if you're the library that implements System.loadLibrary! + // Then set up libcore, which is just a regular JNI library with a regular JNI_OnLoad. + // Most JNI libraries can just use System.loadLibrary, but libcore can't because it's + // the library that implements System.loadLibrary! LoadJniLibrary(instance_->GetJavaVM(), "javacore"); } diff --git a/src/thread.cc b/src/thread.cc index 57bc09b156..232c1150ab 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -209,8 +209,9 @@ extern "C" int artCheckCastFromCode(const Class* a, const Class* b) { return 0; // Success } else { Thread::Current()->ThrowNewException("Ljava/lang/ClassCastException;", - "%s cannot be cast to %s", - PrettyClass(b).c_str(), PrettyClass(a).c_str()); + "%s cannot be cast to %s", + PrettyDescriptor(a->GetDescriptor()).c_str(), + PrettyDescriptor(b->GetDescriptor()).c_str()); return -1; // Failure } } |