diff options
author | 2012-03-21 16:56:56 -0700 | |
---|---|---|
committer | 2012-03-21 16:57:43 -0700 | |
commit | 2ed52c4419dd537c98cd7898bc8bdcf8826b8940 (patch) | |
tree | e90598e39df514d8a86cbb160288b4fd563eb1c1 | |
parent | 051c9fc1de07bbc265af38cf60f061394163c68f (diff) |
Stash the directly-implemented interfaces in Proxy so we can implement Class.getInterfaces.
Also extend test 044 to spot this (found by a libcore test).
Change-Id: I50019db49c549f045d94173c3ed9ae81f05ef858
-rw-r--r-- | src/class_linker.cc | 38 | ||||
-rw-r--r-- | src/java_lang_Class.cc | 7 | ||||
-rw-r--r-- | src/object.h | 6 | ||||
-rw-r--r-- | src/object_utils.h | 29 | ||||
-rw-r--r-- | test/044-proxy/expected.txt | 1 | ||||
-rw-r--r-- | test/044-proxy/src/BasicTest.java | 2 |
6 files changed, 53 insertions, 30 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index c65cf7d3bd..38ce30ac1d 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -2166,13 +2166,21 @@ Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interface klass->SetDexTypeIndex(DexFile::kDexNoIndex16); - // Create static field that holds throws, instance fields are inherited - klass->SetSFields(AllocObjectArray<Field>(1)); - SirtRef<Field> sfield(AllocField()); - klass->SetStaticField(0, sfield.get()); - sfield->SetDexFieldIndex(-1); - sfield->SetDeclaringClass(klass.get()); - sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); + // Instance fields are inherited, but we add a couple of static fields... + klass->SetSFields(AllocObjectArray<Field>(2)); + // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by + // our proxy, so Class.getInterfaces doesn't return the flattened set. + SirtRef<Field> interfaces_sfield(AllocField()); + klass->SetStaticField(0, interfaces_sfield.get()); + interfaces_sfield->SetDexFieldIndex(0); + interfaces_sfield->SetDeclaringClass(klass.get()); + interfaces_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); + // 2. Create a static field 'throws' that holds exceptions thrown by our methods. + SirtRef<Field> throws_sfield(AllocField()); + klass->SetStaticField(1, throws_sfield.get()); + throws_sfield->SetDexFieldIndex(1); + throws_sfield->SetDeclaringClass(klass.get()); + throws_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // Proxies have 1 direct method, the constructor klass->SetDirectMethods(AllocObjectArray<Method>(1)); @@ -2195,7 +2203,8 @@ Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interface klass->SetStatus(Class::kStatusError); return NULL; } - sfield->SetObject(NULL, throws); // initialize throws field + interfaces_sfield->SetObject(NULL, interfaces); + throws_sfield->SetObject(NULL, throws); klass->SetStatus(Class::kStatusInitialized); // sanity checks @@ -2211,12 +2220,17 @@ Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interface SirtRef<Method> prototype(methods->Get(i)); CheckProxyMethod(klass->GetVirtualMethod(i), prototype); } - std::string throws_field_name("java.lang.Class[][] "); - throws_field_name += name->ToModifiedUtf8(); - throws_field_name += ".throws"; - CHECK(PrettyField(klass->GetStaticField(0)) == throws_field_name); + + std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces", + name->ToModifiedUtf8().c_str())); + CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name); + + std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws", + name->ToModifiedUtf8().c_str())); + CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name); SynthesizedProxyClass* synth_proxy_class = down_cast<SynthesizedProxyClass*>(klass.get()); + CHECK_EQ(synth_proxy_class->GetInterfaces(), interfaces); CHECK_EQ(synth_proxy_class->GetThrows(), throws); } return klass.get(); diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc index 3dce55994f..567a067088 100644 --- a/src/java_lang_Class.cc +++ b/src/java_lang_Class.cc @@ -288,6 +288,12 @@ static jstring Class_getNameNative(JNIEnv* env, jobject 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)); + 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); @@ -410,6 +416,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, getDeclaredMethods, "(Z)[Ljava/lang/reflect/Method;"), NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"), NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), + NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"), NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"), NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"), NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"), diff --git a/src/object.h b/src/object.h index 93493fd5b5..fee4dd0b5f 100644 --- a/src/object.h +++ b/src/object.h @@ -2508,10 +2508,16 @@ class MANAGED InterfaceEntry : public ObjectArray<Object> { class MANAGED SynthesizedProxyClass : public Class { public: + ObjectArray<Class>* GetInterfaces() { + return interfaces_; + } + ObjectArray<ObjectArray<Class> >* GetThrows() { return throws_; } + private: + ObjectArray<Class>* interfaces_; ObjectArray<ObjectArray<Class> >* throws_; DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass); }; diff --git a/src/object_utils.h b/src/object_utils.h index b9d8a24a01..cbad7b08e8 100644 --- a/src/object_utils.h +++ b/src/object_utils.h @@ -249,32 +249,28 @@ class FieldHelper { } const char* GetName() { uint32_t field_index = field_->GetDexFieldIndex(); - if (field_index != DexFile::kDexNoIndex) { + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); return dex_file.GetFieldName(dex_file.GetFieldId(field_index)); } else { - // Proxy classes have a single static field called "throws" - CHECK(field_->GetDeclaringClass()->IsProxyClass()); DCHECK(field_->IsStatic()); - return "throws"; + DCHECK_LT(field_index, 2U); + return field_index == 0 ? "interfaces" : "throws"; } } String* GetNameAsString() { uint32_t field_index = field_->GetDexFieldIndex(); - if (field_index != DexFile::kDexNoIndex) { + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); return GetClassLinker()->ResolveString(dex_file, field_id.name_idx_, GetDexCache()); } else { - // Proxy classes have a single static field called "throws" - CHECK(field_->GetDeclaringClass()->IsProxyClass()); - DCHECK(field_->IsStatic()); - return Runtime::Current()->GetInternTable()->InternStrong("throws"); + return Runtime::Current()->GetInternTable()->InternStrong(GetName()); } } Class* GetType() { uint32_t field_index = field_->GetDexFieldIndex(); - if (field_index != DexFile::kDexNoIndex) { + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_); @@ -284,23 +280,20 @@ class FieldHelper { } return type; } else { - // Proxy classes have a single static field called "throws" whose type is Class[][] - CHECK(field_->GetDeclaringClass()->IsProxyClass()); - DCHECK(field_->IsStatic()); - return GetClassLinker()->FindSystemClass("[[Ljava/lang/Class;"); + return GetClassLinker()->FindSystemClass(GetTypeDescriptor()); } } const char* GetTypeDescriptor() { uint32_t field_index = field_->GetDexFieldIndex(); - if (field_index != DexFile::kDexNoIndex) { + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); return dex_file.GetFieldTypeDescriptor(field_id); } else { - // Proxy classes have a single static field called "throws" whose type is Class[][] - CHECK(field_->GetDeclaringClass()->IsProxyClass()); DCHECK(field_->IsStatic()); - return "[[Ljava/lang/Class;"; + DCHECK_LT(field_index, 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; + return field_index == 0 ? "[Ljava/lang/Class;" : "[[Ljava/lang/Class;"; } } Primitive::Type GetTypeAsPrimitiveType() { diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt index ddda58b161..578fd971f3 100644 --- a/test/044-proxy/expected.txt +++ b/test/044-proxy/expected.txt @@ -49,6 +49,7 @@ Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedExcepti (no args) Got expected ie +Proxy interfaces: [interface Quads, interface Colors] Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()] Decl annos: [] Param annos (0) : [] diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java index 8f4d19ed7e..46aa3feea2 100644 --- a/test/044-proxy/src/BasicTest.java +++ b/test/044-proxy/src/BasicTest.java @@ -80,6 +80,8 @@ public class BasicTest { return o1.getReturnType().getName().compareTo(o2.getReturnType().getName()); } }); + System.out.println("Proxy interfaces: " + + Arrays.deepToString(proxy.getClass().getInterfaces())); System.out.println("Proxy methods: " + Arrays.deepToString(methods)); Method meth = methods[methods.length -1]; System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations())); |