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);