diff options
34 files changed, 170 insertions, 592 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index c902d289e9..e0abf197d5 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -277,39 +277,44 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, return; } uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - MethodReference target_method(&GetDexFile(), method_idx); - InvokeType invoke_type = kVirtual; - InvokeType original_invoke_type = invoke_type; - int vtable_idx; - uintptr_t direct_code; - uintptr_t direct_method; - // TODO: support devirtualization. - const bool kEnableDevirtualization = false; - bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, - false, kEnableDevirtualization, - &invoke_type, - &target_method, &vtable_idx, - &direct_code, &direct_method); - if (fast_path && original_invoke_type == invoke_type) { - if (vtable_idx >= 0 && IsUint<16>(vtable_idx)) { - VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) - << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")" - << " to " << Instruction::Name(new_opcode) - << " by replacing method index " << method_idx - << " by vtable index " << vtable_idx - << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " - << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true); - // We are modifying 4 consecutive bytes. - inst->SetOpcode(new_opcode); - // Replace method index by vtable index. - if (is_range) { - inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx)); - } else { - inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx)); - } - quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx)); - } + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader()))); + + ClassLinker* class_linker = unit_.GetClassLinker(); + ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>( + GetDexFile(), + method_idx, + unit_.GetDexCache(), + class_loader, + /* referrer */ nullptr, + kVirtual); + + if (UNLIKELY(resolved_method == nullptr)) { + // Clean up any exception left by type resolution. + soa.Self()->ClearException(); + return; + } + + uint32_t vtable_idx = resolved_method->GetMethodIndex(); + DCHECK(IsUint<16>(vtable_idx)); + VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) + << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")" + << " to " << Instruction::Name(new_opcode) + << " by replacing method index " << method_idx + << " by vtable index " << vtable_idx + << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method " + << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true); + // We are modifying 4 consecutive bytes. + inst->SetOpcode(new_opcode); + // Replace method index by vtable index. + if (is_range) { + inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx)); + } else { + inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx)); } + quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx)); } CompiledMethod* ArtCompileDEX( diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 3a260f5a80..4b913f4255 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -293,146 +293,6 @@ inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex( } } -inline int CompilerDriver::IsFastInvoke( - ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type, - 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; - } - 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; - } - // Sharpen a virtual call into a direct call when the target is known not to have been - // 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_declaring_class->IsFinal()); - // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of - // the super class. - const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet()); - // 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 || - 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()); - DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache( - soa.Self(), *mUnit->GetDexFile(), false)); - CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod( - target_method->dex_method_index, pointer_size), - resolved_method) << PrettyMethod(resolved_method); - int stats_flags = kFlagMethodResolved; - GetCodeAndMethodForDirectCall(/*out*/invoke_type, - kDirect, // Sharp type - false, // The dex cache is guaranteed to be available - referrer_class, resolved_method, - /*out*/&stats_flags, - target_method, - /*out*/direct_code, - /*out*/direct_method); - DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method); - if (*invoke_type == kDirect) { - stats_flags |= kFlagsMethodResolvedVirtualMadeDirect; - } - return stats_flags; - } - - if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) { - // Post-verification callback recorded a more precise invoke target based on its type info. - ArtMethod* called_method; - ClassLinker* class_linker = mUnit->GetClassLinker(); - if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) { - called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>( - *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader, - nullptr, kVirtual); - } else { - auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(*devirt_target->dex_file, - class_loader.Get()))); - called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>( - *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache, - class_loader, nullptr, kVirtual); - } - CHECK(called_method != nullptr); - CHECK(called_method->IsInvokable()); - int stats_flags = kFlagMethodResolved; - GetCodeAndMethodForDirectCall(/*out*/invoke_type, - kDirect, // Sharp type - true, // The dex cache may not be available - referrer_class, called_method, - /*out*/&stats_flags, - target_method, - /*out*/direct_code, - /*out*/direct_method); - DCHECK_NE(*invoke_type, kSuper); - if (*invoke_type == kDirect) { - stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization; - } - return stats_flags; - } - - if (UNLIKELY(*invoke_type == kSuper)) { - // Unsharpened super calls are suspicious so go slow-path. - return 0; - } - - // Sharpening failed so generate a regular resolved method dispatch. - int stats_flags = kFlagMethodResolved; - GetCodeAndMethodForDirectCall(/*out*/invoke_type, - *invoke_type, // Sharp type - false, // The dex cache is guaranteed to be available - referrer_class, resolved_method, - /*out*/&stats_flags, - target_method, - /*out*/direct_code, - /*out*/direct_method); - return stats_flags; -} - inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class, ArtMethod* resolved_method) { if (!resolved_method->IsStatic()) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index a149c07beb..adbf9fd0a7 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1654,12 +1654,8 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi } } -void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type, - bool no_guarantee_of_dex_cache_entry, - const mirror::Class* referrer_class, +void CompilerDriver::GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class, ArtMethod* method, - int* stats_flags, - MethodReference* target_method, uintptr_t* direct_code, uintptr_t* direct_method) { // For direct and static methods compute possible direct_code and direct_method values, ie @@ -1671,15 +1667,11 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType Runtime* const runtime = Runtime::Current(); gc::Heap* const heap = runtime->GetHeap(); auto* cl = runtime->GetClassLinker(); - const auto pointer_size = cl->GetImagePointerSize(); bool use_dex_cache = GetCompilerOptions().GetCompilePic(); // Off by default const bool compiling_boot = heap->IsCompilingBoot(); // TODO This is somewhat hacky. We should refactor all of this invoke codepath. const bool force_relocations = (compiling_boot || GetCompilerOptions().GetIncludePatchInformation()); - if (sharp_type != kStatic && sharp_type != kDirect) { - return; - } // TODO: support patching on all architectures. use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_); mirror::Class* declaring_class = method->GetDeclaringClass(); @@ -1687,14 +1679,12 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType if (!use_dex_cache) { if (!method_code_in_boot) { use_dex_cache = true; - } else { - bool has_clinit_trampoline = - method->IsStatic() && !declaring_class->IsInitialized(); - if (has_clinit_trampoline && declaring_class != referrer_class) { - // Ensure we run the clinit trampoline unless we are invoking a static method in the same - // class. - use_dex_cache = true; - } + } else if (method->IsStatic() && + declaring_class != referrer_class && + !declaring_class->IsInitialized()) { + // Ensure we run the clinit trampoline unless we are invoking a static method in the same + // class. + use_dex_cache = true; } } if (runtime->UseJitCompilation()) { @@ -1705,9 +1695,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType use_dex_cache = true; } } - if (method_code_in_boot) { - *stats_flags |= kFlagDirectCallToBoot | kFlagDirectMethodToBoot; - } + if (!use_dex_cache && force_relocations) { bool is_in_image; if (IsBootImage()) { @@ -1724,39 +1712,8 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType use_dex_cache = true; } } - // The method is defined not within this dex file. We need a dex cache slot within the current - // dex file or direct pointers. - bool must_use_direct_pointers = false; - mirror::DexCache* dex_cache = declaring_class->GetDexCache(); - if (target_method->dex_file == dex_cache->GetDexFile() && - !(runtime->UseJitCompilation() && dex_cache->GetResolvedMethod( - method->GetDexMethodIndex(), pointer_size) == nullptr)) { - target_method->dex_method_index = method->GetDexMethodIndex(); - } else { - if (no_guarantee_of_dex_cache_entry) { - // See if the method is also declared in this dex cache. - uint32_t dex_method_idx = method->FindDexMethodIndexInOtherDexFile( - *target_method->dex_file, target_method->dex_method_index); - if (dex_method_idx != DexFile::kDexNoIndex) { - target_method->dex_method_index = dex_method_idx; - } else { - if (force_relocations && !use_dex_cache) { - target_method->dex_method_index = method->GetDexMethodIndex(); - target_method->dex_file = dex_cache->GetDexFile(); - } - must_use_direct_pointers = true; - } - } - } - if (use_dex_cache) { - if (must_use_direct_pointers) { - // Fail. Test above showed the only safe dispatch was via the dex cache, however, the direct - // pointers are required as the dex cache lacks an appropriate entry. - VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); - } else { - *type = sharp_type; - } - } else { + + if (!use_dex_cache) { bool method_in_image = false; const std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces(); for (gc::space::ImageSpace* image_space : image_spaces) { @@ -1772,85 +1729,13 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType // the method and its code are / will be. We don't sharpen to interpreter bridge since we // check IsQuickToInterpreterBridge above. CHECK(!method->IsAbstract()); - *type = sharp_type; *direct_method = force_relocations ? -1 : reinterpret_cast<uintptr_t>(method); *direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method); - target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); - target_method->dex_method_index = method->GetDexMethodIndex(); - } else if (!must_use_direct_pointers) { - // Set the code and rely on the dex cache for the method. - *type = sharp_type; - if (force_relocations) { - *direct_code = -1; - target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); - target_method->dex_method_index = method->GetDexMethodIndex(); - } else { - *direct_code = compiler_->GetEntryPointOf(method); - } } else { - // Direct pointers were required but none were available. - VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); - } - } -} - -bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - bool update_stats, bool enable_devirtualization, - InvokeType* invoke_type, MethodReference* target_method, - int* vtable_idx, uintptr_t* direct_code, - uintptr_t* direct_method) { - InvokeType orig_invoke_type = *invoke_type; - int stats_flags = 0; - ScopedObjectAccess soa(Thread::Current()); - // Try to resolve the method and compiling method's class. - StackHandleScope<2> hs(soa.Self()); - Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache()); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()))); - uint32_t method_idx = target_method->dex_method_index; - ArtMethod* resolved_method = ResolveMethod( - soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type); - auto h_referrer_class = hs.NewHandle(resolved_method != nullptr ? - ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr); - bool result = false; - if (resolved_method != nullptr) { - *vtable_idx = GetResolvedMethodVTableIndex(resolved_method, orig_invoke_type); - - if (enable_devirtualization && mUnit->GetVerifiedMethod() != nullptr) { - const MethodReference* devirt_target = mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc); - - stats_flags = IsFastInvoke( - soa, dex_cache, class_loader, mUnit, h_referrer_class.Get(), resolved_method, - invoke_type, target_method, devirt_target, direct_code, direct_method); - result = stats_flags != 0; - } else { - // Devirtualization not enabled. Inline IsFastInvoke(), dropping the devirtualization parts. - if (UNLIKELY(h_referrer_class.Get() == nullptr) || - UNLIKELY(!h_referrer_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(), - resolved_method, dex_cache.Get(), - target_method->dex_method_index)) || - *invoke_type == kSuper) { - // Slow path. (Without devirtualization, all super calls go slow path as well.) - } else { - // Sharpening failed so generate a regular resolved method dispatch. - stats_flags = kFlagMethodResolved; - GetCodeAndMethodForDirectCall( - invoke_type, *invoke_type, false, h_referrer_class.Get(), resolved_method, &stats_flags, - target_method, direct_code, direct_method); - result = true; - } + // Set the code and rely on the dex cache for the method. + *direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method); } } - if (!result) { - // Conservative defaults. - *vtable_idx = -1; - *direct_code = 0u; - *direct_method = 0u; - } - if (update_stats) { - ProcessedInvoke(orig_invoke_type, stats_flags); - } - return result; } const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file, diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ee21efa854..1f4c3aca34 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -328,16 +328,6 @@ class CompilerDriver { ArtMethod* resolved_method, InvokeType type) REQUIRES_SHARED(Locks::mutator_lock_); - // Can we fast-path an INVOKE? If no, returns 0. If yes, returns a non-zero opaque flags value - // for ProcessedInvoke() and computes the necessary lowering info. - int IsFastInvoke( - ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, - mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type, - MethodReference* target_method, const MethodReference* devirt_target, - uintptr_t* direct_code, uintptr_t* direct_method) - REQUIRES_SHARED(Locks::mutator_lock_); - // Is method's class initialized for an invoke? // For static invokes to determine whether we need to consider potential call to <clinit>(). // For non-static invokes, assuming a non-null reference, the class is always initialized. @@ -371,14 +361,6 @@ class CompilerDriver { REQUIRES_SHARED(Locks::mutator_lock_); - // Can we fastpath a interface, super class or virtual method call? Computes method's vtable - // index. - bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - bool update_stats, bool enable_devirtualization, - InvokeType* type, MethodReference* target_method, int* vtable_idx, - uintptr_t* direct_code, uintptr_t* direct_method) - REQUIRES(!Locks::mutator_lock_); - const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const; bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc); @@ -538,14 +520,10 @@ class CompilerDriver { public: // TODO make private or eliminate. // Compute constant code and method pointers when possible. - void GetCodeAndMethodForDirectCall(/*out*/InvokeType* type, - InvokeType sharp_type, - bool no_guarantee_of_dex_cache_entry, - const mirror::Class* referrer_class, + void GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class, ArtMethod* method, - /*out*/int* stats_flags, - MethodReference* target_method, - uintptr_t* direct_code, uintptr_t* direct_method) + /* out */ uintptr_t* direct_code, + /* out */ uintptr_t* direct_method) REQUIRES_SHARED(Locks::mutator_lock_); private: diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index cf633df496..0f8cdbb19b 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -346,7 +346,7 @@ void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invok // Initialize to anything to silent compiler warnings. QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck; - switch (invoke->GetOriginalInvokeType()) { + switch (invoke->GetInvokeType()) { case kStatic: entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck; break; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index c0c798d862..85002045a3 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -515,7 +515,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { // otherwise return a fall-back info that should be used instead. virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) = 0; + HInvokeStaticOrDirect* invoke) = 0; // Generate a call to a static or direct method. virtual void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) = 0; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index a052873afd..6be458ce26 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -6672,7 +6672,7 @@ void CodeGeneratorARM::GenerateReadBarrierForRootSlow(HInstruction* instruction, HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) { + HInvokeStaticOrDirect* invoke) { HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info; // We disable pc-relative load when there is an irreducible loop, as the optimization // is incompatible with it. @@ -6686,7 +6686,7 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOr if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) { const DexFile& outer_dex_file = GetGraph()->GetDexFile(); - if (&outer_dex_file != target_method.dex_file) { + if (&outer_dex_file != invoke->GetTargetMethod().dex_file) { // Calls across dex files are more likely to exceed the available BL range, // so use absolute patch with fixup if available and kCallArtMethod otherwise. HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 424a1a1455..6416d40f7f 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -454,7 +454,7 @@ class CodeGeneratorARM : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index a29e9f3e80..7160607687 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3544,7 +3544,7 @@ static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM64* codege HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method ATTRIBUTE_UNUSED) { + HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { // On ARM64 we support all dispatch types. return desired_dispatch_info; } @@ -3588,7 +3588,7 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok break; case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { // Add ADRP with its PC-relative DexCache access patch. - const DexFile& dex_file = *invoke->GetTargetMethod().dex_file; + const DexFile& dex_file = invoke->GetDexFile(); uint32_t element_offset = invoke->GetDexCacheArrayOffset(); vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset); { diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index f1dc7eecb5..a15224578d 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -522,7 +522,7 @@ class CodeGeneratorARM64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index b06c84dd58..226f109bec 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -432,7 +432,7 @@ HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind( // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) { + HInvokeStaticOrDirect* invoke) { TODO_VIXL32(FATAL); return desired_dispatch_info; } diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index d0c2c85b6a..7b7118cb3e 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -363,7 +363,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 2211ea3846..f560207d3e 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -4327,7 +4327,7 @@ Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticO HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method ATTRIBUTE_UNUSED) { + HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info; // We disable PC-relative load when there is an irreducible loop, as the optimization // is incompatible with it. diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index 553a7e6674..f943978b3b 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -395,7 +395,7 @@ class CodeGeneratorMIPS : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 5039fad708..a5e23511a4 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -2972,7 +2972,7 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method ATTRIBUTE_UNUSED) { + HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { switch (desired_dispatch_info.method_load_kind) { case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup: case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 2dd409a224..690eccb7d8 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -343,7 +343,7 @@ class CodeGeneratorMIPS64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index cc9fe832f1..47dfb2e921 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -4217,7 +4217,7 @@ void CodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) { HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method ATTRIBUTE_UNUSED) { + HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info; // We disable pc-relative load when there is an irreducible loop, as the optimization @@ -4297,7 +4297,7 @@ Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticO __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset)); // Bind a new fixup label at the end of the "movl" insn. uint32_t offset = invoke->GetDexCacheArrayOffset(); - __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset)); + __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset)); break; } case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: { diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 5866e65d88..1ae9af3b94 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -402,7 +402,7 @@ class CodeGeneratorX86 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; // Generate a call to a static or direct method. Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 1d87bf6198..59c0ca47f8 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -733,7 +733,7 @@ inline Condition X86_64FPCondition(IfCondition cond) { HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method ATTRIBUTE_UNUSED) { + HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { switch (desired_dispatch_info.code_ptr_location) { case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect: @@ -775,7 +775,7 @@ Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStat Address::Absolute(kDummy32BitOffset, /* no_rip */ false)); // Bind a new fixup label at the end of the "movl" insn. uint32_t offset = invoke->GetDexCacheArrayOffset(); - __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset)); + __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset)); break; } case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: { diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 7108676b8e..594f05157b 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -399,7 +399,7 @@ class CodeGeneratorX86_64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - MethodReference target_method) OVERRIDE; + HInvokeStaticOrDirect* invoke) OVERRIDE; Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp); void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc index 6ad9b07f1a..7010171c80 100644 --- a/compiler/optimizing/dex_cache_array_fixups_arm.cc +++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc @@ -82,12 +82,10 @@ class DexCacheArrayFixupsVisitor : public HGraphVisitor { // we need to add the dex cache arrays base as the special input. if (invoke->HasPcRelativeDexCache() && !IsCallFreeIntrinsic<IntrinsicLocationsBuilderARM>(invoke, codegen_)) { - // Initialize base for target method dex file if needed. - MethodReference target_method = invoke->GetTargetMethod(); - HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file); + HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile()); // Update the element offset in base. - DexCacheArraysLayout layout(kArmPointerSize, target_method.dex_file); - base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index)); + DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFile()); + base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex())); // Add the special argument base to the method. DCHECK(!invoke->HasCurrentMethodInput()); invoke->AddSpecialInput(base); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index b3d5341de0..912ee29cdb 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -447,7 +447,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE { VisitInvoke(invoke); - StartAttributeStream("invoke_type") << invoke->GetOriginalInvokeType(); + StartAttributeStream("invoke_type") << invoke->GetInvokeType(); } void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index ce53134235..f21dc0e7e4 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -263,42 +263,24 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { return false; // Don't bother to move further if we know the method is unresolved. } - uint32_t method_index = invoke_instruction->GetDexMethodIndex(); ScopedObjectAccess soa(Thread::Current()); + uint32_t method_index = invoke_instruction->GetDexMethodIndex(); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, caller_dex_file); - ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); // We can query the dex cache directly. The verifier has populated it already. - ArtMethod* resolved_method; + ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod(); ArtMethod* actual_method = nullptr; - if (invoke_instruction->IsInvokeStaticOrDirect()) { - if (invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit()) { - VLOG(compiler) << "Not inlining a String.<init> method"; - return false; - } - MethodReference ref = invoke_instruction->AsInvokeStaticOrDirect()->GetTargetMethod(); - mirror::DexCache* const dex_cache = IsSameDexFile(caller_dex_file, *ref.dex_file) - ? caller_compilation_unit_.GetDexCache().Get() - : class_linker->FindDexCache(soa.Self(), *ref.dex_file); - resolved_method = dex_cache->GetResolvedMethod( - ref.dex_method_index, class_linker->GetImagePointerSize()); - // actual_method == resolved_method for direct or static calls. - actual_method = resolved_method; - } else { - resolved_method = caller_compilation_unit_.GetDexCache().Get()->GetResolvedMethod( - method_index, class_linker->GetImagePointerSize()); - if (resolved_method != nullptr) { - // Check if we can statically find the method. - actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method); - } - } - if (resolved_method == nullptr) { - // TODO: Can this still happen? - // Method cannot be resolved if it is in another dex file we do not have access to. - VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, caller_dex_file); + DCHECK(invoke_instruction->IsInvokeStaticOrDirect()); + DCHECK(invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit()); + VLOG(compiler) << "Not inlining a String.<init> method"; return false; + } else if (invoke_instruction->IsInvokeStaticOrDirect()) { + actual_method = resolved_method; + } else { + // Check if we can statically find the method. + actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method); } if (actual_method != nullptr) { @@ -763,9 +745,9 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* metho // 2) We will not go to the conflict trampoline with an invoke-virtual. // TODO: Consider sharpening once it is not dependent on the compiler driver. const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); - uint32_t method_index = FindMethodIndexIn( + uint32_t dex_method_index = FindMethodIndexIn( method, caller_dex_file, invoke_instruction->GetDexMethodIndex()); - if (method_index == DexFile::kDexNoIndex) { + if (dex_method_index == DexFile::kDexNoIndex) { return false; } HInvokeVirtual* new_invoke = new (graph_->GetArena()) HInvokeVirtual( @@ -773,7 +755,8 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* metho invoke_instruction->GetNumberOfArguments(), invoke_instruction->GetType(), invoke_instruction->GetDexPc(), - method_index, + dex_method_index, + method, method->GetMethodIndex()); HInputsRef inputs = invoke_instruction->GetInputs(); for (size_t index = 0; index != inputs.size(); ++index) { @@ -1122,7 +1105,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } } - InvokeType invoke_type = invoke_instruction->GetOriginalInvokeType(); + InvokeType invoke_type = invoke_instruction->GetInvokeType(); if (invoke_type == kInterface) { // We have statically resolved the dispatch. To please the class linker // at runtime, we change this call as if it was a virtual call. diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index d7e4c53df0..5a6a212cc9 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -785,8 +785,6 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, number_of_arguments++; } - MethodReference target_method(dex_file_, method_idx); - // Special handling for string init. int32_t string_init_offset = 0; bool is_string_init = compiler_driver_->IsStringInit(method_idx, @@ -800,16 +798,17 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, dchecked_integral_cast<uint64_t>(string_init_offset), 0U }; + MethodReference target_method(dex_file_, method_idx); HInvoke* invoke = new (arena_) HInvokeStaticOrDirect( arena_, number_of_arguments - 1, Primitive::kPrimNot /*return_type */, dex_pc, method_idx, - target_method, + nullptr, dispatch_info, invoke_type, - kStatic /* optimized_invoke_type */, + target_method, HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit); return HandleStringInit(invoke, number_of_vreg_arguments, @@ -853,10 +852,9 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, dex_pc, resolved_method, method_idx, &clinit_check_requirement); } else if (invoke_type == kSuper) { if (IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // Update the target method to the one resolved. Note that this may be a no-op if + // Update the method index to the one resolved. Note that this may be a no-op if // we resolved to the method referenced by the instruction. method_idx = resolved_method->GetDexMethodIndex(); - target_method = MethodReference(dex_file_, method_idx); } } @@ -866,15 +864,17 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, 0u, 0U }; + MethodReference target_method(resolved_method->GetDexFile(), + resolved_method->GetDexMethodIndex()); invoke = new (arena_) HInvokeStaticOrDirect(arena_, number_of_arguments, return_type, dex_pc, method_idx, - target_method, + resolved_method, dispatch_info, invoke_type, - invoke_type, + target_method, clinit_check_requirement); } else if (invoke_type == kVirtual) { ScopedObjectAccess soa(Thread::Current()); // Needed for the method index @@ -883,15 +883,17 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, return_type, dex_pc, method_idx, + resolved_method, resolved_method->GetMethodIndex()); } else { DCHECK_EQ(invoke_type, kInterface); - ScopedObjectAccess soa(Thread::Current()); // Needed for the method index + ScopedObjectAccess soa(Thread::Current()); // Needed for the IMT index. invoke = new (arena_) HInvokeInterface(arena_, number_of_arguments, return_type, dex_pc, method_idx, + resolved_method, resolved_method->GetImtIndex()); } @@ -1103,7 +1105,7 @@ bool HInstructionBuilder::HandleInvoke(HInvoke* invoke, size_t start_index = 0; size_t argument_index = 0; - if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call. + if (invoke->GetInvokeType() != InvokeType::kStatic) { // Instance call. uint32_t obj_reg = is_range ? register_index : args[0]; HInstruction* arg = is_unresolved ? LoadLocal(obj_reg, Primitive::kPrimNot) diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index b7878880d2..ff829af4c2 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -1657,7 +1657,7 @@ void InstructionSimplifierVisitor::SimplifyRotate(HInvoke* invoke, bool is_left, Primitive::Type type) { DCHECK(invoke->IsInvokeStaticOrDirect()); - DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic); + DCHECK_EQ(invoke->GetInvokeType(), InvokeType::kStatic); HInstruction* value = invoke->InputAt(0); HInstruction* distance = invoke->InputAt(1); // Replace the invoke with an HRor. diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 418d59c6cb..4d4bbcf616 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -532,9 +532,7 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile // inline. If the precise type is known, however, the instruction will be sharpened to an // InvokeStaticOrDirect. InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic); - InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ? - invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() : - invoke->IsInvokeVirtual() ? kVirtual : kSuper; + InvokeType invoke_type = invoke->GetInvokeType(); switch (intrinsic_type) { case kStatic: return (invoke_type == kStatic); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 6d207765e3..57ae555caa 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3742,8 +3742,8 @@ class HInvoke : public HInstruction { uint32_t GetDexMethodIndex() const { return dex_method_index_; } const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); } - InvokeType GetOriginalInvokeType() const { - return GetPackedField<OriginalInvokeTypeField>(); + InvokeType GetInvokeType() const { + return GetPackedField<InvokeTypeField>(); } Intrinsics GetIntrinsic() const { @@ -3777,21 +3777,22 @@ class HInvoke : public HInstruction { bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; } + ArtMethod* GetResolvedMethod() const { return resolved_method_; } + DECLARE_ABSTRACT_INSTRUCTION(Invoke); protected: - static constexpr size_t kFieldOriginalInvokeType = kNumberOfGenericPackedBits; - static constexpr size_t kFieldOriginalInvokeTypeSize = + static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits; + static constexpr size_t kFieldInvokeTypeSize = MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType)); static constexpr size_t kFieldReturnType = - kFieldOriginalInvokeType + kFieldOriginalInvokeTypeSize; + kFieldInvokeType + kFieldInvokeTypeSize; static constexpr size_t kFieldReturnTypeSize = MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast)); static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize; static constexpr size_t kNumberOfInvokePackedBits = kFlagCanThrow + 1; static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - using OriginalInvokeTypeField = - BitField<InvokeType, kFieldOriginalInvokeType, kFieldOriginalInvokeTypeSize>; + using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>; using ReturnTypeField = BitField<Primitive::Type, kFieldReturnType, kFieldReturnTypeSize>; HInvoke(ArenaAllocator* arena, @@ -3800,23 +3801,26 @@ class HInvoke : public HInstruction { Primitive::Type return_type, uint32_t dex_pc, uint32_t dex_method_index, - InvokeType original_invoke_type) + ArtMethod* resolved_method, + InvokeType invoke_type) : HInstruction( SideEffects::AllExceptGCDependency(), dex_pc), // Assume write/read on all fields/arrays. number_of_arguments_(number_of_arguments), + resolved_method_(resolved_method), inputs_(number_of_arguments + number_of_other_inputs, arena->Adapter(kArenaAllocInvokeInputs)), dex_method_index_(dex_method_index), intrinsic_(Intrinsics::kNone), intrinsic_optimizations_(0) { SetPackedField<ReturnTypeField>(return_type); - SetPackedField<OriginalInvokeTypeField>(original_invoke_type); + SetPackedField<InvokeTypeField>(invoke_type); SetPackedFlag<kFlagCanThrow>(true); } void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); } uint32_t number_of_arguments_; + ArtMethod* const resolved_method_; ArenaVector<HUserRecord<HInstruction*>> inputs_; const uint32_t dex_method_index_; Intrinsics intrinsic_; @@ -3842,6 +3846,7 @@ class HInvokeUnresolved FINAL : public HInvoke { return_type, dex_pc, dex_method_index, + nullptr, invoke_type) { } @@ -3935,10 +3940,10 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { Primitive::Type return_type, uint32_t dex_pc, uint32_t method_index, - MethodReference target_method, + ArtMethod* resolved_method, DispatchInfo dispatch_info, - InvokeType original_invoke_type, - InvokeType optimized_invoke_type, + InvokeType invoke_type, + MethodReference target_method, ClinitCheckRequirement clinit_check_requirement) : HInvoke(arena, number_of_arguments, @@ -3950,10 +3955,10 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { return_type, dex_pc, method_index, - original_invoke_type), + resolved_method, + invoke_type), target_method_(target_method), dispatch_info_(dispatch_info) { - SetPackedField<OptimizedInvokeTypeField>(optimized_invoke_type); SetPackedField<ClinitCheckRequirementField>(clinit_check_requirement); } @@ -4017,14 +4022,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); } bool HasSpecialInput() const { return GetNumberOfArguments() != InputCount(); } - InvokeType GetOptimizedInvokeType() const { - return GetPackedField<OptimizedInvokeTypeField>(); - } - - void SetOptimizedInvokeType(InvokeType invoke_type) { - SetPackedField<OptimizedInvokeTypeField>(invoke_type); - } - MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; } CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; } bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; } @@ -4046,8 +4043,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { } } bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; } - MethodReference GetTargetMethod() const { return target_method_; } - void SetTargetMethod(MethodReference method) { target_method_ = method; } int32_t GetStringInitOffset() const { DCHECK(IsStringInit()); @@ -4075,7 +4070,11 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { // Is this instruction a call to a static method? bool IsStatic() const { - return GetOriginalInvokeType() == kStatic; + return GetInvokeType() == kStatic; + } + + MethodReference GetTargetMethod() const { + return target_method_; } // Remove the HClinitCheck or the replacement HLoadClass (set as last input by @@ -4117,26 +4116,18 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { void RemoveInputAt(size_t index); private: - static constexpr size_t kFieldOptimizedInvokeType = kNumberOfInvokePackedBits; - static constexpr size_t kFieldOptimizedInvokeTypeSize = - MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType)); - static constexpr size_t kFieldClinitCheckRequirement = - kFieldOptimizedInvokeType + kFieldOptimizedInvokeTypeSize; + static constexpr size_t kFieldClinitCheckRequirement = kNumberOfInvokePackedBits; static constexpr size_t kFieldClinitCheckRequirementSize = MinimumBitsToStore(static_cast<size_t>(ClinitCheckRequirement::kLast)); static constexpr size_t kNumberOfInvokeStaticOrDirectPackedBits = kFieldClinitCheckRequirement + kFieldClinitCheckRequirementSize; static_assert(kNumberOfInvokeStaticOrDirectPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); - using OptimizedInvokeTypeField = - BitField<InvokeType, kFieldOptimizedInvokeType, kFieldOptimizedInvokeTypeSize>; using ClinitCheckRequirementField = BitField<ClinitCheckRequirement, kFieldClinitCheckRequirement, kFieldClinitCheckRequirementSize>; - // The target method may refer to different dex file or method index than the original - // invoke. This happens for sharpened calls and for calls where a method was redeclared - // in derived class to increase visibility. + // Cached values of the resolved method, to avoid needing the mutator lock. MethodReference target_method_; DispatchInfo dispatch_info_; @@ -4152,8 +4143,16 @@ class HInvokeVirtual FINAL : public HInvoke { Primitive::Type return_type, uint32_t dex_pc, uint32_t dex_method_index, + ArtMethod* resolved_method, uint32_t vtable_index) - : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kVirtual), + : HInvoke(arena, + number_of_arguments, + 0u, + return_type, + dex_pc, + dex_method_index, + resolved_method, + kVirtual), vtable_index_(vtable_index) {} bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { @@ -4166,6 +4165,7 @@ class HInvokeVirtual FINAL : public HInvoke { DECLARE_INSTRUCTION(InvokeVirtual); private: + // Cached value of the resolved method, to avoid needing the mutator lock. const uint32_t vtable_index_; DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual); @@ -4178,8 +4178,16 @@ class HInvokeInterface FINAL : public HInvoke { Primitive::Type return_type, uint32_t dex_pc, uint32_t dex_method_index, + ArtMethod* resolved_method, uint32_t imt_index) - : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kInterface), + : HInvoke(arena, + number_of_arguments, + 0u, + return_type, + dex_pc, + dex_method_index, + resolved_method, + kInterface), imt_index_(imt_index) {} bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE { @@ -4193,6 +4201,7 @@ class HInvokeInterface FINAL : public HInvoke { DECLARE_INSTRUCTION(InvokeInterface); private: + // Cached value of the resolved method, to avoid needing the mutator lock. const uint32_t imt_index_; DISALLOW_COPY_AND_ASSIGN(HInvokeInterface); diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index e64c005410..abec55f25c 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -61,44 +61,28 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { return; } - // TODO: Avoid CompilerDriver. - InvokeType original_invoke_type = invoke->GetOriginalInvokeType(); - InvokeType optimized_invoke_type = original_invoke_type; - MethodReference target_method(&graph_->GetDexFile(), invoke->GetDexMethodIndex()); - int vtable_idx; - uintptr_t direct_code, direct_method; - bool success = compiler_driver_->ComputeInvokeInfo( - &compilation_unit_, - invoke->GetDexPc(), - false /* update_stats: already updated in builder */, - true /* enable_devirtualization */, - &optimized_invoke_type, - &target_method, - &vtable_idx, - &direct_code, - &direct_method); - if (!success) { - // TODO: try using kDexCachePcRelative. It's always a valid method load - // kind as long as it's supported by the codegen - return; - } - invoke->SetOptimizedInvokeType(optimized_invoke_type); - invoke->SetTargetMethod(target_method); + HGraph* outer_graph = codegen_->GetGraph(); + ArtMethod* compiling_method = graph_->GetArtMethod(); HInvokeStaticOrDirect::MethodLoadKind method_load_kind; HInvokeStaticOrDirect::CodePtrLocation code_ptr_location; uint64_t method_load_data = 0u; uint64_t direct_code_ptr = 0u; - HGraph* outer_graph = codegen_->GetGraph(); - if (target_method.dex_file == &outer_graph->GetDexFile() && - target_method.dex_method_index == outer_graph->GetMethodIdx()) { + if (invoke->GetResolvedMethod() == outer_graph->GetArtMethod()) { + DCHECK(outer_graph->GetArtMethod() != nullptr); method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive; code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf; } else { - bool use_pc_relative_instructions = - ((direct_method == 0u || direct_code == static_cast<uintptr_t>(-1))) && - ContainsElement(compiler_driver_->GetDexFilesForOatFile(), target_method.dex_file); + uintptr_t direct_code, direct_method; + { + ScopedObjectAccess soa(Thread::Current()); + compiler_driver_->GetCodeAndMethodForDirectCall( + (compiling_method == nullptr) ? nullptr : compiling_method->GetDeclaringClass(), + invoke->GetResolvedMethod(), + &direct_code, + &direct_method); + } if (direct_method != 0u) { // Should we use a direct pointer to the method? // Note: For JIT, kDirectAddressWithFixup doesn't make sense at all and while // kDirectAddress would be fine for image methods, we don't support it at the moment. @@ -110,13 +94,12 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup; } } else { // Use dex cache. - DCHECK_EQ(target_method.dex_file, &graph_->GetDexFile()); - if (use_pc_relative_instructions) { // Can we use PC-relative access to the dex cache arrays? - DCHECK(!Runtime::Current()->UseJitCompilation()); + if (!Runtime::Current()->UseJitCompilation()) { + // Use PC-relative access to the dex cache arrays. method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative; DexCacheArraysLayout layout(GetInstructionSetPointerSize(codegen_->GetInstructionSet()), &graph_->GetDexFile()); - method_load_data = layout.MethodOffset(target_method.dex_method_index); + method_load_data = layout.MethodOffset(invoke->GetDexMethodIndex()); } else { // We must go through the ArtMethod's pointer to resolved methods. method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod; } @@ -125,10 +108,11 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // Note: For JIT, kCallPCRelative and kCallDirectWithFixup don't make sense at all and // while kCallDirect would be fine for image methods, we don't support it at the moment. DCHECK(!Runtime::Current()->UseJitCompilation()); + const DexFile* dex_file_of_callee = invoke->GetTargetMethod().dex_file; if (direct_code != static_cast<uintptr_t>(-1)) { // Is the code pointer known now? code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirect; direct_code_ptr = direct_code; - } else if (use_pc_relative_instructions) { + } else if (ContainsElement(compiler_driver_->GetDexFilesForOatFile(), dex_file_of_callee)) { // Use PC-relative calls for invokes within a multi-dex oat file. code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative; } else { // The direct pointer will be known at link time. @@ -151,8 +135,7 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { method_load_kind, code_ptr_location, method_load_data, direct_code_ptr }; HInvokeStaticOrDirect::DispatchInfo dispatch_info = - codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, - invoke->GetTargetMethod()); + codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke); invoke->SetDispatchInfo(dispatch_info); } diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build deleted file mode 100644 index 92ddfc9a58..0000000000 --- a/test/555-checker-regression-x86const/build +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 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. - -# Stop if something fails. -set -e - -# We can't use src-ex testing infrastructure because src and src-ex are compiled -# with javac independetely and can't share code (without reflection). - -mkdir classes -${JAVAC} -d classes `find src -name '*.java'` - -mkdir classes-ex -mv classes/UnresolvedClass.class classes-ex - -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes-ex.jill.jar -C classes-ex . - - ${JACK} --import classes.jill.jar --output-dex . - zip $TEST_NAME.jar classes.dex - ${JACK} --import classes-ex.jill.jar --output-dex . - zip ${TEST_NAME}-ex.jar classes.dex -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes - zip $TEST_NAME.jar classes.dex - ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex - zip ${TEST_NAME}-ex.jar classes.dex - fi -fi diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/555-checker-regression-x86const/expected.txt +++ /dev/null diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt deleted file mode 100644 index c4037fa88f..0000000000 --- a/test/555-checker-regression-x86const/info.txt +++ /dev/null @@ -1,2 +0,0 @@ -Check that X86 FP constant-area handling handles intrinsics with CurrentMethod -on the call. diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run deleted file mode 100644 index 63fdb8c749..0000000000 --- a/test/555-checker-regression-x86const/run +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 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. - -# Use secondary switch to add secondary dex file to class path. -exec ${RUN} "${@}" --secondary diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java deleted file mode 100644 index 914cfde74f..0000000000 --- a/test/555-checker-regression-x86const/src/Main.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -public class Main extends UnresolvedClass { - - /// CHECK-START: float Main.callAbs(float) register (before) - /// CHECK: <<CurrentMethod:[ij]\d+>> CurrentMethod - /// CHECK: <<ParamValue:f\d+>> ParameterValue - /// CHECK: InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs - static public float callAbs(float f) { - // An intrinsic invoke in a method that has unresolved references will still - // have a CurrentMethod as an argument. The X86 pc_relative_fixups_x86 pass - // must be able to handle Math.abs invokes that have a CurrentMethod, as both - // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask) - // expect to be in the 'SpecialInputIndex' input index. - return Math.abs(f); - } - - static public void main(String[] args) { - expectEquals(callAbs(-6.5f), 6.5f); - } - - public static void expectEquals(float expected, float result) { - if (expected != result) { - throw new Error("Expected: " + expected + ", found: " + result); - } - } -} diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java deleted file mode 100644 index e98bdbf8fb..0000000000 --- a/test/555-checker-regression-x86const/src/Unresolved.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2016 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. - */ - -class UnresolvedClass { -} |