summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Elliott Hughes <enh@google.com> 2012-03-21 16:56:56 -0700
committer Elliott Hughes <enh@google.com> 2012-03-21 16:57:43 -0700
commit2ed52c4419dd537c98cd7898bc8bdcf8826b8940 (patch)
treee90598e39df514d8a86cbb160288b4fd563eb1c1
parent051c9fc1de07bbc265af38cf60f061394163c68f (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.cc38
-rw-r--r--src/java_lang_Class.cc7
-rw-r--r--src/object.h6
-rw-r--r--src/object_utils.h29
-rw-r--r--test/044-proxy/expected.txt1
-rw-r--r--test/044-proxy/src/BasicTest.java2
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()));