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)) {
diff --git a/src/class_linker.h b/src/class_linker.h
index db30936..bb9f7f5 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -353,7 +353,7 @@
const Class* klass1,
const Class* klass2);
- bool LinkClass(SirtRef<Class>& klass);
+ bool LinkClass(SirtRef<Class>& klass, ObjectArray<Class>* interfaces);
bool LinkSuperClass(SirtRef<Class>& klass);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 736853a..0129dbd 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -597,16 +597,6 @@
};
};
-struct ProxyClassOffsets : public CheckOffsets<ProxyClass> {
- ProxyClassOffsets() : CheckOffsets<ProxyClass>(true, "Ljava/lang/reflect/Proxy;") {
- // alphabetical 32-bit
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ProxyClass, NextClassNameIndex_), "NextClassNameIndex"));
-
- // alphabetical 64-bit
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ProxyClass, serialVersionUID_), "serialVersionUID"));
- };
-};
-
// C++ fields must exactly match the fields in the Java classes. If this fails,
// reorder the fields in the C++ class. Managed class fields are ordered by
// ClassLinker::LinkFields.
@@ -628,7 +618,6 @@
EXPECT_TRUE(StringClassOffsets().Check());
EXPECT_TRUE(FieldClassOffsets().Check());
EXPECT_TRUE(MethodClassOffsets().Check());
- EXPECT_TRUE(ProxyClassOffsets().Check());
}
TEST_F(ClassLinkerTest, FindClassNonexistent) {
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index e36e5db..0a5a9ed 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -157,7 +157,6 @@
jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass javaClass, jboolean publicOnly) {
Class* c = Decode<Class*>(env, javaClass);
-
std::vector<Method*> methods;
for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
Method* m = c->GetVirtualMethod(i);
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index 90d718d..bfdcd39 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -30,6 +30,24 @@
return InvokeMethod(env, javaMethod, javaReceiver, javaArgs);
}
+jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
+ Method* proxy_method = Decode<Object*>(env, javaMethod)->AsMethod();
+ CHECK(proxy_method->GetDeclaringClass()->IsProxyClass());
+ SynthesizedProxyClass* proxy_class =
+ down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ return AddLocalReference<jobject>(env, declared_exceptions->Clone());
+}
+
jobject Method_getReturnTypeNative(JNIEnv* env, jobject javaMethod) {
Method* m = Decode<Object*>(env, javaMethod)->AsMethod();
MethodHelper mh(m);
@@ -38,6 +56,7 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
NATIVE_METHOD(Method, getReturnTypeNative, "()Ljava/lang/Class;")
};
diff --git a/src/object.h b/src/object.h
index 90a8322..8c6e660 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1315,6 +1315,8 @@
}
// Can this class access a member in the provided class with the provided member access flags?
+ // Note that access to the class isn't checked in case the declaring class is protected and the
+ // method has been exposed by a public sub-class
bool CanAccessMember(Class* access_to, uint32_t member_flags) const {
// Classes can access all of their own members
if (this == access_to) {
@@ -2368,12 +2370,14 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(InterfaceEntry);
};
-class MANAGED ProxyClass : public Class {
+class MANAGED SynthesizedProxyClass : public Class {
+ public:
+ ObjectArray<ObjectArray<Class> >* GetThrows() {
+ return throws_;
+ }
private:
- int32_t NextClassNameIndex_;
- int64_t serialVersionUID_;
- friend struct ProxyClassOffsets; // for verifying offset information
- DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyClass);
+ ObjectArray<ObjectArray<Class> >* throws_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass);
};
class MANAGED Proxy : public Object {
diff --git a/src/object_utils.h b/src/object_utils.h
index 0c93b43..42937cf 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -20,6 +20,7 @@
#include "class_linker.h"
#include "dex_cache.h"
#include "dex_file.h"
+#include "intern_table.h"
#include "object.h"
#include "runtime.h"
#include "UniquePtr.h"
@@ -90,8 +91,9 @@
return 0;
} else if (klass_->IsArrayClass()) {
return 2;
+ } else if (klass_->IsProxyClass()) {
+ return klass_->GetIfTable()->GetLength();
} else {
- CHECK(!klass_->IsProxyClass());
const DexFile::TypeList* interfaces = GetInterfaceTypeList();
if (interfaces == NULL) {
return 0;
@@ -116,6 +118,8 @@
DCHECK_EQ(1U, idx);
return GetClassLinker()->FindSystemClass("Ljava/io/Serializable;");
}
+ } else if (klass_->IsProxyClass()) {
+ return klass_->GetIfTable()->Get(idx)->GetInterface();
} else {
uint16_t type_idx = GetInterfaceTypeIdx(idx);
Class* interface = GetDexCache()->GetResolvedType(type_idx);
@@ -213,28 +217,60 @@
field_ = new_f;
}
const char* GetName() {
- const DexFile& dex_file = GetDexFile();
- return dex_file.GetFieldName(dex_file.GetFieldId(field_->GetDexFieldIndex()));
+ uint32_t field_index = field_->GetDexFieldIndex();
+ if (field_index != DexFile::kDexNoIndex) {
+ 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";
+ }
}
String* GetNameAsString() {
- const DexFile& dex_file = GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
- return GetClassLinker()->ResolveString(dex_file, field_id.name_idx_, GetDexCache());
+ uint32_t field_index = field_->GetDexFieldIndex();
+ if (field_index != DexFile::kDexNoIndex) {
+ 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");
+ }
}
Class* GetType() {
- const DexFile& dex_file = GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
- Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
- if (type == NULL) {
- type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
- CHECK(type != NULL || Thread::Current()->IsExceptionPending());
+ uint32_t field_index = field_->GetDexFieldIndex();
+ if (field_index != DexFile::kDexNoIndex) {
+ const DexFile& dex_file = GetDexFile();
+ const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index);
+ Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
+ if (type == NULL) {
+ type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
+ CHECK(type != NULL || Thread::Current()->IsExceptionPending());
+ }
+ 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 type;
}
const char* GetTypeDescriptor() {
- const DexFile& dex_file = GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_->GetDexFieldIndex());
- return dex_file.GetFieldTypeDescriptor(field_id);
+ uint32_t field_index = field_->GetDexFieldIndex();
+ if (field_index != DexFile::kDexNoIndex) {
+ 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;";
+ }
}
Primitive::Type GetTypeAsPrimitiveType() {
return Primitive::GetType(GetTypeDescriptor()[0]);
@@ -247,10 +283,20 @@
Primitive::Type type = GetTypeAsPrimitiveType();
return Primitive::FieldSize(type);
}
+
+ // The returned const char* is only guaranteed to be valid for the lifetime of the FieldHelper.
+ // If you need it longer, copy it into a std::string.
const char* GetDeclaringClassDescriptor() {
uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex();
- const DexFile& dex_file = GetDexFile();
- return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
+ if (type_idx != DexFile::kDexNoIndex16) {
+ const DexFile& dex_file = GetDexFile();
+ return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
+ } else {
+ // Most likely a proxy class
+ ClassHelper kh(field_->GetDeclaringClass());
+ declaring_class_descriptor_ = kh.GetDescriptor();
+ return declaring_class_descriptor_.c_str();
+ }
}
private:
@@ -284,6 +330,7 @@
DexCache* dex_cache_;
const DexFile* dex_file_;
const Field* field_;
+ std::string declaring_class_descriptor_;
DISALLOW_COPY_AND_ASSIGN(FieldHelper);
};
@@ -387,7 +434,7 @@
}
const char* GetDeclaringClassDescriptor() {
Class* klass = method_->GetDeclaringClass();
- CHECK(!klass->IsProxyClass());
+ DCHECK(!klass->IsProxyClass());
uint16_t type_idx = klass->GetDexTypeIndex();
const DexFile& dex_file = GetDexFile();
return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx));
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 1222626..4eaa760 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -1074,7 +1074,6 @@
CHECK(interface_method != NULL);
CHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
- LOG(INFO) << "Interface method is " << PrettyMethod(interface_method, true);
// Box arguments
cur_arg = 0; // reset stack location to read to start
// reset index, will index into param type array which doesn't include the receiver
@@ -1156,10 +1155,18 @@
if (!exception->IsCheckedException()) {
self->SetException(exception);
} else {
- // TODO: get the correct intersection of exceptions as passed to the class linker's create
- // proxy code.
- UNIMPLEMENTED(FATAL);
- ObjectArray<Class>* declared_exceptions = NULL; // proxy_mh.GetExceptionTypes();
+ SynthesizedProxyClass* proxy_class =
+ down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
Class* exception_class = exception->GetClass();
bool declares_exception = false;
for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {