Fix nondeterminism in positions from inlining
Bug: b/505807928
Change-Id: Ib9c59a0c382e2579f3791f54d2bb30f1eaec4a1d
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphBuilderBase.java
index c61cd75..40de0b5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/IRProcessingCallGraphBuilderBase.java
@@ -19,27 +19,37 @@
}
public CallGraph build(ExecutorService executorService, Timing timing) throws ExecutionException {
- timing.begin("Build IR processing order constraints");
- timing.begin("Build call graph");
- populateGraph(executorService);
- assert verifyNoRedundantFieldReadEdges();
- timing.end();
- assert verifyAllMethodsWithCodeExists();
+ try (Timing t0 = timing.begin("Build IR processing order constraints")) {
+ try (Timing t1 = timing.begin("Build call graph")) {
+ populateGraph(executorService);
+ }
+ assert verifyNoRedundantFieldReadEdges();
+ assert verifyAllMethodsWithCodeExists();
+ appView.withGeneratedMessageLiteBuilderShrinker(
+ shrinker -> shrinker.preprocessCallGraphBeforeCycleElimination(nodes));
+ runCycleEliminator(timing);
+ return new CallGraph(nodes);
+ }
+ }
- appView.withGeneratedMessageLiteBuilderShrinker(
- shrinker -> shrinker.preprocessCallGraphBeforeCycleElimination(nodes));
+ public CallGraph buildForSmallMethodInliner(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ try (Timing t0 = timing.begin("Build call graph")) {
+ populateGraph(executorService);
+ runCycleEliminator(timing);
+ return new CallGraph(nodes);
+ }
+ }
+ private void runCycleEliminator(Timing timing) {
timing.begin("Cycle elimination");
// Sort the nodes for deterministic cycle elimination.
Set<Node> nodesWithDeterministicOrder = Sets.newTreeSet(nodes.values());
CycleEliminator cycleEliminator = new CycleEliminator();
cycleEliminator.breakCycles(nodesWithDeterministicOrder);
timing.end();
- timing.end();
assert cycleEliminator.breakCycles(nodesWithDeterministicOrder).numberOfRemovedCallEdges()
== 0; // The cycles should be gone.
-
- return new CallGraph(nodes);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/smallmethodinliner/SmallMethodInliner.java b/src/main/java/com/android/tools/r8/optimize/smallmethodinliner/SmallMethodInliner.java
index abbc1ee..a974bc6 100644
--- a/src/main/java/com/android/tools/r8/optimize/smallmethodinliner/SmallMethodInliner.java
+++ b/src/main/java/com/android/tools/r8/optimize/smallmethodinliner/SmallMethodInliner.java
@@ -31,6 +31,8 @@
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
+import com.android.tools.r8.ir.conversion.callgraph.CallGraph;
+import com.android.tools.r8.ir.conversion.callgraph.PartialCallGraphBuilder;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
import com.android.tools.r8.ir.optimize.DefaultInliningOracle;
import com.android.tools.r8.ir.optimize.Inliner;
@@ -236,36 +238,55 @@
throws ExecutionException {
try (Timing t0 = timing.begin("Process callers")) {
MethodProcessor methodProcessor = createMethodProcessor();
+ ProgramMethodSet callGraphSeeds = ProgramMethodSet.createConcurrent();
ThreadUtils.processItems(
callers,
- method -> {
- IRCode code = method.buildIR(appView);
- DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView);
- Timing threadTiming = Timing.empty();
- performInlining(
- method,
- code,
- OptimizationFeedbackSimple.getInstance(),
- methodProcessor,
- threadTiming,
- this,
- this);
-
- // Only convert IR back to LIR if any methods were inlined.
- if (needsFinalization.remove(method)) {
- IRFinalizer<?> finalizer =
- code.getConversionOptions().getFinalizer(deadCodeRemover, appView);
- Code newCode =
- finalizer.finalizeCode(code, BytecodeMetadataProvider.empty(), threadTiming);
- method.setCode(newCode, appView);
+ caller -> {
+ if (methodsToInline.contains(caller)) {
+ callGraphSeeds.add(caller);
+ } else {
+ processCaller(caller, methodProcessor);
}
},
options.getThreadingModule(),
executorService);
+ if (!callGraphSeeds.isEmpty()) {
+ CallGraph callGraph =
+ new PartialCallGraphBuilder(appView, callGraphSeeds)
+ .buildForSmallMethodInliner(executorService, timing);
+ while (!callGraph.isEmpty()) {
+ ThreadUtils.processItems(
+ callGraph.extractLeaves(),
+ caller -> processCaller(caller, methodProcessor),
+ options.getThreadingModule(),
+ executorService);
+ }
+ }
assert needsFinalization.isEmpty();
}
}
+ private void processCaller(ProgramMethod method, MethodProcessor methodProcessor) {
+ IRCode code = method.buildIR(appView);
+ DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView);
+ Timing threadTiming = Timing.empty();
+ performInlining(
+ method,
+ code,
+ OptimizationFeedbackSimple.getInstance(),
+ methodProcessor,
+ threadTiming,
+ this,
+ this);
+
+ // Only convert IR back to LIR if any methods were inlined.
+ if (needsFinalization.remove(method)) {
+ IRFinalizer<?> finalizer = code.getConversionOptions().getFinalizer(deadCodeRemover, appView);
+ Code newCode = finalizer.finalizeCode(code, BytecodeMetadataProvider.empty(), threadTiming);
+ method.setCode(newCode, appView);
+ }
+ }
+
private void pruneInlinedMethods(ExecutorService executorService, Timing timing)
throws ExecutionException {
try (Timing t0 = timing.begin("Prune inlined methods")) {