Enqueue callers for reoptimization on-the-fly in final optimization pass
Bug: b/339210038
Change-Id: I4cb8a4ccc81d462bfc8730d0f007f76e6f418adb
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 3ea094d..2196366 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -136,7 +136,7 @@
private final LibraryMethodSideEffectModelCollection libraryMethodSideEffectModelCollection;
// Optimizations.
- private final ArgumentPropagator argumentPropagator;
+ private ArgumentPropagator argumentPropagator;
private final LibraryMemberOptimizer libraryMemberOptimizer;
private final ProtoShrinker protoShrinker;
@@ -564,6 +564,10 @@
return appInfo.getSyntheticItems();
}
+ public void unsetArgumentPropagator() {
+ argumentPropagator = null;
+ }
+
public <E extends Throwable> void withArgumentPropagator(
ThrowingConsumer<ArgumentPropagator, E> consumer) throws E {
if (argumentPropagator != null) {
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 7eb18f1..83f6884 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
@@ -63,6 +63,7 @@
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.ir.optimize.enums.EnumValueOptimizer;
import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoCollector;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -88,8 +89,8 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
import com.android.tools.r8.utils.InternalOptions.NeverMergeGroup;
-import com.android.tools.r8.utils.LazyBox;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
@@ -283,6 +284,10 @@
return inliner;
}
+ public void unsetEnumUnboxer() {
+ enumUnboxer = EnumUnboxer.empty();
+ }
+
private boolean needsIRConversion(ProgramMethod method) {
if (method.getDefinition().getCode().isThrowNullCode()) {
return false;
@@ -720,21 +725,10 @@
timing.begin("Inline classes");
// Class inliner should work before lambda merger, so if it inlines the
// lambda, it does not get collected by merger.
- assert options.inlinerOptions().enableInlining && inliner != null;
+ assert options.inlinerOptions().enableInlining;
+ assert inliner != null;
classInliner.processMethodCode(
- code.context(),
- code,
- feedback,
- methodProcessor,
- methodProcessingContext,
- new LazyBox<>(
- () ->
- inliner.createDefaultOracle(
- code.context(),
- methodProcessor,
- // Inlining instruction allowance is not needed for the class inliner since it
- // always uses a force inlining oracle for inlining.
- -1)));
+ context, code, feedback, methodProcessor, methodProcessingContext);
timing.end();
code.removeRedundantBlocks();
assert code.isConsistentSSA(appView);
@@ -840,6 +834,7 @@
timing.begin("Finalize IR");
finalizeIR(code, feedback, bytecodeMetadataProviderBuilder.build(), timing, previous);
timing.end();
+ maybeMarkCallersForProcessing(context, methodProcessor);
return timing;
}
@@ -968,6 +963,54 @@
printMethod(code.context(), "After finalization");
}
+ private void maybeMarkCallersForProcessing(
+ ProgramMethod method, MethodProcessor methodProcessor) {
+ if (methodProcessor.isPostMethodProcessor()) {
+ PostMethodProcessor postMethodProcessor = methodProcessor.asPostMethodProcessor();
+ if (shouldMarkCallersForProcessing(method)) {
+ postMethodProcessor.markCallersForProcessing(method);
+ }
+ }
+ }
+
+ private boolean shouldMarkCallersForProcessing(ProgramMethod method) {
+ Code bytecode = method.getDefinition().getCode();
+ InlinerOptions inlinerOptions = appView.options().inlinerOptions();
+ int instructionLimit = inlinerOptions.getSimpleInliningInstructionLimit();
+ int estimatedIncrement = getEstimatedInliningInstructionLimitIncrementForReturn();
+ if (bytecode.estimatedSizeForInliningAtMost(instructionLimit + estimatedIncrement)) {
+ return true;
+ }
+ if (delayedOptimizationFeedback.hasPendingOptimizationInfo(method)) {
+ MethodOptimizationInfo oldOptimizationInfo = method.getOptimizationInfo();
+ MethodOptimizationInfo newOptimizationInfo =
+ delayedOptimizationFeedback.getMethodOptimizationInfoForUpdating(method);
+ if (!oldOptimizationInfo
+ .getAbstractReturnValue()
+ .equals(newOptimizationInfo.getAbstractReturnValue())) {
+ return true;
+ }
+ if (!oldOptimizationInfo.getDynamicType().equals(newOptimizationInfo.getDynamicType())) {
+ return true;
+ }
+ if (oldOptimizationInfo.mayHaveSideEffects() && !newOptimizationInfo.mayHaveSideEffects()) {
+ return true;
+ }
+ if (!oldOptimizationInfo.neverReturnsNormally()
+ && newOptimizationInfo.neverReturnsNormally()) {
+ return true;
+ }
+ if (!oldOptimizationInfo.returnsArgument() && newOptimizationInfo.returnsArgument()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int getEstimatedInliningInstructionLimitIncrementForReturn() {
+ return 1;
+ }
+
private IRCode roundtripThroughLir(
IRCode code,
BytecodeMetadataProvider bytecodeMetadataProvider,
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
index 829c985..9eb24e1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessor.java
@@ -33,6 +33,10 @@
return false;
}
+ public PostMethodProcessor asPostMethodProcessor() {
+ return null;
+ }
+
public abstract MethodProcessorEventConsumer getEventConsumer();
public abstract boolean isProcessedConcurrently(ProgramMethod method);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index 9175986..a8fe188 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.conversion.PrimaryMethodProcessor.MethodAction;
import com.android.tools.r8.ir.conversion.callgraph.CallGraph;
-import com.android.tools.r8.ir.conversion.callgraph.PartialCallGraphBuilder;
+import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.threading.ThreadingModule;
@@ -24,6 +24,7 @@
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.io.IOException;
import java.util.ArrayDeque;
@@ -35,20 +36,45 @@
public class PostMethodProcessor extends MethodProcessorWithWave {
+ private CallSiteInformation callSiteInformation;
private final MethodProcessorEventConsumer eventConsumer;
+ private final ProgramMethodSet methodsToProcess;
+ private final ProgramMethodSet processed = ProgramMethodSet.create();
private final ProcessorContext processorContext;
private final Deque<ProgramMethodSet> waves;
- private final ProgramMethodSet processed = ProgramMethodSet.create();
+
+ // The set of callers for a given method according to the call graph. This might not be the
+ // complete set of callers.
+ private final ProgramMethodMap<ProgramMethodSet> callers = ProgramMethodMap.createConcurrent();
private PostMethodProcessor(
AppView<AppInfoWithLiveness> appView,
CallGraph callGraph,
- MethodProcessorEventConsumer eventConsumer) {
+ MethodProcessorEventConsumer eventConsumer,
+ ProgramMethodSet methodsToProcess) {
+ this.callSiteInformation = callGraph.createCallSiteInformation(appView, this);
this.eventConsumer = eventConsumer;
+ this.methodsToProcess = methodsToProcess;
this.processorContext = appView.createProcessorContext();
this.waves = createWaves(callGraph);
}
+ public void markCallersForProcessing(ProgramMethod method) {
+ assert wave.contains(method);
+ synchronized (methodsToProcess) {
+ for (ProgramMethod caller : callers.removeOrDefault(method, ProgramMethodSet.empty())) {
+ if (!wave.contains(caller)) {
+ methodsToProcess.add(caller);
+ }
+ }
+ }
+ }
+
+ @Override
+ public CallSiteInformation getCallSiteInformation() {
+ return callSiteInformation;
+ }
+
@Override
public MethodProcessorEventConsumer getEventConsumer() {
return eventConsumer;
@@ -60,6 +86,11 @@
}
@Override
+ public PostMethodProcessor asPostMethodProcessor() {
+ return this;
+ }
+
+ @Override
public boolean shouldApplyCodeRewritings(ProgramMethod method) {
assert !wave.contains(method);
return !processed.contains(method);
@@ -152,9 +183,8 @@
assert !appView.options().debug
|| methodsToReprocess.stream()
.allMatch(methodToReprocess -> methodToReprocess.getDefinition().isD8R8Synthesized());
- CallGraph callGraph =
- new PartialCallGraphBuilder(appView, methodsToReprocess).build(executorService, timing);
- return new PostMethodProcessor(appView, callGraph, eventConsumer);
+ CallGraph callGraph = CallGraph.builder(appView).build(executorService, timing);
+ return new PostMethodProcessor(appView, callGraph, eventConsumer, methodsToReprocess);
}
public void dump(DeterminismChecker determinismChecker) throws IOException {
@@ -162,19 +192,28 @@
}
}
- @SuppressWarnings("UnusedVariable")
private Deque<ProgramMethodSet> createWaves(CallGraph callGraph) {
Deque<ProgramMethodSet> waves = new ArrayDeque<>();
- int waveCount = 1;
while (!callGraph.isEmpty()) {
- ProgramMethodSet wave = callGraph.extractLeaves();
- waves.addLast(wave);
+ waves.addLast(
+ callGraph.extractLeaves(
+ leaf -> {
+ if (!leaf.getCallers().isEmpty()) {
+ callers.put(
+ leaf.getProgramMethod(),
+ ProgramMethodSet.create(
+ builder ->
+ leaf.getCallers()
+ .forEach(caller -> builder.accept(caller.getProgramMethod()))));
+ }
+ }));
}
return waves;
}
<E extends Exception> void forEachMethod(
MethodAction<E> consumer,
+ PrimaryR8IRConverter converter,
OptimizationFeedbackDelayed feedback,
ThreadingModule threadingModule,
ExecutorService executorService,
@@ -184,9 +223,14 @@
while (!waves.isEmpty()) {
wave = waves.removeFirst();
assert !wave.isEmpty();
+ wave.removeIf(method -> !methodsToProcess.contains(method));
+ if (wave.isEmpty()) {
+ continue;
+ }
assert waveExtension.isEmpty();
do {
assert feedback.noUpdatesLeft();
+ converter.waveStart(wave);
Collection<Timing> timings =
ThreadUtils.processItemsWithResults(
wave,
@@ -200,11 +244,21 @@
threadingModule,
executorService);
merger.add(timings);
+ converter.waveDone(wave, executorService);
feedback.updateVisibleOptimizationInfo();
processed.addAll(wave);
prepareForWaveExtensionProcessing();
} while (!wave.isEmpty());
}
+ clear();
merger.end();
}
+
+ private void clear() {
+ assert waves.isEmpty();
+ callers.clear();
+ methodsToProcess.clear();
+ processed.clear();
+ callSiteInformation = CallSiteInformation.empty();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
index d56bdfb..4e3f618 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryMethodProcessor.java
@@ -10,9 +10,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.callgraph.CallGraph;
import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
-import com.android.tools.r8.ir.conversion.callgraph.Node;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
@@ -52,7 +50,7 @@
CallGraph callGraph,
MethodProcessorEventConsumer eventConsumer) {
this.appView = appView;
- this.callSiteInformation = callGraph.createCallSiteInformation(appView);
+ this.callSiteInformation = callGraph.createCallSiteInformation(appView, this);
this.eventConsumer = eventConsumer;
this.waves = createWaves(appView, callGraph);
}
@@ -93,16 +91,12 @@
return callSiteInformation;
}
- @SuppressWarnings("UnusedVariable")
private Deque<ProgramMethodSet> createWaves(AppView<?> appView, CallGraph callGraph) {
- InternalOptions options = appView.options();
Deque<ProgramMethodSet> waves = new ArrayDeque<>();
- Collection<Node> nodes = callGraph.getNodes();
- while (!nodes.isEmpty()) {
- ProgramMethodSet wave = callGraph.extractLeaves();
- waves.addLast(wave);
+ while (!callGraph.isEmpty()) {
+ waves.addLast(callGraph.extractLeaves());
}
- options.testing.waveModifier.accept(waves);
+ appView.testing().waveModifier.accept(waves);
return waves;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index 035690f..1277429 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -190,6 +190,7 @@
postMethodProcessor,
methodProcessingContext,
MethodConversionOptions.forLirPhase(appView)),
+ this,
feedback,
appView.options().getThreadingModule(),
executorService,
@@ -248,7 +249,7 @@
}
}
- private void waveStart(ProgramMethodSet wave) {
+ public void waveStart(ProgramMethodSet wave) {
onWaveDoneActions = Collections.synchronizedList(new ArrayList<>());
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallGraph.java
index a5a151b..1e890ec 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallGraph.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.conversion.MethodProcessorWithWave;
import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation.CallGraphBasedCallSiteInformation;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
@@ -56,10 +57,11 @@
node -> node.getProgramMethod().getReference(), Function.identity())));
}
- public CallSiteInformation createCallSiteInformation(AppView<AppInfoWithLiveness> appView) {
+ public CallSiteInformation createCallSiteInformation(
+ AppView<AppInfoWithLiveness> appView, MethodProcessorWithWave methodProcessor) {
// Don't leverage single/dual call site information when we are not tree shaking.
return appView.options().isShrinking()
- ? new CallGraphBasedCallSiteInformation(appView, this)
+ ? new CallGraphBasedCallSiteInformation(appView, this, methodProcessor)
: CallSiteInformation.empty();
}
@@ -67,6 +69,15 @@
return extractNodes(Node::isLeaf, Node::cleanCallersAndReadersForRemoval);
}
+ public ProgramMethodSet extractLeaves(Consumer<Node> nodeRemovalConsumer) {
+ return extractNodes(
+ Node::isLeaf,
+ node -> {
+ nodeRemovalConsumer.accept(node);
+ node.cleanCallersAndReadersForRemoval();
+ });
+ }
+
public ProgramMethodSet extractRoots() {
return extractNodes(Node::isRoot, Node::cleanCalleesAndWritersForRemoval);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
index 300487b..25c381e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
@@ -7,8 +7,10 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.MethodProcessorWithWave;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepMethodInfo;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.classhierarchy.MethodOverridesCollector;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -75,7 +77,10 @@
private final Map<DexMethod, DexMethod> singleCallerMethods = new IdentityHashMap<>();
private final Set<DexMethod> multiCallerInlineCandidates = Sets.newIdentityHashSet();
- CallGraphBasedCallSiteInformation(AppView<AppInfoWithLiveness> appView, CallGraph graph) {
+ CallGraphBasedCallSiteInformation(
+ AppView<AppInfoWithLiveness> appView,
+ CallGraph graph,
+ MethodProcessorWithWave methodProcessor) {
InternalOptions options = appView.options();
ProgramMethodSet pinned =
MethodOverridesCollector.findAllMethodsAndOverridesThatMatches(
@@ -114,6 +119,14 @@
if (!appView.getKeepInfo(method).isSingleCallerInliningAllowed(options)) {
continue;
}
+ if (methodProcessor.isPostMethodProcessor()) {
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ if (syntheticItems.hasKindThatMatches(
+ method.getHolderType(),
+ (kind, naming) -> !kind.isSingleCallerInlineableInPostMethodProcessor(naming))) {
+ continue;
+ }
+ }
Set<Node> callersWithDeterministicOrder = node.getCallersWithDeterministicOrder();
DexMethod caller = reference;
// We can have recursive methods where the recursive call is the only call site. We do
@@ -124,7 +137,7 @@
}
DexMethod existing = singleCallerMethods.put(reference, caller);
assert existing == null;
- } else if (numberOfCallSites > 1) {
+ } else if (numberOfCallSites > 1 && methodProcessor.isPrimaryMethodProcessor()) {
multiCallerInlineCandidates.add(reference);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/Node.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/Node.java
index e515764..bd2c77c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/Node.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/Node.java
@@ -132,6 +132,10 @@
}
}
+ public Set<Node> getCallers() {
+ return callers;
+ }
+
public Set<Node> getCallersWithDeterministicOrder() {
return callers;
}
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 a166867..337d90d 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
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.ir.optimize.Inliner.numberOfInstructions;
import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.addMonitorEnterValue;
import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues;
import static com.android.tools.r8.utils.AndroidApiLevelUtils.isApiSafeForInlining;
@@ -75,9 +76,24 @@
public DefaultInliningOracle(
AppView<AppInfoWithLiveness> appView,
- InliningReasonStrategy inliningReasonStrategy,
ProgramMethod method,
MethodProcessor methodProcessor,
+ InliningReasonStrategy inliningReasonStrategy,
+ IRCode code) {
+ this(
+ appView,
+ method,
+ methodProcessor,
+ inliningReasonStrategy,
+ appView.options().inlinerOptions().inliningInstructionAllowance
+ - numberOfInstructions(code));
+ }
+
+ public DefaultInliningOracle(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod method,
+ MethodProcessor methodProcessor,
+ InliningReasonStrategy inliningReasonStrategy,
int inliningInstructionAllowance) {
this.appView = appView;
this.options = appView.options();
@@ -776,8 +792,8 @@
private boolean willExceedInstructionBudget(
IRCode inlinee, WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
- int numberOfInstructions = Inliner.numberOfInstructions(inlinee);
- if (instructionAllowance < Inliner.numberOfInstructions(inlinee)) {
+ int numberOfInstructions = numberOfInstructions(inlinee);
+ if (instructionAllowance < numberOfInstructions(inlinee)) {
whyAreYouNotInliningReporter.reportWillExceedInstructionBudget(
numberOfInstructions, instructionAllowance);
return true;
@@ -887,7 +903,7 @@
@Override
public void markInlined(IRCode inlinee) {
// TODO(118734615): All inlining use from the budget - should that only be SIMPLE?
- instructionAllowance -= Inliner.numberOfInstructions(inlinee);
+ instructionAllowance -= numberOfInstructions(inlinee);
}
@Override
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 8068a8a..700ead2 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
@@ -879,7 +879,7 @@
}
}
- static int numberOfInstructions(IRCode code) {
+ public static int numberOfInstructions(IRCode code) {
int numberOfInstructions = 0;
for (BasicBlock block : code.blocks) {
for (Instruction instruction : block.getInstructions()) {
@@ -964,13 +964,8 @@
MethodProcessor methodProcessor,
Timing timing,
InliningReasonStrategy inliningReasonStrategy) {
- InlinerOptions options = appView.options().inlinerOptions();
DefaultInliningOracle oracle =
- createDefaultOracle(
- method,
- methodProcessor,
- options.inliningInstructionAllowance - numberOfInstructions(code),
- inliningReasonStrategy);
+ createDefaultOracle(code, method, methodProcessor, inliningReasonStrategy);
InliningIRProvider inliningIRProvider =
new InliningIRProvider(appView, method, code, lensCodeRewriter, methodProcessor);
assert inliningIRProvider.verifyIRCacheIsEmpty();
@@ -988,27 +983,12 @@
}
public DefaultInliningOracle createDefaultOracle(
+ IRCode code,
ProgramMethod method,
MethodProcessor methodProcessor,
- int inliningInstructionAllowance) {
- return createDefaultOracle(
- method,
- methodProcessor,
- inliningInstructionAllowance,
- createDefaultInliningReasonStrategy(methodProcessor));
- }
-
- public DefaultInliningOracle createDefaultOracle(
- ProgramMethod method,
- MethodProcessor methodProcessor,
- int inliningInstructionAllowance,
InliningReasonStrategy inliningReasonStrategy) {
return new DefaultInliningOracle(
- appView,
- inliningReasonStrategy,
- method,
- methodProcessor,
- inliningInstructionAllowance);
+ appView, method, methodProcessor, inliningReasonStrategy, code);
}
private void performInliningImpl(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
index baa1fc5..36e3717 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MultiCallerInliner.java
@@ -74,9 +74,9 @@
int inliningInstructionAllowance = Integer.MAX_VALUE;
return new DefaultInliningOracle(
appView,
- new FixedInliningReasonStrategy(Reason.ALWAYS),
method,
methodProcessor,
+ new FixedInliningReasonStrategy(Reason.ALWAYS),
inliningInstructionAllowance);
});
for (InvokeMethod invoke : code.<InvokeMethod>instructions(Instruction::isInvokeMethod)) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 4918f7c..d934757 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.conversion.passes.BranchSimplifier;
import com.android.tools.r8.ir.conversion.passes.TrivialCheckCastAndInstanceOfRemover;
import com.android.tools.r8.ir.optimize.AffectedValues;
+import com.android.tools.r8.ir.optimize.DefaultInliningOracle;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.InliningOracle;
import com.android.tools.r8.ir.optimize.classinliner.InlineCandidateProcessor.IllegalClassInlinerStateException;
@@ -133,8 +134,17 @@
IRCode code,
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
- MethodProcessingContext methodProcessingContext,
- LazyBox<InliningOracle> defaultOracle) {
+ MethodProcessingContext methodProcessingContext) {
+ LazyBox<InliningOracle> defaultOracle =
+ new LazyBox<>(
+ () ->
+ new DefaultInliningOracle(
+ appView,
+ method,
+ methodProcessor,
+ inliner.createDefaultInliningReasonStrategy(methodProcessor),
+ code));
+
// Collect all the new-instance and static-get instructions in the code before inlining.
List<Instruction> roots =
Lists.newArrayList(code.instructions(insn -> insn.isNewInstance() || insn.isStaticGet()));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index a7cbb72..b26ed45 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -712,6 +712,7 @@
if (enumUnboxingCandidatesInfo.isEmpty()) {
assert enumDataMap.isEmpty();
+ converter.unsetEnumUnboxer();
timing.end();
return;
}
@@ -781,6 +782,7 @@
appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
appView.notifyOptimizationFinishedForTesting();
+ converter.unsetEnumUnboxer();
timing.end();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 6b0b6eb..0ab35bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -64,10 +64,14 @@
return info;
}
- private MutableMethodOptimizationInfo getMethodOptimizationInfoForUpdating(ProgramMethod method) {
+ public MutableMethodOptimizationInfo getMethodOptimizationInfoForUpdating(ProgramMethod method) {
return getMethodOptimizationInfoForUpdating(method.getDefinition());
}
+ public synchronized boolean hasPendingOptimizationInfo(ProgramMethod method) {
+ return methodOptimizationInfos.containsKey(method.getDefinition());
+ }
+
@Override
public void fixupOptimizationInfos(
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
index 7c5240b..2e2c0a1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -58,7 +58,7 @@
if (!converter.isInWave()) {
return;
}
- assert methodProcessor.isPrimaryMethodProcessor();
+ assert methodProcessor.isPrimaryMethodProcessor() || methodProcessor.isPostMethodProcessor();
if (isCandidateForInstanceOfOptimization(method, abstractReturnValue)) {
synchronized (this) {
if (candidatesForInstanceOfOptimization.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index b443888..2fd6eb9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -211,8 +211,8 @@
// Ensure determinism of method-to-reprocess set.
appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
-
appView.notifyOptimizationFinishedForTesting();
+ appView.unsetArgumentPropagator();
}
/**
diff --git a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
index 70b50c9..614cf22 100644
--- a/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
+++ b/src/main/java/com/android/tools/r8/optimize/singlecaller/SingleCallerInliner.java
@@ -250,12 +250,12 @@
@Override
public DefaultInliningOracle createDefaultOracle(
+ IRCode code,
ProgramMethod method,
MethodProcessor methodProcessor,
- int inliningInstructionAllowance,
InliningReasonStrategy inliningReasonStrategy) {
return new DefaultInliningOracle(
- appView, inliningReasonStrategy, method, methodProcessor, inliningInstructionAllowance) {
+ appView, method, methodProcessor, inliningReasonStrategy, code) {
@Override
public InlineResult computeInlining(
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 50c9f23..b940b87 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -50,6 +50,7 @@
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.Timing;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
@@ -64,9 +65,9 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Predicate;
import java.util.function.Supplier;
import org.objectweb.asm.ClassWriter;
@@ -522,6 +523,11 @@
return true;
}
+ public boolean hasKindThatMatches(
+ DexType type, BiPredicate<? super SyntheticKind, ? super SyntheticNaming> predicate) {
+ return Iterables.any(getSyntheticKinds(type), kind -> predicate.test(kind, naming));
+ }
+
public boolean isSyntheticOfKind(DexType type, SyntheticKindSelector kindSelector) {
SyntheticKind kind = kindSelector.select(naming);
return pending.containsTypeOfKind(type, kind) || committed.containsTypeOfKind(type, kind);
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 177bf18..861e8e9 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -232,6 +232,14 @@
return descriptor;
}
+ public boolean isSingleCallerInlineableInPostMethodProcessor(SyntheticNaming naming) {
+ // Do not allow single caller inlining the enum utility classes in the second optimization
+ // pass. We rewrite code on-the-fly to call these method, so removing them as a result of
+ // single caller inlining would lead to compilation errors.
+ return !equals(naming.ENUM_UNBOXING_LOCAL_UTILITY_CLASS)
+ && !equals(naming.ENUM_UNBOXING_SHARED_UTILITY_CLASS);
+ }
+
public boolean isSyntheticMethodKind() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMemberMap.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMemberMap.java
index 35023fc..1d47ac2 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMemberMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMemberMap.java
@@ -169,6 +169,11 @@
.removeIf(entry -> predicate.test(entry.getKey().get(), entry.getValue(), entry));
}
+ public V removeOrDefault(K member, V defaultValue) {
+ V value = remove(member);
+ return value != null ? value : defaultValue;
+ }
+
@Override
public int size() {
return backing.size();
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index f4c915f..ee2f958 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -205,7 +205,7 @@
.withDexCheck(
inspector ->
checkLambdaCount(
- inspector, enableProguardCompatibilityMode ? 3 : 4, "lambdadesugaringnplus"))
+ inspector, enableProguardCompatibilityMode ? 1 : 2, "lambdadesugaringnplus"))
.run();
test("lambdadesugaringnplus", "lambdadesugaringnplus", "LambdasWithStaticAndDefaultMethods")
@@ -247,7 +247,7 @@
b ->
b.addProguardConfiguration(
getProguardOptionsNPlus(enableProguardCompatibilityMode), Origin.unknown()))
- .withDexCheck(inspector -> checkLambdaCount(inspector, 4, "lambdadesugaringnplus"))
+ .withDexCheck(inspector -> checkLambdaCount(inspector, 2, "lambdadesugaringnplus"))
.run();
test("lambdadesugaringnplus", "lambdadesugaringnplus", "LambdasWithStaticAndDefaultMethods")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index b27142b..fba129a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -100,7 +100,9 @@
@NoVerticalClassMerging
static class Base {}
+ @NeverClassInline
static class Sub1 extends Base {}
+
static class Sub2 extends Base {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
index 5228de1..81425e0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
@@ -7,6 +7,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoParameterTypeStrengthening;
import com.android.tools.r8.NoVerticalClassMerging;
@@ -43,6 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeStaticPositiveTest.class)
.addKeepMainRule(MAIN)
+ .enableNeverClassInliningAnnotations()
.enableNoParameterTypeStrengtheningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
@@ -89,7 +91,9 @@
@NoVerticalClassMerging
static class Base {}
+ @NeverClassInline
static class Sub1 extends Base {}
+
static class Sub2 extends Base {}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
index cebee69..a1de3e7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.NeverInline;
@@ -15,7 +14,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -23,6 +21,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class StringIsEmptyTest extends TestBase {
@@ -34,16 +34,13 @@
);
private static final Class<?> MAIN = TestClass.class;
- @Parameterized.Parameters(name = "{0}")
+ @Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- private final TestParameters parameters;
-
- public StringIsEmptyTest(TestParameters parameters) {
- this.parameters = parameters;
- }
+ @Parameter(0)
+ public TestParameters parameters;
@Test
public void testJVMOutput() throws Exception {
@@ -54,13 +51,8 @@
.assertSuccessWithOutput(JAVA_OUTPUT);
}
- private void configure(InternalOptions options) {
- // This test wants to check if compile-time computation is not applied to non-null,
- // non-constant value. In a simple test setting, call-site optimization knows the argument is
- // always a non-null, specific constant, but that is beyond the scope of this test.
- }
-
- private void test(SingleTestRunResult result, int expectedStringIsEmptyCount) throws Exception {
+ private void test(SingleTestRunResult<?> result, int expectedStringIsEmptyCount)
+ throws Exception {
CodeInspector codeInspector = result.inspector();
ClassSubject mainClass = codeInspector.clazz(MAIN);
MethodSubject mainMethod = mainClass.mainMethod();
@@ -75,14 +67,13 @@
@Test
public void testD8() throws Exception {
- assumeTrue("Only run D8 for Dex backend", parameters.isDexRuntime());
+ parameters.assumeDexRuntime();
D8TestRunResult result =
testForD8()
.debug()
.addProgramClasses(MAIN)
.setMinApi(parameters)
- .addOptionsModification(this::configure)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 3);
@@ -92,7 +83,6 @@
.release()
.addProgramClasses(MAIN)
.setMinApi(parameters)
- .addOptionsModification(this::configure)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
test(result, 1);
@@ -103,14 +93,12 @@
R8TestRunResult result =
testForR8(parameters.getBackend())
.addProgramClasses(MAIN)
- .enableProguardTestOptions()
- .enableInliningAnnotations()
.addKeepMainRule(MAIN)
+ .enableInliningAnnotations()
.setMinApi(parameters)
- .addOptionsModification(this::configure)
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 1);
+ test(result, 0);
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
index b0b7907..e90e867 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
@@ -22,34 +22,34 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
/** Reproduction for b/128917897. */
@RunWith(Parameterized.class)
public class NestedInterfaceMethodTest extends TestBase {
- private final TestParameters parameters;
+ private static final String expectedOutput = StringUtils.lines("In A.m()", "In C.m()");
+
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection params() {
return getTestParameters().withAllRuntimes().build();
}
- public NestedInterfaceMethodTest(TestParameters parameters) {
- this.parameters = parameters;
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeCfRuntime();
+ testForJvm(parameters)
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expectedOutput);
}
@Test
- public void test() throws Exception {
- String expectedOutput = StringUtils.lines("In A.m()", "In A.m()");
-
- if (parameters.isCfRuntime()) {
- testForJvm(parameters)
- .addTestClasspath()
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- }
-
+ public void testR8() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
.addInnerClasses(NestedInterfaceMethodTest.class)
@@ -127,7 +127,14 @@
// TestClass.test() gets devirtualized to an invoke-virtual instruction. Otherwise the method
// I.m() would not be present in the output.
@NeverClassInline
- static class C extends A {}
+ static class C implements I {
+
+ @Override
+ public Uninstantiated m() {
+ System.out.println("In C.m()");
+ return null;
+ }
+ }
@NoHorizontalClassMerging
static class Uninstantiated {}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 5b99580..374f653 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.kotlin;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
@@ -130,16 +129,6 @@
testBuilder
.addKeepRules(keepClassMethod(mainClassName, testMethodSignature))
.addOptionsModification(disableClassInliner))
- .inspect(
- inspector -> {
- // This changes depending on when we dead-code eliminate.
- if (kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_5_0)
- || kotlinParameters.is(KotlinCompilerVersion.KOTLINC_1_6_0)
- || testParameters.isDexRuntime()) {
- checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName());
- } else {
- checkClassIsKept(inspector, TEST_DATA_CLASS.getClassName());
- }
- });
+ .inspect(inspector -> checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName()));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
index 554658a..ff134b5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
@@ -188,47 +188,46 @@
} else {
inspector
.assertIsCompleteMergeGroup(
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 1),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 2),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 3),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 4))
+ .assertIsCompleteMergeGroup(
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 0),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 9),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 10),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 11),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 12),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 13),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 21),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 22),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 23),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 24),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 25),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 26),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 27),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 28),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 29))
- .assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 1),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 2),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 3),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 4))
- .assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 3),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 20),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 21))
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 28))
.assertIsCompleteMergeGroup(
SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 0),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 14),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 15))
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 13),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 14))
.assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 7),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 8))
+ SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 1),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 15),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 16))
.assertIsCompleteMergeGroup(
SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 2),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 18),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 19))
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 17),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 18))
+ .assertIsCompleteMergeGroup(
+ SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 3),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 19),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 20))
.assertIsCompleteMergeGroup(
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 5),
SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 6))
.assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(innerClassReference, 1),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 16),
- SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 17));
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 7),
+ SyntheticItemsTestUtils.syntheticLambdaClass(mainClassReference, 8));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
index 28b5ade..3ecfe23 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
@@ -15,6 +15,8 @@
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.ArchiveResourceProvider;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
@@ -65,7 +67,7 @@
private static Path getFeatureApiPath() {
if (featureApiPath == null) {
try {
- return writeClassesToJar(FeatureAPI.class);
+ featureApiPath = writeClassesToJar(FeatureAPI.class);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -76,6 +78,8 @@
@Test
public void test() throws Exception {
Path featureCode = temp.newFile("feature.zip").toPath();
+ CodeInspector inputInspector =
+ new CodeInspector(kotlinBaseClasses.getForConfiguration(kotlinParameters));
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
.addProgramFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinAnnotationJar())
@@ -86,33 +90,7 @@
.addKeepClassAndMembersRules(featureKtClassNamet)
.addKeepClassAndMembersRules(FeatureAPI.class)
.addHorizontallyMergedClassesInspector(
- inspector -> {
- if (kotlinParameters.getLambdaGeneration().isClass()) {
- inspector
- .assertIsCompleteMergeGroup(
- "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$1",
- "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$2")
- .assertIsCompleteMergeGroup(
- "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$1",
- "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$2")
- .assertNoOtherClassesMerged();
- } else {
- ClassReference baseKt =
- Reference.classFromTypeName(
- "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt");
- ClassReference featureKt =
- Reference.classFromTypeName(
- "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt");
- inspector
- .assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(baseKt, 0),
- SyntheticItemsTestUtils.syntheticLambdaClass(baseKt, 1))
- .assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(featureKt, 0),
- SyntheticItemsTestUtils.syntheticLambdaClass(featureKt, 1))
- .assertNoOtherClassesMerged();
- }
- })
+ HorizontallyMergedClassesInspector::assertNoClassesMerged)
.setMinApi(parameters)
.addFeatureSplit(
builder ->
@@ -125,7 +103,51 @@
.allowDiagnosticWarningMessages()
.compile()
.assertAllWarningMessagesMatch(
- equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .inspect(
+ inspector -> {
+ if (kotlinParameters.getLambdaGeneration().isClass()) {
+ assertRemovedFromOutput(
+ "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$1",
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$2",
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$1",
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$2",
+ inputInspector,
+ inspector);
+ } else {
+ ClassReference baseKt =
+ Reference.classFromTypeName(
+ "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt");
+ ClassReference featureKt =
+ Reference.classFromTypeName(
+ "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt");
+ assertRemovedFromOutput(
+ SyntheticItemsTestUtils.syntheticLambdaClass(baseKt, 0),
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ SyntheticItemsTestUtils.syntheticLambdaClass(baseKt, 1),
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ SyntheticItemsTestUtils.syntheticLambdaClass(featureKt, 0),
+ inputInspector,
+ inspector);
+ assertRemovedFromOutput(
+ SyntheticItemsTestUtils.syntheticLambdaClass(featureKt, 1),
+ inputInspector,
+ inspector);
+ }
+ });
// Run the code without the feature code.
compileResult
@@ -138,4 +160,12 @@
.run(parameters.getRuntime(), baseKtClassName)
.assertSuccessWithOutputLines("1", "2", "3", "4");
}
+
+ private void assertRemovedFromOutput(
+ String clazz, CodeInspector inputInspector, CodeInspector outputInspector) {
+ assertRemovedFromOutput(Reference.classFromTypeName(clazz), inputInspector, outputInspector);
+ }
+
+ private void assertRemovedFromOutput(
+ ClassReference clazz, CodeInspector inputInspector, CodeInspector outputInspector) {}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
index d4e6cfd..c4a1eb3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
@@ -17,10 +17,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -81,37 +77,15 @@
inspector ->
inspector
.applyIf(
- splitGroup,
- i -> {
- if (kotlinParameters.getLambdaGeneration().isClass()) {
+ splitGroup && kotlinParameters.getLambdaGeneration().isClass(),
+ i ->
i.assertIsCompleteMergeGroup(
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$1",
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$2",
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$3",
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$4",
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$5",
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$6")
- .assertNoOtherClassesMerged();
- } else {
- if (parameters.getApiLevel().isEqualTo(AndroidApiLevel.B)
- && !splitGroup) {
- inspector.assertNoClassesMerged();
- } else {
- ClassReference simpleKt =
- Reference.classFromTypeName(
- "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt");
- inspector
- .assertIsCompleteMergeGroup(
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 0),
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 1),
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 2),
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 3),
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 4),
- SyntheticItemsTestUtils.syntheticLambdaClass(simpleKt, 5))
- .assertNoOtherClassesMerged();
- }
- }
- })
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$1",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$2",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$3",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$4",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$5",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$6"))
.assertNoOtherClassesMerged())
.allowDiagnosticWarningMessages()
.compile()
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
index d4b5b7f..c6fc1fa 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithSyntheticItemTest.java
@@ -6,9 +6,8 @@
import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
@@ -28,7 +27,7 @@
public static List<Object[]> data() {
return buildParameters(
ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
- getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimesAndAllApiLevels().build());
}
public RepackageWithSyntheticItemTest(
@@ -39,7 +38,7 @@
@Test
public void testRuntime() throws Exception {
testForRuntime(parameters)
- .addInnerClasses(RepackageWithSyntheticItemTest.class)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("0");
}
@@ -47,13 +46,13 @@
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
- .addInnerClasses(RepackageWithSyntheticItemTest.class)
+ .addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addKeepClassRules(I.class)
- .setMinApi(parameters)
.apply(this::configureRepackaging)
+ .enableInliningAnnotations()
.noClassInlining()
- .addInliningAnnotations()
+ .setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("0")
.inspect(
@@ -63,11 +62,13 @@
inspector.allClasses().stream()
.filter(item -> item.getFinalName().startsWith("foo"))
.collect(Collectors.toList());
- assertEquals(1, classesStartingWithfoo.size());
+ assertEquals(2, classesStartingWithfoo.size());
String expectedOriginalNamePrefix = typeName(A.class) + "$$ExternalSyntheticLambda0";
- assertThat(
- classesStartingWithfoo.get(0).getOriginalTypeName(),
- containsString(expectedOriginalNamePrefix));
+ assertTrue(
+ classesStartingWithfoo.stream()
+ .anyMatch(
+ clazz ->
+ clazz.getOriginalTypeName().contains(expectedOriginalNamePrefix)));
});
}
diff --git a/src/test/java/com/android/tools/r8/synthesis/MethodCollisionAfterSyntheticSharingTest.java b/src/test/java/com/android/tools/r8/synthesis/MethodCollisionAfterSyntheticSharingTest.java
index 31210f6..31a3057 100644
--- a/src/test/java/com/android/tools/r8/synthesis/MethodCollisionAfterSyntheticSharingTest.java
+++ b/src/test/java/com/android/tools/r8/synthesis/MethodCollisionAfterSyntheticSharingTest.java
@@ -47,6 +47,7 @@
.addOptionsModification(
options -> options.testing.enableSyntheticSharing = enableSyntheticSharing)
.enableInliningAnnotations()
+ .noClassInliningOfSynthetics()
.noHorizontalClassMergingOfSynthetics()
.setMinApi(parameters)
.compile()