Remove modeling of default parameters of Composable functions
Bug: b/302483644
Change-Id: Ie5f875d2b8b2747e3eddbf317d704a49ac339d6e
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 1290cc8..85a71d4 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -542,7 +542,7 @@
}
public ComposeReferences getComposeReferences() {
- assert testing().modelUnknownChangedAndDefaultArgumentsToComposableFunctions;
+ assert testing().modelChangedArgumentsToComposableFunctions;
if (composeReferences == null) {
composeReferences = new ComposeReferences(dexItemFactory());
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
index 567d39a..2e59422 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
@@ -86,7 +86,7 @@
// Account for the temporary hack in the Compose modeling where we create a
// DefiniteBitsNumberValue with set bits=0b1^32 and unset bits = 0b1^(31)0. This value is used
// to simulate the effect of `x | 1` in joins.
- if (testingOptions.modelUnknownChangedAndDefaultArgumentsToComposableFunctions) {
+ if (testingOptions.modelChangedArgumentsToComposableFunctions) {
boolean overlappingSetAndUnsetBits = (definitelySetBits & definitelyUnsetBits) != 0;
if (overlappingSetAndUnsetBits) {
allBitsSet = false;
@@ -95,7 +95,7 @@
if (allBitsSet) {
return createUncheckedSingleNumberValue(definitelySetBits);
}
- return new DefiniteBitsNumberValue(definitelySetBits, definitelyUnsetBits, testingOptions);
+ return new DefiniteBitsNumberValue(definitelySetBits, definitelyUnsetBits);
}
return AbstractValue.unknown();
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
index a18281e..778e61b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.OptionalBool;
import java.util.Objects;
@@ -17,10 +16,8 @@
private final int definitelySetBits;
private final int definitelyUnsetBits;
- public DefiniteBitsNumberValue(
- int definitelySetBits, int definitelyUnsetBits, TestingOptions testingOptions) {
- assert (definitelySetBits & definitelyUnsetBits) == 0
- || testingOptions.modelUnknownChangedAndDefaultArgumentsToComposableFunctions;
+ public DefiniteBitsNumberValue(int definitelySetBits, int definitelyUnsetBits) {
+ assert (definitelySetBits & definitelyUnsetBits) == 0;
this.definitelySetBits = definitelySetBits;
this.definitelyUnsetBits = definitelyUnsetBits;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerModeling.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerModeling.java
index 3e5e433..c5c3476 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerModeling.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerModeling.java
@@ -17,7 +17,7 @@
ArgumentPropagatorCodeScannerModeling(AppView<AppInfoWithLiveness> appView) {
this.composeModeling =
- appView.testing().modelUnknownChangedAndDefaultArgumentsToComposableFunctions
+ appView.testing().modelChangedArgumentsToComposableFunctions
? new ArgumentPropagatorComposeModeling(appView)
: null;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java b/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
index 332b695..8450fe3 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
@@ -38,7 +38,7 @@
private final DexString invokeName;
public ArgumentPropagatorComposeModeling(AppView<AppInfoWithLiveness> appView) {
- assert appView.testing().modelUnknownChangedAndDefaultArgumentsToComposableFunctions;
+ assert appView.testing().modelChangedArgumentsToComposableFunctions;
this.appView = appView;
this.rewrittenComposeReferences =
appView
@@ -145,92 +145,83 @@
return null;
}
- // We only model the two last arguments ($$changed and $$default) to the @Composable function.
- // If this argument is not on of these two int arguments, then don't apply any modeling.
- if (argumentIndex <= composerParameterIndex) {
+ // We only model the $$changed argument to the @Composable function.
+ if (argumentIndex != composerParameterIndex + 1) {
return null;
}
assert argument.getType().isInt();
- DexString expectedFieldName =
- !hasDefaultParameter || argumentIndex == invokedMethod.getArity() - 2
- ? rewrittenComposeReferences.changedFieldName
- : rewrittenComposeReferences.defaultFieldName;
- DexField expectedField =
+ DexField changedField =
appView
.dexItemFactory()
.createField(
- context.getHolderType(), appView.dexItemFactory().intType, expectedFieldName);
+ context.getHolderType(),
+ appView.dexItemFactory().intType,
+ rewrittenComposeReferences.changedFieldName);
UpdateChangedFlagsAbstractFunction inFlow = null;
- if (expectedFieldName.isIdenticalTo(rewrittenComposeReferences.changedFieldName)) {
- // We are looking at an argument to the $$changed parameter of the @Composable function.
- // We generally expect this argument to be defined by a call to updateChangedFlags().
- if (argument.isDefinedByInstructionSatisfying(Instruction::isInvokeStatic)) {
- InvokeStatic invokeStatic = argument.getDefinition().asInvokeStatic();
- SingleResolutionResult<?> resolutionResult =
- invokeStatic.resolveMethod(appView, context).asSingleResolution();
- if (resolutionResult == null) {
- return null;
- }
- DexClassAndMethod invokeSingleTarget =
- resolutionResult
- .lookupDispatchTarget(appView, invokeStatic, context)
- .getSingleDispatchTarget();
- if (invokeSingleTarget == null) {
- return null;
- }
- inFlow =
- invokeSingleTarget
- .getOptimizationInfo()
- .getAbstractFunction()
- .asUpdateChangedFlagsAbstractFunction();
- if (inFlow == null) {
- return null;
- }
- // By accounting for the abstract function we can safely strip the call.
- argument = invokeStatic.getFirstArgument();
+ // We are looking at an argument to the $$changed parameter of the @Composable function.
+ // We generally expect this argument to be defined by a call to updateChangedFlags().
+ if (argument.isDefinedByInstructionSatisfying(Instruction::isInvokeStatic)) {
+ InvokeStatic invokeStatic = argument.getDefinition().asInvokeStatic();
+ SingleResolutionResult<?> resolutionResult =
+ invokeStatic.resolveMethod(appView, context).asSingleResolution();
+ if (resolutionResult == null) {
+ return null;
}
- // Allow the argument to be defined by `this.$$changed | 1`.
- if (argument.isDefinedByInstructionSatisfying(Instruction::isOr)) {
- Or or = argument.getDefinition().asOr();
- Value maybeNumberOperand =
- or.leftValue().isConstNumber() ? or.leftValue() : or.rightValue();
- Value otherOperand = or.getOperand(1 - or.inValues().indexOf(maybeNumberOperand));
- if (!maybeNumberOperand.isConstNumber(1)) {
- return null;
- }
- // Strip the OR instruction.
- argument = otherOperand;
- // Update the model from bottom to a special value that effectively throws away any known
- // information about the lowermost bit of $$changed.
- SingleNumberValue one =
- appView.abstractValueFactory().createSingleNumberValue(1, TypeElement.getInt());
- inFlow =
- new UpdateChangedFlagsAbstractFunction(
- new OrAbstractFunction(new FieldValue(expectedField), one));
- } else {
- inFlow = new UpdateChangedFlagsAbstractFunction(new FieldValue(expectedField));
+ DexClassAndMethod invokeSingleTarget =
+ resolutionResult
+ .lookupDispatchTarget(appView, invokeStatic, context)
+ .getSingleDispatchTarget();
+ if (invokeSingleTarget == null) {
+ return null;
}
+ inFlow =
+ invokeSingleTarget
+ .getOptimizationInfo()
+ .getAbstractFunction()
+ .asUpdateChangedFlagsAbstractFunction();
+ if (inFlow == null) {
+ return null;
+ }
+ // By accounting for the abstract function we can safely strip the call.
+ argument = invokeStatic.getFirstArgument();
+ }
+ // Allow the argument to be defined by `this.$$changed | 1`.
+ if (argument.isDefinedByInstructionSatisfying(Instruction::isOr)) {
+ Or or = argument.getDefinition().asOr();
+ Value maybeNumberOperand = or.leftValue().isConstNumber() ? or.leftValue() : or.rightValue();
+ Value otherOperand = or.getOperand(1 - or.inValues().indexOf(maybeNumberOperand));
+ if (!maybeNumberOperand.isConstNumber(1)) {
+ return null;
+ }
+ // Strip the OR instruction.
+ argument = otherOperand;
+ // Update the model from bottom to a special value that effectively throws away any known
+ // information about the lowermost bit of $$changed.
+ SingleNumberValue one =
+ appView.abstractValueFactory().createSingleNumberValue(1, TypeElement.getInt());
+ inFlow =
+ new UpdateChangedFlagsAbstractFunction(
+ new OrAbstractFunction(new FieldValue(changedField), one));
+ } else {
+ inFlow = new UpdateChangedFlagsAbstractFunction(new FieldValue(changedField));
}
- // At this point we expect that the restart lambda is reading either this.$$changed or
- // this.$$default using an instance-get.
+ // At this point we expect that the restart lambda is reading this.$$changed using an
+ // instance-get.
if (!argument.isDefinedByInstructionSatisfying(Instruction::isInstanceGet)) {
return null;
}
// Check that the instance-get is reading the capture field that we expect it to.
InstanceGet instanceGet = argument.getDefinition().asInstanceGet();
- if (!instanceGet.getField().isIdenticalTo(expectedField)) {
+ if (!instanceGet.getField().isIdenticalTo(changedField)) {
return null;
}
- // Return the argument model. Note that, for the $$default field, this is always bottom, which
- // is equivalent to modeling that this call does not contribute any new argument information.
- return inFlow != null
- ? new ConcretePrimitiveTypeValueState(inFlow)
- : ValueState.bottomPrimitiveTypeParameter();
+ // Return the argument model.
+ return new ConcretePrimitiveTypeValueState(inFlow);
}
}
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
index 1c23e06..3da6f3b 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposableOptimizationPass.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ComposableOptimizationPass.java
@@ -41,7 +41,7 @@
}
TestingOptions testingOptions = options.getTestingOptions();
if (!testingOptions.enableComposableOptimizationPass
- || !testingOptions.modelUnknownChangedAndDefaultArgumentsToComposableFunctions) {
+ || !testingOptions.modelChangedArgumentsToComposableFunctions) {
return;
}
timing.time(
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposeReferences.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposeReferences.java
index e441188..e38f9a4 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposeReferences.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ComposeReferences.java
@@ -12,7 +12,6 @@
public class ComposeReferences {
public final DexString changedFieldName;
- public final DexString defaultFieldName;
public final DexType composableType;
public final DexType composerType;
@@ -21,7 +20,6 @@
public ComposeReferences(DexItemFactory factory) {
changedFieldName = factory.createString("$$changed");
- defaultFieldName = factory.createString("$$default");
composableType = factory.createType("Landroidx/compose/runtime/Composable;");
composerType = factory.createType("Landroidx/compose/runtime/Composer;");
@@ -35,12 +33,10 @@
public ComposeReferences(
DexString changedFieldName,
- DexString defaultFieldName,
DexType composableType,
DexType composerType,
DexMethod updatedChangedFlagsMethod) {
this.changedFieldName = changedFieldName;
- this.defaultFieldName = defaultFieldName;
this.composableType = composableType;
this.composerType = composerType;
this.updatedChangedFlagsMethod = updatedChangedFlagsMethod;
@@ -49,7 +45,6 @@
public ComposeReferences rewrittenWithLens(GraphLens graphLens, GraphLens codeLens) {
return new ComposeReferences(
changedFieldName,
- defaultFieldName,
graphLens.lookupClassType(composableType, codeLens),
graphLens.lookupClassType(composerType, codeLens),
graphLens.getRenamedMethodSignature(updatedChangedFlagsMethod, codeLens));
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 40e2beb..4254412 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -334,7 +334,7 @@
AnnotatedKind kind,
Mode mode,
InternalOptions options) {
- return options.testing.modelUnknownChangedAndDefaultArgumentsToComposableFunctions
+ return options.testing.modelChangedArgumentsToComposableFunctions
&& mode.isInitialTreeShaking()
&& kind.isMethod()
&& annotation
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 7b83b69..a00cd5b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -2392,10 +2392,9 @@
public boolean enableComposableOptimizationPass =
SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault(
"com.android.tools.r8.enableComposableOptimizationPass", false);
- public boolean modelUnknownChangedAndDefaultArgumentsToComposableFunctions =
+ public boolean modelChangedArgumentsToComposableFunctions =
SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault(
- "com.android.tools.r8.modelUnknownChangedAndDefaultArgumentsToComposableFunctions",
- false);
+ "com.android.tools.r8.modelChangedArgumentsToComposableFunctions", false);
// Flag to allow processing of resources in D8. A data resource consumer still needs to be
// specified.
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 d056f65..7ca99c9 100644
--- a/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/compose/NestedComposableArgumentPropagationTest.java
@@ -117,7 +117,7 @@
options -> {
options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces();
options.testing.enableComposableOptimizationPass = enableComposeOptimizations;
- options.testing.modelUnknownChangedAndDefaultArgumentsToComposableFunctions =
+ options.testing.modelChangedArgumentsToComposableFunctions =
enableComposeOptimizations;
})
.setMinApi(AndroidApiLevel.N)