Expand test 046 and move reflective class initialization later.
We have no reason to do this later; we're just being conservative. We
might want to revisit this in a future release so you only pay once,
when you cache your Field or Method instance.
Change-Id: Ib18fa75c0648561d3c5e1554cb3955ed57ab9314
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 43573b5..5c834f7 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -26,12 +26,14 @@
namespace art {
-static Class* DecodeInitializedClass(JNIEnv* env, jclass java_class) {
+static Class* DecodeClass(JNIEnv* env, jobject java_class) {
Class* c = Decode<Class*>(env, java_class);
DCHECK(c != NULL);
DCHECK(c->IsClass());
- bool initialized = Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true);
- return initialized ? c : NULL;
+ // TODO: we could EnsureInitialized here, rather than on every reflective get/set or invoke .
+ // For now, we conservatively preserve the old dalvik behavior. A quick "IsInitialized" check
+ // every time probably doesn't make much difference to reflection performance anyway.
+ return c;
}
// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
@@ -72,7 +74,7 @@
}
static jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) {
- Class* c = Decode<Class*>(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) {
return 0; // primitive, array and proxy classes don't have class definitions
}
@@ -106,7 +108,7 @@
}
static jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- Class* c = DecodeInitializedClass(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
if (c == NULL) {
return NULL;
}
@@ -130,7 +132,7 @@
}
static jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- Class* c = DecodeInitializedClass(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
if (c == NULL) {
return NULL;
}
@@ -172,7 +174,7 @@
}
static jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
- Class* c = DecodeInitializedClass(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
if (c == NULL) {
return NULL;
}
@@ -201,7 +203,7 @@
}
static jobject Class_getDex(JNIEnv* env, jobject javaClass) {
- Class* c = Decode<Class*>(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
DexCache* dex_cache = c->GetDexCache();
if (dex_cache == NULL) {
@@ -260,7 +262,7 @@
static jobject Class_getDeclaredConstructorOrMethod(JNIEnv* env, jclass javaClass, jstring javaName,
jobjectArray javaArgs) {
- Class* c = DecodeInitializedClass(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
if (c == NULL) {
return NULL;
}
@@ -281,7 +283,7 @@
}
static jobject Class_getDeclaredFieldNative(JNIEnv* env, jclass java_class, jobject jname) {
- Class* c = DecodeInitializedClass(env, java_class);
+ Class* c = DecodeClass(env, java_class);
if (c == NULL) {
return NULL;
}
@@ -309,20 +311,20 @@
static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- Class* c = Decode<Class*>(env, javaThis);
+ Class* c = DecodeClass(env, javaThis);
return AddLocalReference<jstring>(env, c->ComputeName());
}
static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- SynthesizedProxyClass* c = down_cast<SynthesizedProxyClass*>(Decode<Class*>(env, javaThis));
+ SynthesizedProxyClass* c = down_cast<SynthesizedProxyClass*>(DecodeClass(env, javaThis));
return AddLocalReference<jobjectArray>(env, c->GetInterfaces()->Clone());
}
static jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- Class* lhs = Decode<Class*>(env, javaLhs);
- Class* rhs = Decode<Class*>(env, javaRhs);
+ Class* lhs = DecodeClass(env, javaLhs);
+ Class* rhs = Decode<Class*>(env, javaRhs); // Can be null.
if (rhs == NULL) {
Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "class == null");
return JNI_FALSE;
@@ -331,7 +333,7 @@
}
static jboolean Class_isInstance(JNIEnv* env, jobject javaClass, jobject javaObject) {
- Class* c = Decode<Class*>(env, javaClass);
+ Class* c = DecodeClass(env, javaClass);
Object* o = Decode<Object*>(env, javaObject);
if (o == NULL) {
return JNI_FALSE;
@@ -370,7 +372,7 @@
static jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- Class* c = Decode<Class*>(env, javaThis);
+ Class* c = DecodeClass(env, javaThis);
if (c->IsPrimitive() || c->IsInterface() || c->IsArrayClass() || c->IsAbstract()) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/InstantiationException;",
"Class %s can not be instantiated", PrettyDescriptor(ClassHelper(c).GetDescriptor()).c_str());
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index 4eea533..70636d6 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -26,7 +26,9 @@
static bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- DCHECK(f->GetDeclaringClass()->IsInitialized());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true)) {
+ return false;
+ }
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
case Primitive::kPrimBoolean:
value.z = f->GetBoolean(o);
@@ -155,7 +157,9 @@
}
static void SetFieldValue(Object* o, Field* f, const JValue& new_value, bool allow_references) {
- DCHECK(f->GetDeclaringClass()->IsInitialized());
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true)) {
+ return;
+ }
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
case Primitive::kPrimBoolean:
f->SetBoolean(o, new_value.z);