Create proxy class, constructor, and methods.

This code compiles but has not been exercised. I still
need to wire in the code blocks and return types.

Change-Id: I1796103d3bc4fc3c863f95bdca4cfb9765d4b3b7
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 1968eb6..7875ee9 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -123,6 +123,7 @@
 	src/java_lang_reflect_Constructor.cc \
 	src/java_lang_reflect_Field.cc \
 	src/java_lang_reflect_Method.cc \
+	src/java_lang_reflect_Proxy.cc \
 	src/java_util_concurrent_atomic_AtomicLong.cc \
 	src/jni_compiler.cc \
 	src/jni_internal.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 6ad6543..99b5b0e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1513,6 +1513,77 @@
   }
 }
 
+Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interfaces,
+    ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<Object>* throws) {
+  Class* klass = AllocClass(GetClassRoot(kJavaLangClass), sizeof(ProxyClass));
+  CHECK(klass != NULL);
+  klass->SetObjectSize(sizeof(Proxy));
+  klass->SetDescriptor(intern_table_->InternStrong(name));
+  klass->SetAccessFlags(kAccPublic | kAccFinal);
+  klass->SetClassLoader(loader);
+  klass->SetStatus(Class::kStatusInitialized);
+  klass->SetInterfaces(interfaces);
+
+  klass->SetDirectMethods(AllocObjectArray<Method>(1));
+  klass->SetDirectMethod(0, CreateProxyConstructor(klass));
+
+  size_t num_virtual_methods = methods->GetLength();
+  klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
+  for (size_t i = 0; i < num_virtual_methods; ++i) {
+    Method* prototype = methods->Get(i);
+    klass->SetVirtualMethod(i, CreateProxyMethod(klass, prototype, throws->Get(i)));
+  }
+
+  if (!LinkMethods(klass)) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return NULL;
+  }
+
+  return klass;
+}
+
+Method* ClassLinker::CreateProxyConstructor(Class* klass) {
+  Method* constructor = AllocMethod();
+  constructor->SetDeclaringClass(klass);
+  constructor->SetName(intern_table_->InternStrong("<init>"));
+  constructor->SetSignature(intern_table_->InternStrong("(Ljava/lang/reflect/InvocationHandler;)V"));
+  constructor->SetShorty(intern_table_->InternStrong("LV"));
+  constructor->SetAccessFlags(kAccPublic | kAccNative);
+
+  // TODO: return type
+  // TODO: code block
+
+  return constructor;
+}
+
+Method* ClassLinker::CreateProxyMethod(Class* klass, Method* prototype, Object* throws) {
+  Method* method = AllocMethod();
+  method->SetDeclaringClass(klass);
+  method->SetName(const_cast<String*>(prototype->GetName()));
+  method->SetSignature(const_cast<String*>(prototype->GetSignature()));
+  method->SetShorty(prototype->GetShorty());
+  method->SetAccessFlags(prototype->GetAccessFlags());
+  method->SetExceptionTypes(throws);
+
+  // TODO: return type
+  // method->SetReturnTypeIdx(dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_);
+
+  // TODO: code block
+  // method->SetCodeItemOffset(src.code_off_);
+  // method->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
+  // method->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
+  // method->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
+  // method->SetDexCacheResolvedFields(klass->GetDexCache()->GetResolvedFields());
+  // method->SetDexCacheCodeAndDirectMethods(klass->GetDexCache()->GetCodeAndDirectMethods());
+  // method->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
+  // method->SetNumRegisters(code_item->registers_size_);
+  // method->SetNumIns(code_item->ins_size_);
+  // method->SetNumOuts(code_item->outs_size_);
+  // LinkCode(method, oat_class.get(), method_index);
+
+  return method;
+}
+
 bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
   CHECK(klass->IsResolved() || klass->IsErroneous())
       << PrettyClass(klass) << " is " << klass->GetStatus();
diff --git a/src/class_linker.h b/src/class_linker.h
index e74494e..37802ae 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -226,6 +226,9 @@
 
   void VerifyClass(Class* klass);
 
+  Class* CreateProxyClass(String* name, ObjectArray<Class>* interfaces, ClassLoader* loader,
+      ObjectArray<Method>* methods, ObjectArray<Object>* throws);
+
  private:
   ClassLinker(InternTable*);
 
@@ -343,6 +346,9 @@
     return dex_caches_;
   }
 
+  Method* CreateProxyConstructor(Class* klass);
+  Method* CreateProxyMethod(Class* klass, Method* prototype, Object* throws);
+
   // lock to protect ClassLinker state
   mutable Mutex lock_;
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 19d51b5..34e02f0 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -573,6 +573,14 @@
     : CheckOffsets<PathClassLoader>(false, "Ldalvik/system/PathClassLoader;") {};
 };
 
+struct ProxyOffsets : public CheckOffsets<Proxy> {
+  ProxyOffsets() : CheckOffsets<Proxy>(false, "Ljava/lang/reflect/Proxy;") {
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Proxy, h_), "h"));
+  };
+};
+
 struct ClassClassOffsets : public CheckOffsets<ClassClass> {
   ClassClassOffsets() : CheckOffsets<ClassClass>(true, "Ljava/lang/Class;") {
 
@@ -626,6 +634,17 @@
   };
 };
 
