diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2021-05-10 17:28:32 +0000 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2021-05-14 07:38:39 +0000 |
commit | ec06809b9fb7d4a0d2c3e46066bd37034130e53b (patch) | |
tree | c3a69b142e38d249a01ed425cde23caa78c1d36c /compiler | |
parent | 1651c6050d913fb38ebd293df9da6d189eb3851d (diff) |
Reland "Devirtualize to HInvokeStaticOrDirect."
This reverts commit 39d4df62d4e2606073d05cc363370db825ad7b9f.
Reason for revert: fix JIT-zygote issue.
Test: JIT zygote boots.
Change-Id: I895ad8e59e472fb662ca9bc5394c2fd9c6babc74
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/optimizing/inliner.cc | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 611c691ae1..9e1965d8aa 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1240,32 +1240,22 @@ void HInliner::MaybeRunReferenceTypePropagation(HInstruction* replacement, bool HInliner::TryDevirtualize(HInvoke* invoke_instruction, ArtMethod* method, HInvoke** replacement) { - DCHECK(!method->IsProxyMethod()); DCHECK(invoke_instruction != *replacement); - if (!invoke_instruction->IsInvokeInterface()) { - // TODO: Consider sharpening an invoke virtual once it is not dependent on the - // compiler driver. + if (!invoke_instruction->IsInvokeInterface() && !invoke_instruction->IsInvokeVirtual()) { return false; } - // Devirtualization by exact type uses a method in the vtable, so we should - // not see a default non-copied method. - DCHECK(!method->IsDefault() || method->IsCopied()); - // Turn an invoke-interface into an invoke-virtual. An invoke-virtual is always - // better than an invoke-interface because: - // 1) In the best case, the interface call has one more indirection (to fetch the IMT). - // 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. - - if (kIsDebugBuild && method->IsDefaultConflicting()) { - ReferenceTypeInfo receiver_type = invoke_instruction->InputAt(0)->GetReferenceTypeInfo(); - // Devirtualization by exact type uses a method in the vtable, - // so it's OK to change this invoke into a HInvokeVirtual. - ObjPtr<mirror::Class> receiver_class = receiver_type.GetTypeHandle().Get(); - CHECK(!receiver_class->IsInterface()); - PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - CHECK(method == receiver_class->GetVTableEntry(method->GetMethodIndex(), pointer_size)); - } + // Don't bother trying to call directly a default conflict method. It + // doesn't have a proper MethodReference, but also `GetCanonicalMethod` + // will return an actual default implementation. + if (method->IsDefaultConflicting()) { + return false; + } + DCHECK(!method->IsProxyMethod()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + PointerSize pointer_size = cl->GetImagePointerSize(); + // The sharpening logic assumes the caller isn't passing a copied method. + method = method->GetCanonicalMethod(pointer_size); uint32_t dex_method_index = FindMethodIndexIn( method, *invoke_instruction->GetMethodReference().dex_file, @@ -1273,19 +1263,40 @@ bool HInliner::TryDevirtualize(HInvoke* invoke_instruction, if (dex_method_index == dex::kDexNoIndex) { return false; } - HInvokeVirtual* new_invoke = new (graph_->GetAllocator()) HInvokeVirtual( + HInvokeStaticOrDirect::DispatchInfo dispatch_info = + HSharpening::SharpenLoadMethod(method, + /* has_method_id= */ true, + /* for_interface_call= */ false, + codegen_); + DCHECK_NE(dispatch_info.code_ptr_location, CodePtrLocation::kCallCriticalNative); + if (dispatch_info.method_load_kind == MethodLoadKind::kRuntimeCall) { + // If sharpening returns that we need to load the method at runtime, keep + // the virtual/interface call which will be faster. + // Also, the entrypoints for runtime calls do not handle devirtualized + // calls. + return false; + } + + HInvokeStaticOrDirect* new_invoke = new (graph_->GetAllocator()) HInvokeStaticOrDirect( graph_->GetAllocator(), invoke_instruction->GetNumberOfArguments(), invoke_instruction->GetType(), invoke_instruction->GetDexPc(), MethodReference(invoke_instruction->GetMethodReference().dex_file, dex_method_index), method, + dispatch_info, + kDirect, MethodReference(method->GetDexFile(), method->GetDexMethodIndex()), - method->GetMethodIndex()); + HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); HInputsRef inputs = invoke_instruction->GetInputs(); + DCHECK_EQ(inputs.size(), invoke_instruction->GetNumberOfArguments()); for (size_t index = 0; index != inputs.size(); ++index) { new_invoke->SetArgumentAt(index, inputs[index]); } + if (HInvokeStaticOrDirect::NeedsCurrentMethodInput(dispatch_info)) { + new_invoke->SetRawInputAt(new_invoke->GetCurrentMethodIndexUnchecked(), + graph_->GetCurrentMethod()); + } invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction); new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); if (invoke_instruction->GetType() == DataType::Type::kReference) { |