diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/driver/compiler_driver-inl.h | 50 | ||||
-rw-r--r-- | compiler/optimizing/builder.cc | 66 |
2 files changed, 86 insertions, 30 deletions
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 0eb3e439ac..0d65bc7405 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -305,11 +305,31 @@ inline int CompilerDriver::IsFastInvoke( MethodReference* target_method, const MethodReference* devirt_target, uintptr_t* direct_code, uintptr_t* direct_method) { // Don't try to fast-path if we don't understand the caller's class. + // Referrer_class is the class that this invoke is contained in. if (UNLIKELY(referrer_class == nullptr)) { return 0; } - mirror::Class* methods_class = resolved_method->GetDeclaringClass(); - if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_class, resolved_method, + StackHandleScope<2> hs(soa.Self()); + // Methods_class is the class refered to by the class_idx field of the methodId the method_idx is + // pointing to. + // For example in + // .class LABC; + // .super LDEF; + // .method hi()V + // ... + // invoke-super {p0}, LDEF;->hi()V + // ... + // .end method + // the referrer_class is 'ABC' and the methods_class is DEF. Note that the methods class is 'DEF' + // even if 'DEF' inherits the method from it's superclass. + Handle<mirror::Class> methods_class(hs.NewHandle(mUnit->GetClassLinker()->ResolveType( + *target_method->dex_file, + target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_, + dex_cache, + class_loader))); + DCHECK(methods_class.Get() != nullptr); + mirror::Class* methods_declaring_class = resolved_method->GetDeclaringClass(); + if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_declaring_class, resolved_method, dex_cache.Get(), target_method->dex_method_index))) { return 0; @@ -318,18 +338,31 @@ inline int CompilerDriver::IsFastInvoke( // overridden (ie is final). const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile(); bool can_sharpen_virtual_based_on_type = same_dex_file && - (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); + (*invoke_type == kVirtual) && (resolved_method->IsFinal() || + methods_declaring_class->IsFinal()); // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of // the super class. const size_t pointer_size = InstructionSetPointerSize(GetInstructionSet()); - bool can_sharpen_super_based_on_type = same_dex_file && (*invoke_type == kSuper) && - (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && - resolved_method->GetMethodIndex() < methods_class->GetVTableLength() && - (methods_class->GetVTableEntry( + // TODO We should be able to sharpen if we are going into the boot image as well. + bool can_sharpen_super_based_on_type = same_dex_file && + (*invoke_type == kSuper) && + !methods_class->IsInterface() && + (referrer_class != methods_declaring_class) && + referrer_class->IsSubClass(methods_declaring_class) && + resolved_method->GetMethodIndex() < methods_declaring_class->GetVTableLength() && + (methods_declaring_class->GetVTableEntry( resolved_method->GetMethodIndex(), pointer_size) == resolved_method) && resolved_method->IsInvokable(); + // TODO We should be able to sharpen if we are going into the boot image as well. + bool can_sharpen_interface_super_based_on_type = same_dex_file && + (*invoke_type == kSuper) && + methods_class->IsInterface() && + methods_class->IsAssignableFrom(referrer_class) && + resolved_method->IsInvokable(); - if (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type) { + if (can_sharpen_virtual_based_on_type || + can_sharpen_super_based_on_type || + can_sharpen_interface_super_based_on_type) { // Sharpen a virtual call into a direct call. The method_idx is into referrer's // dex cache, check that this resolved method is where we expect it. CHECK_EQ(target_method->dex_file, mUnit->GetDexFile()); @@ -363,7 +396,6 @@ inline int CompilerDriver::IsFastInvoke( *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader, nullptr, kVirtual); } else { - StackHandleScope<1> hs(soa.Self()); auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile( *devirt_target->dex_file, class_linker->GetOrCreateAllocatorForClassLoader(class_loader.Get())))); diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 37218139fb..c7430e7eb6 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -798,7 +798,7 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( @@ -833,31 +833,56 @@ ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_t } // We have to special case the invoke-super case, as ClassLinker::ResolveMethod does not. - // We need to look at the referrer's super class vtable. + // We need to look at the referrer's super class vtable. We need to do this to know if we need to + // make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of + // which require runtime handling. if (invoke_type == kSuper) { if (compiling_class.Get() == nullptr) { - // Invoking a super method requires knowing the actual super class. If we did not resolve - // the compiling method's declaring class (which only happens for ahead of time compilation), - // bail out. + // We could not determine the method's class we need to wait until runtime. DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; } - uint16_t vtable_index = resolved_method->GetMethodIndex(); - ArtMethod* actual_method = compiling_class->GetSuperClass()->GetVTableEntry( - vtable_index, class_linker->GetImagePointerSize()); - if (actual_method != resolved_method && - !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // TODO: The actual method could still be referenced in the current dex file, so we - // could try locating it. - // TODO: Remove the dex_file restriction. - return nullptr; - } - if (!actual_method->IsInvokable()) { - // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub - // could resolve the callee to the wrong method. + ArtMethod* current_method = graph_->GetArtMethod(); + DCHECK(current_method != nullptr); + Handle<mirror::Class> methods_class(hs.NewHandle( + dex_compilation_unit_->GetClassLinker()->ResolveReferencedClassOfMethod(Thread::Current(), + method_idx, + current_method))); + if (methods_class.Get() == nullptr) { + // Invoking a super method requires knowing the actual super class. If we did not resolve + // the compiling method's declaring class (which only happens for ahead of time + // compilation), bail out. + DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; + } else { + ArtMethod* actual_method; + if (methods_class->IsInterface()) { + actual_method = methods_class->FindVirtualMethodForInterfaceSuper( + resolved_method, class_linker->GetImagePointerSize()); + } else { + uint16_t vtable_index = resolved_method->GetMethodIndex(); + actual_method = compiling_class->GetSuperClass()->GetVTableEntry( + vtable_index, class_linker->GetImagePointerSize()); + } + if (actual_method != resolved_method && + !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { + // The back-end code generator relies on this check in order to ensure that it will not + // attempt to read the dex_cache with a dex_method_index that is not from the correct + // dex_file. If we didn't do this check then the dex_method_index will not be updated in the + // builder, which means that the code-generator (and compiler driver during sharpening and + // inliner, maybe) might invoke an incorrect method. + // TODO: The actual method could still be referenced in the current dex file, so we + // could try locating it. + // TODO: Remove the dex_file restriction. + return nullptr; + } + if (!actual_method->IsInvokable()) { + // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub + // could resolve the callee to the wrong method. + return nullptr; + } + resolved_method = actual_method; } - resolved_method = actual_method; } // Check for incompatible class changes. The class linker has a fast path for @@ -923,7 +948,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type); - if (resolved_method == nullptr) { + if (UNLIKELY(resolved_method == nullptr)) { MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, number_of_arguments, @@ -943,7 +968,6 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (invoke_type == kDirect || invoke_type == kStatic || invoke_type == kSuper) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. |