Remove Composable optimization pass
Change-Id: I90cbba0d7e7650d1cc651873b7067f4c64441841
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 f5c3538..fd87cbc 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
@@ -864,10 +864,6 @@
appView.withArgumentPropagator(
argumentPropagator -> argumentPropagator.scan(method, code, methodProcessor, timing));
- if (methodProcessor.isComposeMethodProcessor()) {
- methodProcessor.asComposeMethodProcessor().scan(method, code, timing);
- }
-
if (methodProcessor.isPrimaryMethodProcessor()) {
enumUnboxer.analyzeEnums(code, methodProcessor);
numberUnboxer.analyze(code);
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 9eb24e1..9c8b286 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
@@ -5,18 +5,9 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
-import com.android.tools.r8.optimize.compose.ComposeMethodProcessor;
public abstract class MethodProcessor {
- public boolean isComposeMethodProcessor() {
- return false;
- }
-
- public ComposeMethodProcessor asComposeMethodProcessor() {
- return null;
- }
-
public boolean isD8MethodProcessor() {
return false;
}
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 3b3ba7a..d25c1b5 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
@@ -15,7 +15,6 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.naming.IdentifierMinifier;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
-import com.android.tools.r8.optimize.compose.ComposableOptimizationPass;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -224,8 +223,6 @@
identifierNameStringMarker.decoupleIdentifierNameStringsInFields(executorService);
}
- ComposableOptimizationPass.run(appView, this, executorService, timing);
-
// Assure that no more optimization feedback left after post processing.
assert feedback.noUpdatesLeft();
return appView.appInfo().app();
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorCodeScannerForComposableFunctions.java b/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorCodeScannerForComposableFunctions.java
deleted file mode 100644
index 371af3d..0000000
--- a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorCodeScannerForComposableFunctions.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize.compose;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.path.PathConstraintSupplier;
-import com.android.tools.r8.ir.code.AbstractValueSupplier;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorCodeScanner;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.Timing;
-
-public class ArgumentPropagatorCodeScannerForComposableFunctions
- extends ArgumentPropagatorCodeScanner {
-
- private final ComposableCallGraph callGraph;
-
- public ArgumentPropagatorCodeScannerForComposableFunctions(
- AppView<AppInfoWithLiveness> appView, ComposableCallGraph callGraph) {
- super(appView);
- this.callGraph = callGraph;
- }
-
- @Override
- public void scan(
- ProgramMethod method,
- IRCode code,
- AbstractValueSupplier abstractValueSupplier,
- PathConstraintSupplier pathConstraintSupplier,
- Timing timing) {
- new CodeScanner(abstractValueSupplier, code, method, pathConstraintSupplier).scan(timing);
- }
-
- @Override
- protected boolean isMethodParameterAlreadyUnknown(
- DexType staticType, MethodParameter methodParameter, ProgramMethod method) {
- // We haven't defined the virtual root mapping, so we can't tell.
- return false;
- }
-
- private class CodeScanner extends ArgumentPropagatorCodeScanner.CodeScanner {
-
- protected CodeScanner(
- AbstractValueSupplier abstractValueSupplier,
- IRCode code,
- ProgramMethod method,
- PathConstraintSupplier pathConstraintSupplier) {
- super(abstractValueSupplier, code, method, pathConstraintSupplier);
- }
-
- @Override
- protected void addTemporaryMethodState(
- InvokeMethod invoke, ProgramMethod resolvedMethod, Timing timing) {
- ComposableCallGraphNode node = callGraph.getNodes().get(resolvedMethod);
- if (node != null && node.isComposable()) {
- super.addTemporaryMethodState(invoke, resolvedMethod, timing);
- }
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraph.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraph.java
deleted file mode 100644
index 8364488..0000000
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraph.java
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize.compose;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.Code;
-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.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.collections.ProgramMethodMap;
-import java.util.function.Consumer;
-
-/**
- * A partial call graph that stores call edges to @Composable functions. By processing all the call
- * sites of a given @Composable function we can reapply arguent propagation for the @Composable
- * function.
- */
-public class ComposableCallGraph {
-
- private final ProgramMethodMap<ComposableCallGraphNode> nodes;
-
- public ComposableCallGraph(ProgramMethodMap<ComposableCallGraphNode> nodes) {
- this.nodes = nodes;
- }
-
- public static Builder builder(AppView<AppInfoWithLiveness> appView) {
- return new Builder(appView);
- }
-
- public static ComposableCallGraph empty() {
- return new ComposableCallGraph(ProgramMethodMap.empty());
- }
-
- public void forEachNode(Consumer<ComposableCallGraphNode> consumer) {
- nodes.forEachValue(consumer);
- }
-
- public ProgramMethodMap<ComposableCallGraphNode> getNodes() {
- return nodes;
- }
-
- public boolean isEmpty() {
- return nodes.isEmpty();
- }
-
- public static class Builder {
-
- private final AppView<AppInfoWithLiveness> appView;
- private final ProgramMethodMap<ComposableCallGraphNode> nodes = ProgramMethodMap.create();
-
- Builder(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- public ComposableCallGraph build() {
- createCallGraphNodesForComposableFunctions();
- if (!nodes.isEmpty()) {
- addCallEdgesToComposableFunctions();
- }
- return new ComposableCallGraph(nodes);
- }
-
- private void createCallGraphNodesForComposableFunctions() {
- ComposeReferences rewrittenComposeReferences =
- appView
- .getComposeReferences()
- .rewrittenWithLens(appView.graphLens(), GraphLens.getIdentityLens());
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachProgramDirectMethodMatching(
- method -> method.annotations().hasAnnotation(rewrittenComposeReferences.composableType),
- method -> {
- // TODO(b/302483644): Don't include kept @Composable functions, since we can't
- // optimize them anyway.
- assert method.getAccessFlags().isStatic();
- nodes.put(method, new ComposableCallGraphNode(method, true));
- });
- }
- }
-
- // TODO(b/302483644): Parallelize identification of @Composable call sites.
- private void addCallEdgesToComposableFunctions() {
- // Code is fully rewritten so no need to lens rewrite in registry.
- assert appView.graphLens().isMemberRebindingIdentityLens();
- assert appView.codeLens() == appView.graphLens().asNonIdentityLens().getPrevious();
-
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachProgramMethodMatching(
- DexEncodedMethod::hasCode,
- method -> {
- Code code = method.getDefinition().getCode();
-
- // TODO(b/302483644): Leverage LIR code constant pool for efficient checking.
- // TODO(b/302483644): Maybe remove the possibility of CF/DEX at this point.
- assert code.isLirCode()
- || code.isCfCode()
- || code.isDexCode()
- || code.isDefaultInstanceInitializerCode()
- || code.isThrowNullCode();
-
- code.registerCodeReferences(
- method,
- new UseRegistry<>(appView, method) {
-
- private final AppView<AppInfoWithLiveness> appViewWithLiveness =
- appView.withLiveness();
-
- @Override
- public void registerInvokeStatic(DexMethod method) {
- ProgramMethod resolvedMethod =
- appViewWithLiveness
- .appInfo()
- .unsafeResolveMethodDueToDexFormat(method)
- .getResolvedProgramMethod();
- if (resolvedMethod == null) {
- return;
- }
-
- ComposableCallGraphNode callee = nodes.get(resolvedMethod);
- if (callee == null || !callee.isComposable()) {
- // Only record calls to Composable functions.
- return;
- }
-
- ComposableCallGraphNode caller =
- nodes.computeIfAbsent(
- getContext(), context -> new ComposableCallGraphNode(context, false));
- callee.addCaller(caller);
- }
-
- @Override
- public void registerInitClass(DexType type) {}
-
- @Override
- public void registerInvokeDirect(DexMethod method) {}
-
- @Override
- public void registerInvokeInterface(DexMethod method) {}
-
- @Override
- public void registerInvokeSuper(DexMethod method) {}
-
- @Override
- public void registerInvokeVirtual(DexMethod method) {}
-
- @Override
- public void registerInstanceFieldRead(DexField field) {}
-
- @Override
- public void registerInstanceFieldWrite(DexField field) {}
-
- @Override
- public void registerStaticFieldRead(DexField field) {}
-
- @Override
- public void registerStaticFieldWrite(DexField field) {}
-
- @Override
- public void registerTypeReference(DexType type) {}
- });
- });
- }
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraphNode.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraphNode.java
deleted file mode 100644
index 13ec14db..0000000
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposableCallGraphNode.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize.compose;
-
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.utils.SetUtils;
-import java.util.Set;
-import java.util.function.Consumer;
-
-public class ComposableCallGraphNode {
-
- private final ProgramMethod method;
- private final boolean isComposable;
-
- private final Set<ComposableCallGraphNode> callers = SetUtils.newIdentityHashSet();
- private final Set<ComposableCallGraphNode> callees = SetUtils.newIdentityHashSet();
-
- ComposableCallGraphNode(ProgramMethod method, boolean isComposable) {
- this.method = method;
- this.isComposable = isComposable;
- }
-
- public void addCaller(ComposableCallGraphNode caller) {
- callers.add(caller);
- caller.callees.add(this);
- }
-
- public void forEachComposableCallee(Consumer<ComposableCallGraphNode> consumer) {
- for (ComposableCallGraphNode callee : callees) {
- if (callee.isComposable()) {
- consumer.accept(callee);
- }
- }
- }
-
- public Set<ComposableCallGraphNode> getCallers() {
- return callers;
- }
-
- public ProgramMethod getMethod() {
- return method;
- }
-
- public boolean isComposable() {
- return isComposable;
- }
-
- @Override
- public String toString() {
- return method.toString();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposableOptimizationPass.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposableOptimizationPass.java
deleted file mode 100644
index c2890d8..0000000
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposableOptimizationPass.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize.compose;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.ir.conversion.PrimaryR8IRConverter;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-public class ComposableOptimizationPass {
-
- private final AppView<AppInfoWithLiveness> appView;
- private final PrimaryR8IRConverter converter;
-
- private ComposableOptimizationPass(
- AppView<AppInfoWithLiveness> appView, PrimaryR8IRConverter converter) {
- this.appView = appView;
- this.converter = converter;
- }
-
- public static void run(
- AppView<AppInfoWithLiveness> appView,
- PrimaryR8IRConverter converter,
- ExecutorService executorService,
- Timing timing)
- throws ExecutionException {
- if (appView.options().getJetpackComposeOptions().isComposableOptimizationPassEnabled()) {
- timing.time(
- "ComposableOptimizationPass",
- () -> new ComposableOptimizationPass(appView, converter).processWaves(executorService));
- }
- }
-
- void processWaves(ExecutorService executorService) throws ExecutionException {
- ComposableCallGraph callGraph = ComposableCallGraph.builder(appView).build();
- ComposeMethodProcessor methodProcessor =
- new ComposeMethodProcessor(appView, callGraph, converter);
- Set<ComposableCallGraphNode> wave = createInitialWave(callGraph);
- while (!wave.isEmpty()) {
- Set<ComposableCallGraphNode> optimizedComposableFunctions =
- methodProcessor.processWave(wave, executorService);
- wave = createNextWave(methodProcessor, optimizedComposableFunctions);
- }
- }
-
- // TODO(b/302483644): Should we skip root @Composable functions that don't have any nested
- // @Composable functions (?).
- private Set<ComposableCallGraphNode> computeComposableRoots(ComposableCallGraph callGraph) {
- Set<ComposableCallGraphNode> composableRoots = Sets.newIdentityHashSet();
- callGraph.forEachNode(
- node -> {
- if (!node.isComposable()
- || Iterables.any(node.getCallers(), ComposableCallGraphNode::isComposable)) {
- // This is not a @Composable root.
- return;
- }
- if (node.getCallers().isEmpty()) {
- // Don't include root @Composable functions that are never called. These are either kept
- // or will be removed in tree shaking.
- return;
- }
- composableRoots.add(node);
- });
- return composableRoots;
- }
-
- private Set<ComposableCallGraphNode> createInitialWave(ComposableCallGraph callGraph) {
- Set<ComposableCallGraphNode> wave = Sets.newIdentityHashSet();
- Set<ComposableCallGraphNode> composableRoots = computeComposableRoots(callGraph);
- composableRoots.forEach(composableRoot -> wave.addAll(composableRoot.getCallers()));
- return wave;
- }
-
- // TODO(b/302483644): Consider repeatedly extracting the roots from the graph similar to the way
- // we extract leaves in the primary optimization pass.
- private static Set<ComposableCallGraphNode> createNextWave(
- ComposeMethodProcessor methodProcessor,
- Set<ComposableCallGraphNode> optimizedComposableFunctions) {
- Set<ComposableCallGraphNode> nextWave =
- SetUtils.newIdentityHashSet(optimizedComposableFunctions);
-
- // If the new wave contains two @Composable functions where one calls the other, then defer the
- // processing of the callee to a later wave, to ensure that we have seen all of its callers
- // before processing the callee.
- List<ComposableCallGraphNode> deferredComposableFunctions = new ArrayList<>();
- nextWave.forEach(
- node -> {
- if (SetUtils.containsAnyOf(nextWave, node.getCallers())) {
- deferredComposableFunctions.add(node);
- }
- });
- deferredComposableFunctions.forEach(nextWave::remove);
-
- // To optimize the @Composable functions that are called from the @Composable functions of the
- // next wave in the wave after that, we need to include their callers in the next wave as well.
- Set<ComposableCallGraphNode> callersOfCalledComposableFunctions = Sets.newIdentityHashSet();
- nextWave.forEach(
- node ->
- node.forEachComposableCallee(
- callee -> callersOfCalledComposableFunctions.addAll(callee.getCallers())));
- nextWave.addAll(callersOfCalledComposableFunctions);
- nextWave.removeIf(methodProcessor::isProcessed);
- return nextWave;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java
deleted file mode 100644
index 9e8bd8d..0000000
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.optimize.compose;
-
-import static com.android.tools.r8.graph.ProgramField.asProgramFieldOrNull;
-
-import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramField;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
-import com.android.tools.r8.ir.analysis.path.PathConstraintSupplier;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.code.AbstractValueSupplier;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions;
-import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
-import com.android.tools.r8.ir.conversion.PrimaryR8IRConverter;
-import com.android.tools.r8.ir.conversion.callgraph.CallSiteInformation;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorCodeScanner;
-import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorOptimizationInfoPopulator;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePrimitiveTypeValueState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
-import com.android.tools.r8.optimize.argumentpropagation.propagation.DefaultFieldValueJoiner;
-import com.android.tools.r8.optimize.argumentpropagation.propagation.FlowGraph;
-import com.android.tools.r8.optimize.argumentpropagation.propagation.InFlowPropagator;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.LazyBox;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.TraversalUtils;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-public class ComposeMethodProcessor extends MethodProcessor {
-
- private final AppView<AppInfoWithLiveness> appView;
- private final ArgumentPropagatorCodeScanner codeScanner;
- private final PrimaryR8IRConverter converter;
-
- private final Set<ComposableCallGraphNode> processed = Sets.newIdentityHashSet();
-
- public ComposeMethodProcessor(
- AppView<AppInfoWithLiveness> appView,
- ComposableCallGraph callGraph,
- PrimaryR8IRConverter converter) {
- this.appView = appView;
- this.codeScanner = new ArgumentPropagatorCodeScannerForComposableFunctions(appView, callGraph);
- this.converter = converter;
- }
-
- public Set<ComposableCallGraphNode> processWave(
- Set<ComposableCallGraphNode> wave, ExecutorService executorService)
- throws ExecutionException {
- ProcessorContext processorContext = appView.createProcessorContext();
- ThreadUtils.processItems(
- wave,
- node -> {
- assert !processed.contains(node);
- converter.processDesugaredMethod(
- node.getMethod(),
- OptimizationFeedback.getIgnoreFeedback(),
- this,
- processorContext.createMethodProcessingContext(node.getMethod()),
- MethodConversionOptions.forLirPhase(appView));
- },
- appView.options().getThreadingModule(),
- executorService);
- processed.addAll(wave);
- return optimizeComposableFunctionsCalledFromWave(wave, executorService);
- }
-
- private Set<ComposableCallGraphNode> optimizeComposableFunctionsCalledFromWave(
- Set<ComposableCallGraphNode> wave, ExecutorService executorService)
- throws ExecutionException {
- prepareForInFlowPropagator();
-
- InFlowComparator emptyComparator = InFlowComparator.builder().build();
- InFlowPropagator inFlowPropagator =
- new InFlowPropagator(
- appView,
- null,
- converter,
- codeScanner.getFieldStates(),
- codeScanner.getMethodStates(),
- emptyComparator) {
-
- @Override
- protected DefaultFieldValueJoiner createDefaultFieldValueJoiner(
- List<FlowGraph> flowGraphs) {
- return new DefaultFieldValueJoiner(appView, null, fieldStates, flowGraphs) {
-
- @Override
- protected Map<DexProgramClass, List<ProgramField>> getFieldsOfInterest() {
- // We do not rely on the optimization of any fields in the Composable optimization
- // pass.
- return Collections.emptyMap();
- }
- };
- }
- };
- inFlowPropagator.run(executorService);
-
- ArgumentPropagatorOptimizationInfoPopulator optimizationInfoPopulator =
- new ArgumentPropagatorOptimizationInfoPopulator(appView, null, null, null, null);
- Set<ComposableCallGraphNode> optimizedComposableFunctions = Sets.newIdentityHashSet();
- wave.forEach(
- node ->
- node.forEachComposableCallee(
- callee -> {
- if (Iterables.all(callee.getCallers(), this::isProcessed)) {
- optimizationInfoPopulator.setOptimizationInfo(
- callee.getMethod(), ProgramMethodSet.empty(), getMethodState(callee));
- // TODO(b/302483644): Only enqueue this callee if its optimization info changed.
- optimizedComposableFunctions.add(callee);
- }
- }));
- return optimizedComposableFunctions;
- }
-
- private void prepareForInFlowPropagator() {
- FieldStateCollection fieldStates = codeScanner.getFieldStates();
-
- // Set all field states to unknown since we are not guaranteed to have processes all field
- // writes.
- fieldStates.forEach(
- (field, fieldState) ->
- fieldStates.addTemporaryFieldState(
- appView, field, ValueState::unknown, Timing.empty()));
-
- // Widen all parameter states that have in-flow to unknown, except when the in-flow is an
- // update-changed-flags abstract function.
- MethodStateCollectionByReference methodStates = codeScanner.getMethodStates();
- methodStates.forEach(
- (method, methodState) -> {
- if (!methodState.isMonomorphic()) {
- assert methodState.isUnknown();
- return;
- }
- ConcreteMonomorphicMethodState monomorphicMethodState = methodState.asMonomorphic();
- for (int parameterIndex = 0;
- parameterIndex < monomorphicMethodState.size();
- parameterIndex++) {
- ValueState parameterState = monomorphicMethodState.getParameterState(parameterIndex);
- if (parameterState.isConcrete()) {
- ConcreteValueState concreteParameterState = parameterState.asConcrete();
- prepareParameterStateForInFlowPropagator(
- method, monomorphicMethodState, parameterIndex, concreteParameterState);
- }
- }
- });
- }
-
- private void prepareParameterStateForInFlowPropagator(
- DexMethod method,
- ConcreteMonomorphicMethodState methodState,
- int parameterIndex,
- ConcreteValueState parameterState) {
- if (!parameterState.hasInFlow()) {
- return;
- }
-
- UpdateChangedFlagsAbstractFunction transferFunction;
- if (parameterState.getInFlow().size() == 1) {
- transferFunction =
- Iterables.getOnlyElement(parameterState.getInFlow())
- .asUpdateChangedFlagsAbstractFunction();
- } else {
- transferFunction = null;
- }
- if (transferFunction == null) {
- methodState.setParameterState(parameterIndex, ValueState.unknown());
- return;
- }
-
- // This is a call to a composable function from a restart function.
- assert TraversalUtils.isSingleton(transferFunction::traverseBaseInFlow);
- BaseInFlow baseInFlow = TraversalUtils.getFirst(transferFunction::traverseBaseInFlow);
- ProgramField field =
- asProgramFieldOrNull(appView.definitionFor(baseInFlow.asFieldValue().getField()));
- assert field != null;
-
- // If the only input to the $$changed parameter of the Composable function is in-flow then skip.
- if (methodState.getParameterState(parameterIndex).getAbstractValue(appView).isBottom()) {
- methodState.setParameterState(parameterIndex, ValueState.unknown());
- return;
- }
-
- codeScanner
- .getFieldStates()
- .addTemporaryFieldState(
- appView,
- field,
- () ->
- new ConcretePrimitiveTypeValueState(
- MethodParameter.createStatic(method, parameterIndex)),
- Timing.empty());
- }
-
- private MethodState getMethodState(ComposableCallGraphNode node) {
- assert processed.containsAll(node.getCallers());
- return codeScanner.getMethodStates().get(node.getMethod());
- }
-
- public void scan(ProgramMethod method, IRCode code, Timing timing) {
- LazyBox<Map<Value, AbstractValue>> abstractValues =
- new LazyBox<>(() -> new SparseConditionalConstantPropagation(appView).analyze(code));
- AbstractValueSupplier abstractValueSupplier =
- value -> {
- AbstractValue abstractValue = abstractValues.computeIfAbsent().get(value);
- assert abstractValue != null;
- return abstractValue;
- };
- PathConstraintSupplier pathConstraintSupplier =
- new PathConstraintSupplier(appView, code, codeScanner.getMethodParameterFactory());
- codeScanner.scan(method, code, abstractValueSupplier, pathConstraintSupplier, timing);
- }
-
- public boolean isProcessed(ComposableCallGraphNode node) {
- return processed.contains(node);
- }
-
- @Override
- public CallSiteInformation getCallSiteInformation() {
- return CallSiteInformation.empty();
- }
-
- @Override
- public MethodProcessorEventConsumer getEventConsumer() {
- throw new Unreachable();
- }
-
- @Override
- public boolean isComposeMethodProcessor() {
- return true;
- }
-
- @Override
- public ComposeMethodProcessor asComposeMethodProcessor() {
- return this;
- }
-
- @Override
- public boolean isProcessedConcurrently(ProgramMethod method) {
- return false;
- }
-
- @Override
- public void scheduleDesugaredMethodForProcessing(ProgramMethod method) {
- throw new Unreachable();
- }
-
- @Override
- public boolean shouldApplyCodeRewritings(ProgramMethod method) {
- return false;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/JetpackComposeOptions.java b/src/main/java/com/android/tools/r8/optimize/compose/JetpackComposeOptions.java
index 69ec5e6..65a8199 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/JetpackComposeOptions.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/JetpackComposeOptions.java
@@ -10,10 +10,6 @@
private final InternalOptions options;
- public boolean enableComposableOptimizationPass =
- SystemPropertyUtils.parseSystemPropertyOrDefault(
- "com.android.tools.r8.jetpackcompose.enableComposableOptimizationPass", false);
-
public boolean enableModelingOfChangedArguments =
SystemPropertyUtils.parseSystemPropertyOrDefault(
"com.android.tools.r8.jetpackcompose.enableModelingOfChangedArguments", false);
@@ -22,20 +18,6 @@
this.options = options;
}
- public void enableAllOptimizations(boolean enable) {
- enableComposableOptimizationPass = enable;
- enableModelingOfChangedArguments = enable;
- }
-
- public boolean isAnyOptimizationsEnabled() {
- return isComposableOptimizationPassEnabled()
- || isModelingChangedArgumentsToComposableFunctions();
- }
-
- public boolean isComposableOptimizationPassEnabled() {
- return isModelingChangedArgumentsToComposableFunctions() && enableComposableOptimizationPass;
- }
-
public boolean isModelingChangedArgumentsToComposableFunctions() {
return options.isOptimizing() && options.isShrinking() && enableModelingOfChangedArguments;
}
diff --git a/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java
index 7c40462..b45d46d 100644
--- a/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.compose;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -40,7 +41,23 @@
enum ComposableFunction {
A,
B,
- C
+ C;
+
+ public int getExpectedNumberOfIfInstructions() {
+ switch (this) {
+ case A:
+ // TODO(b/302281503): Should be 5.
+ return 7;
+ case B:
+ // TODO(b/302281503): Should be 5.
+ return 7;
+ case C:
+ // TODO(b/302281503): Should be 3.
+ return 5;
+ default:
+ throw new Unreachable();
+ }
+ }
}
static class CodeStats {
@@ -76,24 +93,15 @@
@Test
public void test() throws Exception {
- EnumMap<ComposableFunction, CodeStats> defaultCodeStats = build(false);
- EnumMap<ComposableFunction, CodeStats> optimizedCodeStats = build(true);
+ EnumMap<ComposableFunction, CodeStats> result = build();
for (ComposableFunction composableFunction : ComposableFunction.values()) {
- CodeStats defaultCodeStatsForFunction = defaultCodeStats.get(composableFunction);
- CodeStats optimizedCodeStatsForFunction = optimizedCodeStats.get(composableFunction);
- assertTrue(
- composableFunction
- + ": "
- + defaultCodeStatsForFunction.numberOfIfInstructions
- + " vs "
- + optimizedCodeStatsForFunction.numberOfIfInstructions,
- defaultCodeStatsForFunction.numberOfIfInstructions
- > optimizedCodeStatsForFunction.numberOfIfInstructions);
+ CodeStats codeStats = result.get(composableFunction);
+ assertEquals(
+ composableFunction.getExpectedNumberOfIfInstructions(), codeStats.numberOfIfInstructions);
}
}
- private EnumMap<ComposableFunction, CodeStats> build(boolean enableComposeOptimizations)
- throws Exception {
+ private EnumMap<ComposableFunction, CodeStats> build() throws Exception {
Box<ClassReference> mainActivityKtClassReference =
new Box<>(Reference.classFromTypeName("com.example.MainActivityKt"));
R8TestCompileResult compileResult =
@@ -114,12 +122,7 @@
updateMainActivityKt(
MinificationInspector::getTarget, mainActivityKtClassReference, true))
.addOptionsModification(
- options -> {
- options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
- options
- .getJetpackComposeOptions()
- .enableAllOptimizations(enableComposeOptimizations);
- })
+ options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.setMinApi(AndroidApiLevel.N)
.allowDiagnosticMessages()
.allowUnnecessaryDontWarnWildcards()