diff options
Diffstat (limited to 'src/class_linker.cc')
-rw-r--r-- | src/class_linker.cc | 100 |
1 files changed, 61 insertions, 39 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc index 9fd8f0b249..53bcf7e93f 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -19,6 +19,7 @@ #include "oat_file.h" #include "object.h" #include "runtime.h" +#include "runtime_support.h" #include "ScopedLocalRef.h" #include "space.h" #include "stl_util.h" @@ -127,6 +128,7 @@ const char* ClassLinker::class_roots_descriptors_[] = { "Ljava/lang/reflect/Constructor;", "Ljava/lang/reflect/Field;", "Ljava/lang/reflect/Method;", + "Ljava/lang/reflect/Proxy;", "Ljava/lang/ClassLoader;", "Ldalvik/system/BaseDexClassLoader;", "Ldalvik/system/PathClassLoader;", @@ -420,6 +422,12 @@ void ClassLinker::Init(const std::string& boot_class_path) { Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;"); CHECK_EQ(java_lang_reflect_Method, Method_class); + // End of special init trickery, subsequent classes may be loaded via FindSystemClass + + // Create java.lang.reflect.Proxy root + Class* java_lang_reflect_Proxy = FindSystemClass("Ljava/lang/reflect/Proxy;"); + SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy); + // java.lang.ref classes need to be specially flagged, but otherwise are normal classes Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;"); SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference); @@ -1291,6 +1299,7 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) } const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const { + CHECK(dex_cache != NULL); MutexLock mu(lock_); for (size_t i = 0; i != dex_caches_.size(); ++i) { if (dex_caches_[i] == dex_cache) { @@ -1533,72 +1542,85 @@ void ClassLinker::VerifyClass(Class* klass) { } Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interfaces, - ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<Object>* throws) { + ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws) { Class* klass = AllocClass(GetClassRoot(kJavaLangClass), sizeof(ProxyClass)); CHECK(klass != NULL); klass->SetObjectSize(sizeof(Proxy)); - klass->SetDescriptor(intern_table_->InternStrong(name)); + const char* descriptor = DotToDescriptor(name->ToModifiedUtf8().c_str()).c_str();; + klass->SetDescriptor(intern_table_->InternStrong(descriptor)); klass->SetAccessFlags(kAccPublic | kAccFinal); klass->SetClassLoader(loader); - klass->SetStatus(Class::kStatusInitialized); - klass->SetInterfaces(interfaces); + klass->SetStatus(Class::kStatusInitialized); // no loading or initializing necessary + Class* proxy_class = GetClassRoot(kJavaLangReflectProxy); + klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy + klass->SetInterfaces(interfaces); // The interfaces are the array of interfaces specified + // Proxies have 1 direct method, the constructor klass->SetDirectMethods(AllocObjectArray<Method>(1)); klass->SetDirectMethod(0, CreateProxyConstructor(klass)); + // Create virtual method using specified prototypes 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))); } - + // Link the virtual methods, creating vtable and iftables if (!LinkMethods(klass)) { DCHECK(Thread::Current()->IsExceptionPending()); return NULL; } - return klass; } Method* ClassLinker::CreateProxyConstructor(Class* klass) { - Method* constructor = AllocMethod(); + // Create constructor for Proxy that must initialize h + Class* proxy_class = GetClassRoot(kJavaLangReflectProxy); + ObjectArray<Method>* proxy_direct_methods = proxy_class->GetDirectMethods(); + CHECK_EQ(proxy_direct_methods->GetLength(), 12); + Method* proxy_constructor = proxy_direct_methods->Get(2); + // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its + // code_ too) + Method* constructor = down_cast<Method*>(proxy_constructor->Clone()); + // Make this constructor public and fix the class to be our Proxy version + constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic); 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 - + // Sanity checks + CHECK(constructor->IsConstructor()); + CHECK(constructor->GetName()->Equals("<init>")); + CHECK(constructor->GetSignature()->Equals("(Ljava/lang/reflect/InvocationHandler;)V")); + DCHECK(constructor->IsPublic()); return constructor; } -Method* ClassLinker::CreateProxyMethod(Class* klass, Method* prototype, Object* throws) { - Method* method = AllocMethod(); +Method* ClassLinker::CreateProxyMethod(Class* klass, Method* prototype, + ObjectArray<Class>* throws) { + // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialise + // as necessary + Method* method = down_cast<Method*>(prototype->Clone()); + + // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to + // the intersection of throw exceptions as defined in Proxy 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->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal); 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); + // At runtime the method looks like a reference and argument saving method, clone the code + // related parameters from this method. + Method* refs_and_args = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs); + method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask()); + method->SetFpSpillMask(refs_and_args->GetFpSpillMask()); + method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes()); + method->SetCode(reinterpret_cast<void*>(art_proxy_invoke_handler)); + + // Basic sanity + DCHECK(method->GetName()->Equals(prototype->GetName())); + DCHECK(method->GetSignature()->Equals(prototype->GetSignature())); + DCHECK(method->GetShorty()->Equals(prototype->GetShorty())); + + // More complex sanity - via dex cache + CHECK_EQ(method->GetReturnType(), prototype->GetReturnType()); return method; } @@ -2092,7 +2114,7 @@ bool ClassLinker::LinkVirtualMethods(Class* klass) { size_t j = 0; for (; j < actual_count; ++j) { Method* super_method = vtable->Get(j); - if (local_method->HasSameNameAndDescriptor(super_method)) { + if (local_method->HasSameNameAndSignature(super_method)) { // Verify if (super_method->IsFinal()) { ThrowLinkageError("Method %s.%s overrides final method in class %s", @@ -2212,7 +2234,7 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { // matter which direction we go. We walk it backward anyway.) for (k = vtable->GetLength() - 1; k >= 0; --k) { Method* vtable_method = vtable->Get(k); - if (interface_method->HasSameNameAndDescriptor(vtable_method)) { + if (interface_method->HasSameNameAndSignature(vtable_method)) { if (!vtable_method->IsPublic()) { Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", "Implementation not public: %s", PrettyMethod(vtable_method).c_str()); @@ -2225,7 +2247,7 @@ bool ClassLinker::LinkInterfaceMethods(Class* klass) { if (k < 0) { Method* miranda_method = NULL; for (size_t mir = 0; mir < miranda_list.size(); mir++) { - if (miranda_list[mir]->HasSameNameAndDescriptor(interface_method)) { + if (miranda_list[mir]->HasSameNameAndSignature(interface_method)) { miranda_method = miranda_list[mir]; break; } |