Verify methods that have been inlined into their single call site are pruned
Bug: 130721661
Change-Id: Ia7cda6e9d4f068705d8ae2984027f37182c00ed0
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e92c6f5..b48ea11 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -639,6 +639,9 @@
application,
CollectionUtils.mergeSets(prunedTypes, pruner.getRemovedClasses())));
+ // TODO(b/130721661): Enable this assert.
+ // assert Inliner.verifyNoMethodsInlinedDueToSingleCallSite(appView);
+
assert appView.verticallyMergedClasses() == null
|| appView.verticallyMergedClasses().verifyAllSourcesPruned(appViewWithLiveness);
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 23dbfbf..0446c21 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.OptimizationFeedback;
import com.android.tools.r8.ir.conversion.OptimizationFeedbackIgnore;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
@@ -22,7 +21,6 @@
private final boolean writeIR;
private final AppInfoWithSubtyping appInfo;
private final Timing timing = new Timing("AssemblyWriter");
- private final OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
public AssemblyWriter(
DexApplication application, InternalOptions options, boolean allInfo, boolean writeIR) {
@@ -122,7 +120,7 @@
private void writeIR(DexEncodedMethod method, PrintStream ps) {
CfgPrinter printer = new CfgPrinter();
new IRConverter(appInfo, options, timing, printer)
- .processMethod(method, ignoreOptimizationFeedback, null, null, null);
+ .processMethod(method, OptimizationFeedbackIgnore.getInstance(), null, null, null);
ps.println(printer.toString());
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 55c1336..add6578 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1045,6 +1045,11 @@
}
@Override
+ public boolean hasBeenInlinedIntoSingleCallSite() {
+ return false;
+ }
+
+ @Override
public boolean isReachabilitySensitive() {
return false;
}
@@ -1150,6 +1155,7 @@
public static class MethodOptimizationInfoImpl implements UpdatableMethodOptimizationInfo {
+ private boolean hasBeenInlinedIntoSingleCallSite = false;
private Set<DexType> initializedClassesOnNormalExit =
DefaultMethodOptimizationInfoImpl.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
private int returnedArgument = DefaultMethodOptimizationInfoImpl.UNKNOWN_RETURNED_ARGUMENT;
@@ -1259,6 +1265,16 @@
}
@Override
+ public boolean hasBeenInlinedIntoSingleCallSite() {
+ return hasBeenInlinedIntoSingleCallSite;
+ }
+
+ @Override
+ public void markInlinedIntoSingleCallSite() {
+ hasBeenInlinedIntoSingleCallSite = true;
+ }
+
+ @Override
public boolean isReachabilitySensitive() {
return reachabilitySensitive;
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/graph/MethodOptimizationInfo.java
index 96bbf6d..213bb11 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodOptimizationInfo.java
@@ -27,6 +27,8 @@
BitSet getNonNullParamOnNormalExits();
+ boolean hasBeenInlinedIntoSingleCallSite();
+
boolean isReachabilitySensitive();
boolean returnsArgument();
diff --git a/src/main/java/com/android/tools/r8/graph/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/graph/UpdatableMethodOptimizationInfo.java
index 1aa2129..5791733 100644
--- a/src/main/java/com/android/tools/r8/graph/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/UpdatableMethodOptimizationInfo.java
@@ -14,6 +14,8 @@
void markInitializesClassesOnNormalExit(Set<DexType> initializedClasses);
+ void markInlinedIntoSingleCallSite();
+
void markReturnsArgument(int argument);
void markReturnsConstantNumber(long value);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index d802627..0ec8d2f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -148,7 +148,6 @@
private final OptimizationFeedbackDelayed delayedOptimizationFeedback =
new OptimizationFeedbackDelayed();
- private final OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
private final OptimizationFeedback simpleOptimizationFeedback = new OptimizationFeedbackSimple();
private DexString highestSortingString;
@@ -598,7 +597,7 @@
(code, method) -> {
outliner.applyOutliningCandidate(code, method);
printMethod(code, "IR after outlining (SSA)", null);
- finalizeIR(method, code, ignoreOptimizationFeedback);
+ finalizeIR(method, code, OptimizationFeedbackIgnore.getInstance());
});
assert outliner.checkAllOutlineSitesFoundAgain();
builder.addSynthesizedClass(outlineClass, true);
@@ -962,7 +961,7 @@
previous = printMethod(code, "IR after null tracking (SSA)", previous);
if (!isDebugMode && options.enableInlining && inliner != null) {
- inliner.performInlining(method, code, isProcessedConcurrently, callSiteInformation);
+ inliner.performInlining(method, code, feedback, isProcessedConcurrently, callSiteInformation);
}
previous = printMethod(code, "IR after inlining (SSA)", previous);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
index 488c06b..bf7e94f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedback.java
@@ -17,6 +17,8 @@
public interface OptimizationFeedback {
+ void markInlinedIntoSingleCallSite(DexEncodedMethod method);
+
void methodInitializesClassesOnNormalExit(
DexEncodedMethod method, Set<DexType> initializedClasses);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDelayed.java
index 874977b..4ca780d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackDelayed.java
@@ -38,6 +38,11 @@
}
@Override
+ public synchronized void markInlinedIntoSingleCallSite(DexEncodedMethod method) {
+ getOptimizationInfoForUpdating(method).markInlinedIntoSingleCallSite();
+ }
+
+ @Override
public synchronized void methodInitializesClassesOnNormalExit(
DexEncodedMethod method, Set<DexType> initializedClasses) {
getOptimizationInfoForUpdating(method).markInitializesClassesOnNormalExit(initializedClasses);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
index 0946ca3..7eb3549 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackIgnore.java
@@ -17,6 +17,17 @@
public class OptimizationFeedbackIgnore implements OptimizationFeedback {
+ private static final OptimizationFeedbackIgnore INSTANCE = new OptimizationFeedbackIgnore();
+
+ private OptimizationFeedbackIgnore() {}
+
+ public static OptimizationFeedbackIgnore getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public void markInlinedIntoSingleCallSite(DexEncodedMethod method) {}
+
@Override
public void methodInitializesClassesOnNormalExit(
DexEncodedMethod method, Set<DexType> initializedClasses) {}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
index 313148f..44639e3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/OptimizationFeedbackSimple.java
@@ -18,6 +18,11 @@
public class OptimizationFeedbackSimple implements OptimizationFeedback {
@Override
+ public synchronized void markInlinedIntoSingleCallSite(DexEncodedMethod method) {
+ // Ignored.
+ }
+
+ @Override
public void methodInitializesClassesOnNormalExit(
DexEncodedMethod method, Set<DexType> initializedClasses) {
// Ignored.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 4cf7120..e22e6fa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.CallSiteInformation;
+import com.android.tools.r8.ir.conversion.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.InlineeWithReason;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -384,13 +385,14 @@
}
@Override
- public void ensureMethodProcessed(DexEncodedMethod target, IRCode inlinee) {
+ public void ensureMethodProcessed(
+ DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback) {
if (!target.isProcessed()) {
if (Log.ENABLED) {
Log.verbose(getClass(), "Forcing extra inline on " + target.toSourceString());
}
inliner.performInlining(
- target, inlinee, isProcessedConcurrently, callSiteInformation);
+ target, inlinee, feedback, isProcessedConcurrently, callSiteInformation);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index dd1f2fe..90d0ac9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokePolymorphic;
import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.conversion.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
import com.android.tools.r8.ir.optimize.Inliner.InlineeWithReason;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -69,7 +70,8 @@
}
@Override
- public void ensureMethodProcessed(DexEncodedMethod target, IRCode inlinee) {
+ public void ensureMethodProcessed(
+ DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback) {
// Do nothing. If the method is not yet processed, we still should
// be able to build IR for inlining, though.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index dfa9dd0..1aca825 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.NestMemberClassAttribute;
@@ -34,6 +35,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.LensCodeRewriter;
import com.android.tools.r8.ir.conversion.OptimizationFeedback;
+import com.android.tools.r8.ir.conversion.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -745,12 +747,13 @@
Map<InvokeMethod, InliningInfo> invokesToInline) {
ForcedInliningOracle oracle = new ForcedInliningOracle(method, invokesToInline);
- performInliningImpl(oracle, oracle, method, code);
+ performInliningImpl(oracle, oracle, method, code, OptimizationFeedbackIgnore.getInstance());
}
public void performInlining(
DexEncodedMethod method,
IRCode code,
+ OptimizationFeedback feedback,
Predicate<DexEncodedMethod> isProcessedConcurrently,
CallSiteInformation callSiteInformation) {
InternalOptions options = appView.options();
@@ -762,7 +765,7 @@
callSiteInformation,
options.inliningInstructionLimit,
options.inliningInstructionAllowance - numberOfInstructions(code));
- performInliningImpl(oracle, oracle, method, code);
+ performInliningImpl(oracle, oracle, method, code, feedback);
}
public DefaultInliningOracle createDefaultOracle(
@@ -784,7 +787,11 @@
}
private void performInliningImpl(
- InliningStrategy strategy, InliningOracle oracle, DexEncodedMethod context, IRCode code) {
+ InliningStrategy strategy,
+ InliningOracle oracle,
+ DexEncodedMethod context,
+ IRCode code,
+ OptimizationFeedback feedback) {
AssumeDynamicTypeRemover assumeDynamicTypeRemover = new AssumeDynamicTypeRemover(appView, code);
List<BasicBlock> blocksToRemove = new ArrayList<>();
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -826,7 +833,7 @@
// If this code did not go through the full pipeline, apply inlining to make sure
// that force inline targets get processed.
- strategy.ensureMethodProcessed(target, inlinee.code);
+ strategy.ensureMethodProcessed(target, inlinee.code, feedback);
// Make sure constructor inlining is legal.
assert !target.isClassInitializer();
@@ -852,6 +859,10 @@
blocksToRemove,
getDowncastTypeIfNeeded(strategy, invoke, target));
+ if (inlinee.reason == Reason.SINGLE_CALLER) {
+ feedback.markInlinedIntoSingleCallSite(target);
+ }
+
classInitializationAnalysis.notifyCodeHasChanged();
strategy.updateTypeInformationIfNeeded(inlinee.code, blockIterator, block);
@@ -910,4 +921,13 @@
}
return null;
}
+
+ public static boolean verifyNoMethodsInlinedDueToSingleCallSite(AppView<?> appView) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ for (DexEncodedMethod method : clazz.methods()) {
+ assert !method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite();
+ }
+ }
+ return true;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
index feba578..678cbc3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningStrategy.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.conversion.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.Inliner.InlineeWithReason;
import java.util.ListIterator;
@@ -28,7 +29,8 @@
/** Inform the strategy that the inlinee has been inlined. */
void markInlined(InlineeWithReason inlinee);
- void ensureMethodProcessed(DexEncodedMethod target, IRCode inlinee);
+ void ensureMethodProcessed(
+ DexEncodedMethod target, IRCode inlinee, OptimizationFeedback feedback);
boolean isValidTarget(
InvokeMethod invoke, DexEncodedMethod target, IRCode inlinee, ClassHierarchy hierarchy);