+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.
@@ -642,11 +661,13 @@
   EXPECT_TRUE(ClassLoaderOffsets().Check());
   EXPECT_TRUE(BaseDexClassLoaderOffsets().Check());
   EXPECT_TRUE(PathClassLoaderOffsets().Check());
+  EXPECT_TRUE(ProxyOffsets().Check());
 
   EXPECT_TRUE(ClassClassOffsets().Check());
   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_reflect_Proxy.cc b/src/java_lang_reflect_Proxy.cc
new file mode 100644
index 0000000..821bdd8
--- /dev/null
+++ b/src/java_lang_reflect_Proxy.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "object.h"
+#include "class_linker.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring javaName, jobjectArray javaInterfaces, jobject javaLoader, jobjectArray javaMethods, jobjectArray javaThrows) {
+  String* name = Decode<String*>(env, javaName);
+  ObjectArray<Class>* interfaces = Decode<ObjectArray<Class>*>(env, javaInterfaces);
+  ClassLoader* loader = Decode<ClassLoader*>(env, javaLoader);
+  ObjectArray<Method>* methods = Decode<ObjectArray<Method>*>(env, javaMethods);
+  ObjectArray<Object>* throws = Decode<ObjectArray<Object>*>(env, javaThrows);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Class* result = class_linker->CreateProxyClass(name, interfaces, loader, methods, throws);
+  return AddLocalReference<jclass>(env, result);
+}
+
+JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+};
+
+}  // namespace
+
+void register_java_lang_reflect_Proxy(JNIEnv* env) {
+  jniRegisterNativeMethods(env, "java/lang/reflect/Proxy", gMethods, NELEM(gMethods));
+}
+
+}  // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 21b5918..9c7a63d 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -95,6 +95,7 @@
 template ObjectArray<Class>* Decode<ObjectArray<Class>*>(JNIEnv*, jobject);
 template ObjectArray<Object>* Decode<ObjectArray<Object>*>(JNIEnv*, jobject);
 template ObjectArray<StackTraceElement>* Decode<ObjectArray<StackTraceElement>*>(JNIEnv*, jobject);
+template ObjectArray<Method>* Decode<ObjectArray<Method>*>(JNIEnv*, jobject);
 template String* Decode<String*>(JNIEnv*, jobject);
 template Throwable* Decode<Throwable*>(JNIEnv*, jobject);
 
diff --git a/src/oatexec.cc b/src/oatexec.cc
index f1d63c3..ad5b6d9 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -12,6 +12,7 @@
 #include "jni.h"
 #include "logging.h"
 #include "toStringArray.h"
+#include "object.h"
 
 // Determine whether or not the specified method is public.
 static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
@@ -27,14 +28,13 @@
     fprintf(stderr, "Failed to find class Method\n");
     return false;
   }
-  static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
   jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
   if (get_modifiers == NULL) {
     fprintf(stderr, "Failed to find reflect.Method.getModifiers\n");
     return false;
   }
   int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
-  if ((modifiers & PUBLIC) == 0) {
+  if ((modifiers & art::kAccPublic) == 0) {
     return false;
   }
   return true;
diff --git a/src/object.h b/src/object.h
index 5bbdc6b..a4e9c7a 100644
--- a/src/object.h
+++ b/src/object.h
@@ -949,6 +949,10 @@
     SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), fp_spill_mask, false);
   }
 
+  void SetExceptionTypes(Object* exception_types) {
+    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), exception_types, false);
+  }
+
   ObjectArray<Class>* GetJavaParameterTypes() const {
     return GetFieldObject<ObjectArray<Class>*>(
         OFFSET_OF_OBJECT_MEMBER(Method, java_parameter_types_), false);
@@ -2767,6 +2771,22 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(InterfaceEntry);
 };
 
+class MANAGED ProxyClass : public Class {
+ private:
+  int32_t NextClassNameIndex_;
+  int64_t serialVersionUID_;
+  friend struct ProxyClassOffsets;  // for verifying offset information
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyClass);
+};
+
+class MANAGED Proxy : public Object {
+ private:
+  Object* h_;
+
+  friend struct ProxyOffsets;  // for verifying offset information
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Proxy);
+};
+
 }  // namespace art
 
 #endif  // ART_SRC_OBJECT_H_
diff --git a/src/runtime.cc b/src/runtime.cc
index 552bff8..946c4cf 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -511,7 +511,7 @@
   REGISTER(register_java_lang_reflect_Constructor);
   REGISTER(register_java_lang_reflect_Field);
   REGISTER(register_java_lang_reflect_Method);
-  //REGISTER(register_java_lang_reflect_Proxy);
+  REGISTER(register_java_lang_reflect_Proxy);
   REGISTER(register_java_util_concurrent_atomic_AtomicLong);
   REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmServer);
   //REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmVmInternal);