Fix for test 044-proxy
Proxy implementation was incomplete following meta-data refactoring,
complete this change.
Change-Id: Ic0567bdef373dbae17031a30aabc779027173229
diff --git a/src/class_linker.cc b/src/class_linker.cc
index caf2876..a72cbbf 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1102,7 +1102,7 @@
CHECK(klass->IsLoaded());
// Link the class (if necessary)
CHECK(!klass->IsResolved());
- if (!LinkClass(klass)) {
+ if (!LinkClass(klass, NULL)) {
// Linking failed.
CHECK(self->IsExceptionPending());
klass->SetStatus(Class::kStatusError);
@@ -1201,7 +1201,7 @@
CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
klass->SetAccessFlags(access_flags);
klass->SetClassLoader(class_loader);
- DCHECK(klass->GetPrimitiveType() == Primitive::kPrimNot);
+ DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
klass->SetStatus(Class::kStatusIdx);
klass->SetDexTypeIndex(dex_class_def.class_idx_);
@@ -1704,20 +1704,34 @@
}
}
+static void CheckProxyConstructor(Method* constructor);
+static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype);
+
Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interfaces,
ClassLoader* loader, ObjectArray<Method>* methods,
ObjectArray<ObjectArray<Class> >* throws) {
- SirtRef<Class> klass(AllocClass(GetClassRoot(kJavaLangClass), sizeof(ProxyClass)));
+ SirtRef<Class> klass(AllocClass(GetClassRoot(kJavaLangClass), sizeof(SynthesizedProxyClass)));
CHECK(klass.get() != NULL);
+ DCHECK(klass->GetClass() != NULL);
klass->SetObjectSize(sizeof(Proxy));
klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
klass->SetClassLoader(loader);
+ DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
klass->SetName(name);
Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
klass->SetDexCache(proxy_class->GetDexCache());
- klass->SetDexTypeIndex(-1);
- klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy
- klass->SetStatus(Class::kStatusInitialized); // no loading or initializing necessary
+
+ klass->SetStatus(Class::kStatusIdx);
+
+ 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);
// Proxies have 1 direct method, the constructor
klass->SetDirectMethods(AllocObjectArray<Method>(1));
@@ -1730,11 +1744,40 @@
SirtRef<Method> prototype(methods->Get(i));
klass->SetVirtualMethod(i, CreateProxyMethod(klass, prototype));
}
- // Link the virtual methods, creating vtable and iftables
- if (!LinkMethods(klass, interfaces)) {
+
+ klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy
+ klass->SetStatus(Class::kStatusLoaded); // Class is now effectively in the loaded state
+ DCHECK(!Thread::Current()->IsExceptionPending());
+
+ // Link the fields and virtual methods, creating vtable and iftables
+ if (!LinkClass(klass, interfaces)) {
DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
}
+ sfield->SetObject(NULL, throws); // initialize throws field
+ klass->SetStatus(Class::kStatusInitialized);
+
+ // sanity checks
+#ifndef NDEBUG
+ bool debug = true;
+#else
+ bool debug = false;
+#endif
+ if (debug) {
+ CHECK(klass->GetIFields() == NULL);
+ CheckProxyConstructor(klass->GetDirectMethod(0));
+ for (size_t i = 0; i < num_virtual_methods; ++i) {
+ 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);
+
+ SynthesizedProxyClass* synth_proxy_class = down_cast<SynthesizedProxyClass*>(klass.get());
+ CHECK_EQ(synth_proxy_class->GetThrows(), throws);
+ }
return klass.get();
}
@@ -1757,13 +1800,15 @@
// Make this constructor public and fix the class to be our Proxy version
constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
constructor->SetDeclaringClass(klass.get());
- // Sanity checks
+ return constructor;
+}
+
+static void CheckProxyConstructor(Method* constructor) {
CHECK(constructor->IsConstructor());
MethodHelper mh(constructor);
CHECK_STREQ(mh.GetName(), "<init>");
CHECK(mh.GetSignature() == "(Ljava/lang/reflect/InvocationHandler;)V");
DCHECK(constructor->IsPublic());
- return constructor;
}
Method* ClassLinker::CreateProxyMethod(SirtRef<Class>& klass, SirtRef<Method>& prototype) {
@@ -1786,7 +1831,10 @@
method->SetFpSpillMask(refs_and_args->GetFpSpillMask());
method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes());
method->SetCode(reinterpret_cast<void*>(art_proxy_invoke_handler));
+ return method;
+}
+static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype) {
// Basic sanity
CHECK(!prototype->IsFinal());
CHECK(method->IsFinal());
@@ -1803,8 +1851,6 @@
// More complex sanity - via dex cache
CHECK_EQ(mh.GetReturnType(), method_return);
-
- return method;
}
bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
@@ -2111,12 +2157,12 @@
}
}
-bool ClassLinker::LinkClass(SirtRef<Class>& klass) {
+bool ClassLinker::LinkClass(SirtRef<Class>& klass, ObjectArray<Class>* interfaces) {
CHECK_EQ(Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
}
- if (!LinkMethods(klass, NULL)) {
+ if (!LinkMethods(klass, interfaces)) {
return false;
}
if (!LinkInstanceFields(klass)) {