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++) {