Implement reflective method invocation.
Change-Id: Ib3af9d7e00bf226398610b5ac6efbfe3eb2d15e8
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 2031f30..b921281 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -133,6 +133,7 @@
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 be1de23..6daa27a 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -72,9 +72,10 @@
}
-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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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* 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 @@
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* 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 78be84b..083d641 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 @@
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 @@
enum ClassRoot {
kJavaLangClass,
kJavaLangObject,
+ kClassArrayClass,
kObjectArrayClass,
kJavaLangString,
kJavaLangReflectField,
@@ -345,7 +365,7 @@
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 9ca171b..69ad910 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -67,53 +67,43 @@
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);
+ 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 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();
+ 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;
+ for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+ Method* m = c->GetDirectMethod(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);
}
return NULL;
@@ -326,7 +316,6 @@
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 c6abe53..5584da3 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 @@
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 @@
}
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 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_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 @@
}
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 @@
} // 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 188614f..6ddb436 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 {
-
// 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 @@
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 e196c0c..96b3b34 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -111,6 +111,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
+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());
-}
-
-JValue InvokeWithVarArgs(ScopedJniThreadState& ts, jobject obj, jmethodID mid, va_list 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());
+ 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 @@
return NULL;
}
+ method->InitJavaFields();
+
return EncodeMethod(method);
}
@@ -606,6 +608,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 392ad24..e5bcb75 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -18,6 +18,7 @@
class ClassLoader;
class Field;
+union JValue;
class Libraries;
class Method;
class Thread;
@@ -58,6 +59,8 @@
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 4602af9..2a88e3d 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -76,7 +76,7 @@
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 12cd68d..813abce 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -321,6 +321,76 @@
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 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 ffc8caf..2ee90fc 100644
--- a/src/object.h
+++ b/src/object.h
@@ -916,8 +916,7 @@
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 @@
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 @@
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 @@
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 @@
}
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* 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 0000000..3edb9f7
--- /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 0000000..7256754
--- /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 751e8da..b1da77d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -440,17 +440,19 @@
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 57bc09b..232c115 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -209,8 +209,9 @@
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
}
}