Revert "Inline and optimize interface calls."
Went ahead too quickly.
This reverts commit d9faceaa8da92f4a56c2907de949081bd42faf79.
Change-Id: I1610deaf89b38037cf2786d135a59c48b10ced0c
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 8ee04dd..c67b2d5 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -750,35 +750,7 @@
bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
HInstruction* return_replacement = nullptr;
if (!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
- if (invoke_instruction->IsInvokeInterface()) {
- // 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.
- HInvokeVirtual* new_invoke = new (graph_->GetArena()) HInvokeVirtual(
- graph_->GetArena(),
- invoke_instruction->GetNumberOfArguments(),
- invoke_instruction->GetType(),
- invoke_instruction->GetDexPc(),
- invoke_instruction->GetDexMethodIndex(),
- method->GetMethodIndex());
- HInputsRef inputs = invoke_instruction->GetInputs();
- size_t index = 0;
- for (HInstruction* instr : inputs) {
- new_invoke->SetArgumentAt(index++, instr);
- }
- invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
- new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
- if (invoke_instruction->GetType() == Primitive::kPrimNot) {
- new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
- }
- return_replacement = new_invoke;
- } else {
- // TODO: Consider sharpening an invoke virtual once it is not dependent on the
- // compiler driver.
- return false;
- }
+ return false;
}
if (return_replacement != nullptr) {
invoke_instruction->ReplaceWith(return_replacement);
@@ -1267,6 +1239,14 @@
return false;
}
+ if (current->IsInvokeInterface()) {
+ // Disable inlining of interface calls. The cost in case of entering the
+ // resolution conflict is currently too high.
+ VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+ << " could not be inlined because it has an interface call.";
+ return false;
+ }
+
if (!same_dex_file && current->NeedsEnvironment()) {
VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
<< " could not be inlined because " << current->DebugName()
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 923ea1a..03771aa 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2141,7 +2141,11 @@
StackHandleScope<1> hs(self);
Handle<mirror::Class> cls(hs.NewHandle(this_object->GetClass()));
- ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
+ // The optimizing compiler currently does not inline methods that have an interface
+ // invocation. We use the outer method directly to avoid fetching a stack map, which is
+ // more expensive.
+ ArtMethod* caller_method = QuickArgumentVisitor::GetOuterMethod(sp);
+ DCHECK_EQ(caller_method, QuickArgumentVisitor::GetCallingMethod(sp));
// Fetch the dex_method_idx of the target interface method from the caller.
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index 95ac1ee..6fc12f1 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -103,8 +103,10 @@
static boolean doThrow = false;
static void $noinline$staticMethod() {
- // Try defeating inlining.
- if (doThrow) { throw new Error(); }
+ if (doThrow) {
+ // Try defeating inlining.
+ throw new Error();
+ }
}
}
@@ -179,8 +181,10 @@
static boolean doThrow = false;
static void $noinline$staticMethod() {
+ if (doThrow) {
// Try defeating inlining.
- if (doThrow) { throw new Error(); }
+ throw new Error();
+ }
}
}
@@ -241,8 +245,10 @@
static boolean doThrow = false;
static void $noinline$staticMethod() {
+ if (doThrow) {
// Try defeating inlining.
- if (doThrow) { throw new Error(); }
+ throw new Error();
+ }
}
static {
@@ -308,7 +314,7 @@
static void constClassAndInvokeStatic(Iterable<?> it) {
$opt$inline$ignoreClass(ClassWithClinit7.class);
- ClassWithClinit7.$noinline$someStaticMethod(it);
+ ClassWithClinit7.someStaticMethod(it);
}
static void $opt$inline$ignoreClass(Class<?> c) {
@@ -319,10 +325,10 @@
System.out.println("Main$ClassWithClinit7's static initializer");
}
- static void $noinline$someStaticMethod(Iterable<?> it) {
+ // Note: not inlined from constClassAndInvokeStatic() but fully inlined from main().
+ static void someStaticMethod(Iterable<?> it) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
}
}
@@ -339,7 +345,7 @@
static void sgetAndInvokeStatic(Iterable<?> it) {
$opt$inline$ignoreInt(ClassWithClinit8.value);
- ClassWithClinit8.$noinline$someStaticMethod(it);
+ ClassWithClinit8.someStaticMethod(it);
}
static void $opt$inline$ignoreInt(int i) {
@@ -351,10 +357,10 @@
System.out.println("Main$ClassWithClinit8's static initializer");
}
- static void $noinline$someStaticMethod(Iterable<?> it) {
+ // Note: not inlined from sgetAndInvokeStatic() but fully inlined from main().
+ static void someStaticMethod(Iterable<?> it) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
}
}
@@ -371,7 +377,7 @@
static void constClassSgetAndInvokeStatic(Iterable<?> it) {
$opt$inline$ignoreClass(ClassWithClinit9.class);
$opt$inline$ignoreInt(ClassWithClinit9.value);
- ClassWithClinit9.$noinline$someStaticMethod(it);
+ ClassWithClinit9.someStaticMethod(it);
}
static class ClassWithClinit9 {
@@ -380,10 +386,10 @@
System.out.println("Main$ClassWithClinit9's static initializer");
}
- static void $noinline$someStaticMethod(Iterable<?> it) {
+ // Note: not inlined from constClassSgetAndInvokeStatic() but fully inlined from main().
+ static void someStaticMethod(Iterable<?> it) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
}
}
@@ -416,9 +422,8 @@
static void inlinedForNull(Iterable<?> it) {
if (it != null) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
}
}
}
@@ -455,11 +460,8 @@
}
static void inlinedForNull(Iterable<?> it) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- if (it != null) {
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
- }
}
}
@@ -492,8 +494,8 @@
static void inlinedForNull(Iterable<?> it) {
if (it != null) {
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
+ // We're not inlining invoke-interface at the moment.
+ it.iterator();
}
}
}
@@ -508,9 +510,8 @@
}
public static void $noinline$getIterator(Iterable<?> it) {
+ // We're not inlining invoke-interface at the moment.
it.iterator();
- // We're not inlining throws at the moment.
- if (doThrow) { throw new Error(""); }
}
}
diff --git a/test/548-checker-inlining-and-dce/src/Main.java b/test/548-checker-inlining-and-dce/src/Main.java
index bf64c3b..38fdcc0 100644
--- a/test/548-checker-inlining-and-dce/src/Main.java
+++ b/test/548-checker-inlining-and-dce/src/Main.java
@@ -16,19 +16,17 @@
public class Main {
- static boolean doThrow = false;
-
private void inlinedForNull(Iterable it) {
if (it != null) {
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
+ // We're not inlining invoke-interface at the moment.
+ it.iterator();
}
}
private void inlinedForFalse(boolean value, Iterable it) {
if (value) {
- // We're not inlining throw at the moment.
- if (doThrow) { throw new Error(""); }
+ // We're not inlining invoke-interface at the moment.
+ it.iterator();
}
}
diff --git a/test/609-checker-inline-interface/expected.txt b/test/609-checker-inline-interface/expected.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/609-checker-inline-interface/expected.txt
+++ /dev/null
diff --git a/test/609-checker-inline-interface/info.txt b/test/609-checker-inline-interface/info.txt
deleted file mode 100644
index 35eee08..0000000
--- a/test/609-checker-inline-interface/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Checker test that we inline interface calls and if we can't inline
-them, we can turn them into a virtual invoke.
diff --git a/test/609-checker-inline-interface/src/Main.java b/test/609-checker-inline-interface/src/Main.java
deleted file mode 100644
index e9b3e87..0000000
--- a/test/609-checker-inline-interface/src/Main.java
+++ /dev/null
@@ -1,70 +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 final class Main implements Interface {
-
- static void methodWithInvokeInterface(Interface interf) {
- interf.$noinline$doCall();
- }
-
- public void $noinline$doCall() {
- if (doThrow) throw new Error("");
- }
-
- public static void main(String[] args) {
- testInlineInterfaceCall();
- testInterfaceToVirtualCall();
- }
-
- /// CHECK-START: void Main.testInlineInterfaceCall() inliner (before)
- /// CHECK: InvokeStaticOrDirect method_name:Main.methodWithInvokeInterface
-
- /// CHECK-START: void Main.testInlineInterfaceCall() inliner (before)
- /// CHECK-NOT: InvokeInterface
-
- /// CHECK-START: void Main.testInlineInterfaceCall() inliner (after)
- /// CHECK: InvokeInterface method_name:Interface.$noinline$doCall
-
- /// CHECK-START: void Main.testInlineInterfaceCall() inliner (after)
- /// CHECK-NOT: InvokeStaticOrDirect
- public static void testInlineInterfaceCall() {
- methodWithInvokeInterface(itf);
- }
-
- /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (before)
- /// CHECK: InvokeStaticOrDirect method_name:Main.methodWithInvokeInterface
-
- /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (before)
- /// CHECK-NOT: InvokeInterface
-
- /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (after)
- /// CHECK: InvokeVirtual method_name:Main.$noinline$doCall
-
- /// CHECK-START: void Main.testInterfaceToVirtualCall() inliner (after)
- /// CHECK-NOT: InvokeStaticOrDirect
- /// CHECK-NOT: InvokeInterface
- public static void testInterfaceToVirtualCall() {
- methodWithInvokeInterface(m);
- }
-
- static Interface itf = new Main();
- static Main m = new Main();
- static boolean doThrow = false;
-}
-
-interface Interface {
- public void $noinline$doCall();
-}