diff options
| author | 2011-10-12 18:14:17 -0400 | |
|---|---|---|
| committer | 2011-10-13 15:21:24 -0400 | |
| commit | 95caa791e560da97363c0c0d22bfda4a7e7377c3 (patch) | |
| tree | 7cc1c2b15566009216a0c34f456e506e1c859e81 | |
| parent | ce46d3237c5117b1d2268c17e3639392416ff34d (diff) | |
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
| -rw-r--r-- | build/Android.common.mk | 1 | ||||
| -rw-r--r-- | src/class_linker.cc | 71 | ||||
| -rw-r--r-- | src/class_linker.h | 6 | ||||
| -rw-r--r-- | src/class_linker_test.cc | 21 | ||||
| -rw-r--r-- | src/java_lang_reflect_Proxy.cc | 48 | ||||
| -rw-r--r-- | src/jni_internal.cc | 1 | ||||
| -rw-r--r-- | src/oatexec.cc | 4 | ||||
| -rw-r--r-- | src/object.h | 20 | ||||
| -rw-r--r-- | src/runtime.cc | 2 |
9 files changed, 171 insertions, 3 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index 1968eb6bfa..7875ee97c0 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -123,6 +123,7 @@ LIBART_COMMON_SRC_FILES := \ 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 6ad6543115..99b5b0ea31 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -1513,6 +1513,77 @@ void ClassLinker::VerifyClass(Class* klass) { } } +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 e74494e134..37802ae67f 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -226,6 +226,9 @@ class ClassLinker { 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 @@ class ClassLinker { 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 19d51b59fb..34e02f02c9 100644 --- a/src/class_linker_test.cc +++ b/src/class_linker_test.cc @@ -573,6 +573,14 @@ struct PathClassLoaderOffsets : public CheckOffsets<PathClassLoader> { : 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 MethodClassOffsets : public CheckOffsets<MethodClass> { }; }; +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 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) { 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 0000000000..821bdd80cf --- /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 21b5918c11..9c7a63d3ba 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -95,6 +95,7 @@ template Object* Decode<Object*>(JNIEnv*, jobject); 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 f1d63c33ad..ad5b6d95d1 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 @@ static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) { 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 5bbdc6bce1..a4e9c7a475 100644 --- a/src/object.h +++ b/src/object.h @@ -949,6 +949,10 @@ class MANAGED Method : public AccessibleObject { 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 @@ class MANAGED InterfaceEntry : public ObjectArray<Object> { 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 552bff8992..946c4cf30b 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -511,7 +511,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { 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); |