Add @KeepUnusedReturnValue testing annotation Change-Id: I7f5d6dd476c1e3b44a79159348f1aaa69581a283
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java index f8d617b..470e442 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -32,6 +32,7 @@ import com.android.tools.r8.optimize.argumentpropagation.propagation.VirtualDispatchMethodArgumentPropagator; import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils; import com.android.tools.r8.shaking.AppInfoWithLiveness; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.ListUtils; import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.Timing; @@ -50,6 +51,7 @@ private final AppView<AppInfoWithLiveness> appView; private final MethodStateCollectionByReference methodStates; + private final InternalOptions options; private final ImmediateProgramSubtypingInfo immediateSubtypingInfo; private final List<Set<DexProgramClass>> stronglyConnectedProgramComponents; @@ -66,6 +68,7 @@ this.appView = appView; this.immediateSubtypingInfo = immediateSubtypingInfo; this.methodStates = methodStates; + this.options = appView.options(); this.stronglyConnectedProgramComponents = stronglyConnectedProgramComponents; this.interfaceDispatchOutsideProgram = interfaceDispatchOutsideProgram; } @@ -158,7 +161,7 @@ } // Do not optimize @KeepConstantArgument methods. - if (appView.appInfo().isKeepConstantArgumentsMethod(method)) { + if (!appView.getKeepInfo(method).isConstantArgumentOptimizationAllowed(options)) { methodState = MethodState.unknown(); } @@ -215,7 +218,7 @@ private MethodState getMethodStateAfterUninstantiatedParameterRemoval( ProgramMethod method, MethodState methodState) { assert methodState.isMonomorphic() || methodState.isUnknown(); - if (appView.appInfo().isKeepConstantArgumentsMethod(method)) { + if (!appView.getKeepInfo(method).isConstantArgumentOptimizationAllowed(options)) { return methodState; }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java index 72129db..34d8967 100644 --- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java +++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
@@ -19,7 +19,7 @@ if (!keepInfo.isParameterRemovalAllowed(options)) { return false; } - if (appView.appInfo().isKeepUnusedArgumentsMethod(method)) { + if (!appView.getKeepInfo(method).isUnusedArgumentOptimizationAllowed(options)) { return false; } return method.getDefinition().isLibraryMethodOverride().isFalse()
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java index 78c8797..e156407 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -153,10 +153,6 @@ private final Set<DexMethod> neverInlineDueToSingleCaller; /** Items for which to print inlining decisions for (testing only). */ private final Set<DexMethod> whyAreYouNotInlining; - /** All methods that may not have any parameters with a constant value removed. */ - private final Set<DexMethod> keepConstantArguments; - /** All methods that may not have any unused arguments removed. */ - private final Set<DexMethod> keepUnusedArguments; /** All methods that must be reprocessed (testing only). */ private final Set<DexMethod> reprocess; /** All methods that must not be reprocessed (testing only). */ @@ -228,8 +224,6 @@ Set<DexMethod> alwaysInline, Set<DexMethod> neverInlineDueToSingleCaller, Set<DexMethod> whyAreYouNotInlining, - Set<DexMethod> keepConstantArguments, - Set<DexMethod> keepUnusedArguments, Set<DexMethod> reprocess, Set<DexMethod> neverReprocess, PredicateSet<DexType> alwaysClassInline, @@ -265,8 +259,6 @@ this.alwaysInline = alwaysInline; this.neverInlineDueToSingleCaller = neverInlineDueToSingleCaller; this.whyAreYouNotInlining = whyAreYouNotInlining; - this.keepConstantArguments = keepConstantArguments; - this.keepUnusedArguments = keepUnusedArguments; this.reprocess = reprocess; this.neverReprocess = neverReprocess; this.alwaysClassInline = alwaysClassInline; @@ -310,8 +302,6 @@ previous.alwaysInline, previous.neverInlineDueToSingleCaller, previous.whyAreYouNotInlining, - previous.keepConstantArguments, - previous.keepUnusedArguments, previous.reprocess, previous.neverReprocess, previous.alwaysClassInline, @@ -360,8 +350,6 @@ pruneMethods(previous.alwaysInline, prunedItems, executorService, futures), pruneMethods(previous.neverInlineDueToSingleCaller, prunedItems, executorService, futures), pruneMethods(previous.whyAreYouNotInlining, prunedItems, executorService, futures), - pruneMethods(previous.keepConstantArguments, prunedItems, executorService, futures), - pruneMethods(previous.keepUnusedArguments, prunedItems, executorService, futures), pruneMethods(previous.reprocess, prunedItems, executorService, futures), pruneMethods(previous.neverReprocess, prunedItems, executorService, futures), previous.alwaysClassInline, @@ -567,8 +555,6 @@ alwaysInline, neverInlineDueToSingleCaller, whyAreYouNotInlining, - keepConstantArguments, - keepUnusedArguments, reprocess, neverReprocess, alwaysClassInline, @@ -649,8 +635,6 @@ this.alwaysInline = previous.alwaysInline; this.neverInlineDueToSingleCaller = previous.neverInlineDueToSingleCaller; this.whyAreYouNotInlining = previous.whyAreYouNotInlining; - this.keepConstantArguments = previous.keepConstantArguments; - this.keepUnusedArguments = previous.keepUnusedArguments; this.reprocess = previous.reprocess; this.neverReprocess = previous.neverReprocess; this.alwaysClassInline = previous.alwaysClassInline; @@ -814,22 +798,6 @@ return whyAreYouNotInlining.isEmpty(); } - public boolean isKeepConstantArgumentsMethod(ProgramMethod method) { - return isKeepConstantArgumentsMethod(method.getReference()); - } - - public boolean isKeepConstantArgumentsMethod(DexMethod method) { - return keepConstantArguments.contains(method); - } - - public boolean isKeepUnusedArgumentsMethod(ProgramMethod method) { - return isKeepUnusedArgumentsMethod(method.getReference()); - } - - public boolean isKeepUnusedArgumentsMethod(DexMethod method) { - return keepUnusedArguments.contains(method); - } - public boolean isNeverReprocessMethod(ProgramMethod method) { return neverReprocess.contains(method.getReference()) || method.getOptimizationInfo().hasBeenInlinedIntoSingleCallSite(); @@ -1285,8 +1253,6 @@ lens.rewriteReferences(alwaysInline), lens.rewriteReferences(neverInlineDueToSingleCaller), lens.rewriteReferences(whyAreYouNotInlining), - lens.rewriteReferences(keepConstantArguments), - lens.rewriteReferences(keepUnusedArguments), lens.rewriteReferences(reprocess), lens.rewriteReferences(neverReprocess), alwaysClassInline.rewriteItems(lens::lookupType),
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java index 658cfbf..46732db 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3806,8 +3806,6 @@ amendWithCompanionMethods(rootSet.alwaysInline), amendWithCompanionMethods(rootSet.neverInlineDueToSingleCaller), amendWithCompanionMethods(rootSet.whyAreYouNotInlining), - amendWithCompanionMethods(rootSet.keepConstantArguments), - amendWithCompanionMethods(rootSet.keepUnusedArguments), amendWithCompanionMethods(rootSet.reprocess), amendWithCompanionMethods(rootSet.neverReprocess), rootSet.alwaysClassInline,
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java similarity index 83% rename from src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java rename to src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java index bc33778..f234a09 100644 --- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepConstantArgumentRule.java
@@ -7,10 +7,12 @@ import com.android.tools.r8.position.Position; import java.util.List; -public class ConstantArgumentRule extends ProguardConfigurationRule { +public class KeepConstantArgumentRule extends NoOptimizationBaseRule<KeepConstantArgumentRule> { + + public static final String RULE_NAME = "keepconstantarguments"; public static class Builder - extends ProguardConfigurationRule.Builder<ConstantArgumentRule, Builder> { + extends NoOptimizationBaseRule.Builder<KeepConstantArgumentRule, Builder> { private Builder() { super(); @@ -22,8 +24,8 @@ } @Override - public ConstantArgumentRule build() { - return new ConstantArgumentRule( + public KeepConstantArgumentRule build() { + return new KeepConstantArgumentRule( origin, getPosition(), source, @@ -40,7 +42,7 @@ } } - private ConstantArgumentRule( + private KeepConstantArgumentRule( Origin origin, Position position, String source,
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java index 9b83643..bcf9467 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepInfo.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepInfo.java
@@ -83,12 +83,6 @@ return checkDiscarded; } - public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) { - return isOptimizationAllowed(configuration) - && isShrinkingAllowed(configuration) - && !isCheckDiscardedEnabled(configuration); - } - /** * True if an item must be present in the output. *
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java index b43c44d..c82c666 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -25,18 +25,24 @@ } private final boolean allowClassInlining; + private final boolean allowConstantArgumentOptimization; private final boolean allowInlining; private final boolean allowMethodStaticizing; private final boolean allowParameterTypeStrengthening; private final boolean allowReturnTypeStrengthening; + private final boolean allowUnusedArgumentOptimization; + private final boolean allowUnusedReturnValueOptimization; private KeepMethodInfo(Builder builder) { super(builder); this.allowClassInlining = builder.isClassInliningAllowed(); + this.allowConstantArgumentOptimization = builder.isConstantArgumentOptimizationAllowed(); this.allowInlining = builder.isInliningAllowed(); this.allowMethodStaticizing = builder.isMethodStaticizingAllowed(); this.allowParameterTypeStrengthening = builder.isParameterTypeStrengtheningAllowed(); this.allowReturnTypeStrengthening = builder.isReturnTypeStrengtheningAllowed(); + this.allowUnusedArgumentOptimization = builder.isUnusedArgumentOptimizationAllowed(); + this.allowUnusedReturnValueOptimization = builder.isUnusedReturnValueOptimizationAllowed(); } // This builder is not private as there are known instances where it is safe to modify keep info @@ -50,6 +56,12 @@ return isParameterRemovalAllowed(configuration); } + public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) { + return isOptimizationAllowed(configuration) + && isShrinkingAllowed(configuration) + && !isCheckDiscardedEnabled(configuration); + } + public boolean isClassInliningAllowed(GlobalKeepInfoConfiguration configuration) { return isOptimizationAllowed(configuration) && internalIsClassInliningAllowed(); } @@ -58,6 +70,14 @@ return allowClassInlining; } + public boolean isConstantArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) { + return isOptimizationAllowed(configuration) && internalIsConstantArgumentOptimizationAllowed(); + } + + boolean internalIsConstantArgumentOptimizationAllowed() { + return allowConstantArgumentOptimization; + } + public boolean isInliningAllowed(GlobalKeepInfoConfiguration configuration) { return isOptimizationAllowed(configuration) && internalIsInliningAllowed(); } @@ -97,6 +117,26 @@ return allowReturnTypeStrengthening; } + public boolean isUnusedArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) { + return isOptimizationAllowed(configuration) + && isShrinkingAllowed(configuration) + && internalIsUnusedArgumentOptimizationAllowed(); + } + + boolean internalIsUnusedArgumentOptimizationAllowed() { + return allowUnusedArgumentOptimization; + } + + public boolean isUnusedReturnValueOptimizationAllowed(GlobalKeepInfoConfiguration configuration) { + return isOptimizationAllowed(configuration) + && isShrinkingAllowed(configuration) + && internalIsUnusedReturnValueOptimizationAllowed(); + } + + boolean internalIsUnusedReturnValueOptimizationAllowed() { + return allowUnusedReturnValueOptimization; + } + public Joiner joiner() { assert !isTop(); return new Joiner(this); @@ -115,10 +155,13 @@ public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> { private boolean allowClassInlining; + private boolean allowConstantArgumentOptimization; private boolean allowInlining; private boolean allowMethodStaticizing; private boolean allowParameterTypeStrengthening; private boolean allowReturnTypeStrengthening; + private boolean allowUnusedArgumentOptimization; + private boolean allowUnusedReturnValueOptimization; private Builder() { super(); @@ -127,12 +170,18 @@ private Builder(KeepMethodInfo original) { super(original); allowClassInlining = original.internalIsClassInliningAllowed(); + allowConstantArgumentOptimization = original.internalIsConstantArgumentOptimizationAllowed(); allowInlining = original.internalIsInliningAllowed(); allowMethodStaticizing = original.internalIsMethodStaticizingAllowed(); allowParameterTypeStrengthening = original.internalIsParameterTypeStrengtheningAllowed(); allowReturnTypeStrengthening = original.internalIsReturnTypeStrengtheningAllowed(); + allowUnusedArgumentOptimization = original.internalIsUnusedArgumentOptimizationAllowed(); + allowUnusedReturnValueOptimization = + original.internalIsUnusedReturnValueOptimizationAllowed(); } + // Class inlining. + public boolean isClassInliningAllowed() { return allowClassInlining; } @@ -150,6 +199,27 @@ return setAllowClassInlining(false); } + // Constant argument optimization. + + public boolean isConstantArgumentOptimizationAllowed() { + return allowConstantArgumentOptimization; + } + + public Builder setAllowConstantArgumentOptimization(boolean allowConstantArgumentOptimization) { + this.allowConstantArgumentOptimization = allowConstantArgumentOptimization; + return self(); + } + + public Builder allowConstantArgumentOptimization() { + return setAllowConstantArgumentOptimization(true); + } + + public Builder disallowConstantArgumentOptimization() { + return setAllowConstantArgumentOptimization(false); + } + + // Inlining. + public boolean isInliningAllowed() { return allowInlining; } @@ -167,6 +237,8 @@ return setAllowInlining(false); } + // Method staticizing. + public boolean isMethodStaticizingAllowed() { return allowMethodStaticizing; } @@ -184,6 +256,8 @@ return setAllowMethodStaticizing(false); } + // Parameter type strengthening. + public boolean isParameterTypeStrengtheningAllowed() { return allowParameterTypeStrengthening; } @@ -201,6 +275,8 @@ return setAllowParameterTypeStrengthening(false); } + // Return type strengthening. + public boolean isReturnTypeStrengtheningAllowed() { return allowReturnTypeStrengthening; } @@ -218,6 +294,45 @@ return setAllowReturnTypeStrengthening(false); } + // Unused argument optimization. + + public boolean isUnusedArgumentOptimizationAllowed() { + return allowUnusedArgumentOptimization; + } + + public Builder setAllowUnusedArgumentOptimization(boolean allowUnusedArgumentOptimization) { + this.allowUnusedArgumentOptimization = allowUnusedArgumentOptimization; + return self(); + } + + public Builder allowUnusedArgumentOptimization() { + return setAllowUnusedArgumentOptimization(true); + } + + public Builder disallowUnusedArgumentOptimization() { + return setAllowUnusedArgumentOptimization(false); + } + + // Unused return value optimization. + + public boolean isUnusedReturnValueOptimizationAllowed() { + return allowUnusedReturnValueOptimization; + } + + public Builder setAllowUnusedReturnValueOptimization( + boolean allowUnusedReturnValueOptimization) { + this.allowUnusedReturnValueOptimization = allowUnusedReturnValueOptimization; + return self(); + } + + public Builder allowUnusedReturnValueOptimization() { + return setAllowUnusedReturnValueOptimization(true); + } + + public Builder disallowUnusedReturnValueOptimization() { + return setAllowUnusedReturnValueOptimization(false); + } + @Override public Builder self() { return this; @@ -242,11 +357,17 @@ boolean internalIsEqualTo(KeepMethodInfo other) { return super.internalIsEqualTo(other) && isClassInliningAllowed() == other.internalIsClassInliningAllowed() + && isConstantArgumentOptimizationAllowed() + == other.internalIsConstantArgumentOptimizationAllowed() && isInliningAllowed() == other.internalIsInliningAllowed() && isMethodStaticizingAllowed() == other.internalIsMethodStaticizingAllowed() && isParameterTypeStrengtheningAllowed() == other.internalIsParameterTypeStrengtheningAllowed() - && isReturnTypeStrengtheningAllowed() == other.internalIsReturnTypeStrengtheningAllowed(); + && isReturnTypeStrengtheningAllowed() == other.internalIsReturnTypeStrengtheningAllowed() + && isUnusedArgumentOptimizationAllowed() + == other.internalIsUnusedArgumentOptimizationAllowed() + && isUnusedReturnValueOptimizationAllowed() + == other.internalIsUnusedReturnValueOptimizationAllowed(); } @Override @@ -258,20 +379,26 @@ public Builder makeTop() { return super.makeTop() .disallowClassInlining() + .disallowConstantArgumentOptimization() .disallowInlining() .disallowMethodStaticizing() .disallowParameterTypeStrengthening() - .disallowReturnTypeStrengthening(); + .disallowReturnTypeStrengthening() + .disallowUnusedArgumentOptimization() + .disallowUnusedReturnValueOptimization(); } @Override public Builder makeBottom() { return super.makeBottom() .allowClassInlining() + .allowConstantArgumentOptimization() .allowInlining() .allowMethodStaticizing() .allowParameterTypeStrengthening() - .allowReturnTypeStrengthening(); + .allowReturnTypeStrengthening() + .allowUnusedArgumentOptimization() + .allowUnusedReturnValueOptimization(); } } @@ -286,6 +413,11 @@ return self(); } + public Joiner disallowConstantArgumentOptimization() { + builder.disallowConstantArgumentOptimization(); + return self(); + } + public Joiner disallowInlining() { builder.disallowInlining(); return self(); @@ -306,6 +438,16 @@ return self(); } + public Joiner disallowUnusedArgumentOptimization() { + builder.disallowUnusedArgumentOptimization(); + return self(); + } + + public Joiner disallowUnusedReturnValueOptimization() { + builder.disallowUnusedReturnValueOptimization(); + return self(); + } + @Override public Joiner asMethodJoiner() { return this; @@ -316,6 +458,9 @@ // Should be extended to merge the fields of this class in case any are added. return super.merge(joiner) .applyIf(!joiner.builder.isClassInliningAllowed(), Joiner::disallowClassInlining) + .applyIf( + !joiner.builder.isConstantArgumentOptimizationAllowed(), + Joiner::disallowConstantArgumentOptimization) .applyIf(!joiner.builder.isInliningAllowed(), Joiner::disallowInlining) .applyIf(!joiner.builder.isMethodStaticizingAllowed(), Joiner::disallowMethodStaticizing) .applyIf( @@ -323,7 +468,13 @@ Joiner::disallowParameterTypeStrengthening) .applyIf( !joiner.builder.isReturnTypeStrengtheningAllowed(), - Joiner::disallowReturnTypeStrengthening); + Joiner::disallowReturnTypeStrengthening) + .applyIf( + !joiner.builder.isUnusedArgumentOptimizationAllowed(), + Joiner::disallowUnusedArgumentOptimization) + .applyIf( + !joiner.builder.isUnusedReturnValueOptimizationAllowed(), + Joiner::disallowUnusedReturnValueOptimization); } @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java similarity index 83% rename from src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java rename to src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java index dd537bc..18ba2ff 100644 --- a/src/main/java/com/android/tools/r8/shaking/UnusedArgumentRule.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedArgumentRule.java
@@ -7,10 +7,12 @@ import com.android.tools.r8.position.Position; import java.util.List; -public class UnusedArgumentRule extends ProguardConfigurationRule { +public class KeepUnusedArgumentRule extends NoOptimizationBaseRule<KeepUnusedArgumentRule> { + + public static final String RULE_NAME = "keepunusedarguments"; public static class Builder - extends ProguardConfigurationRule.Builder<UnusedArgumentRule, Builder> { + extends NoOptimizationBaseRule.Builder<KeepUnusedArgumentRule, Builder> { private Builder() { super(); @@ -22,8 +24,8 @@ } @Override - public UnusedArgumentRule build() { - return new UnusedArgumentRule( + public KeepUnusedArgumentRule build() { + return new KeepUnusedArgumentRule( origin, getPosition(), source, @@ -40,7 +42,7 @@ } } - private UnusedArgumentRule( + private KeepUnusedArgumentRule( Origin origin, Position position, String source, @@ -76,6 +78,6 @@ @Override String typeString() { - return "keepunusedarguments"; + return RULE_NAME; } }
diff --git a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java similarity index 76% copy from src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java copy to src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java index bc33778..2543285 100644 --- a/src/main/java/com/android/tools/r8/shaking/ConstantArgumentRule.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepUnusedReturnValueRule.java
@@ -1,29 +1,32 @@ -// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file +// Copyright (c) 2022, 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.shaking; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.position.Position; import java.util.List; -public class ConstantArgumentRule extends ProguardConfigurationRule { +public class KeepUnusedReturnValueRule extends NoOptimizationBaseRule<KeepUnusedReturnValueRule> { + + public static final String RULE_NAME = "keepunusedreturnvalue"; public static class Builder - extends ProguardConfigurationRule.Builder<ConstantArgumentRule, Builder> { + extends NoOptimizationBaseRule.Builder<KeepUnusedReturnValueRule, Builder> { - private Builder() { + Builder() { super(); } @Override - public Builder self() { + public KeepUnusedReturnValueRule.Builder self() { return this; } @Override - public ConstantArgumentRule build() { - return new ConstantArgumentRule( + public KeepUnusedReturnValueRule build() { + return new KeepUnusedReturnValueRule( origin, getPosition(), source, @@ -40,7 +43,7 @@ } } - private ConstantArgumentRule( + KeepUnusedReturnValueRule( Origin origin, Position position, String source, @@ -76,6 +79,6 @@ @Override String typeString() { - return "keepconstantarguments"; + return RULE_NAME; } }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java index b1fdef2..0f2ad2c 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -450,13 +450,21 @@ configurationBuilder.addRule(rule); return true; } - if (acceptString("keepconstantarguments")) { - ConstantArgumentRule rule = parseConstantArgumentRule(optionStart); + if (acceptString(KeepConstantArgumentRule.RULE_NAME)) { + KeepConstantArgumentRule rule = + parseNoOptimizationRule(optionStart, KeepConstantArgumentRule.builder()); configurationBuilder.addRule(rule); return true; } - if (acceptString("keepunusedarguments")) { - UnusedArgumentRule rule = parseUnusedArgumentRule(optionStart); + if (acceptString(KeepUnusedArgumentRule.RULE_NAME)) { + KeepUnusedArgumentRule rule = + parseNoOptimizationRule(optionStart, KeepUnusedArgumentRule.builder()); + configurationBuilder.addRule(rule); + return true; + } + if (acceptString(KeepUnusedReturnValueRule.RULE_NAME)) { + KeepUnusedReturnValueRule rule = + parseNoOptimizationRule(optionStart, KeepUnusedReturnValueRule.builder()); configurationBuilder.addRule(rule); return true; } @@ -918,10 +926,10 @@ "Expecting '-keep' option after '-if' option.", origin, getPosition(optionStart))); } - private ConstantArgumentRule parseConstantArgumentRule(Position start) + private KeepConstantArgumentRule parseConstantArgumentRule(Position start) throws ProguardRuleParserException { - ConstantArgumentRule.Builder keepRuleBuilder = - ConstantArgumentRule.builder().setOrigin(origin).setStart(start); + KeepConstantArgumentRule.Builder keepRuleBuilder = + KeepConstantArgumentRule.builder().setOrigin(origin).setStart(start); parseClassSpec(keepRuleBuilder, false); Position end = getPosition(); keepRuleBuilder.setSource(getSourceSnippet(contents, start, end)); @@ -929,10 +937,10 @@ return keepRuleBuilder.build(); } - private UnusedArgumentRule parseUnusedArgumentRule(Position start) + private KeepUnusedArgumentRule parseUnusedArgumentRule(Position start) throws ProguardRuleParserException { - UnusedArgumentRule.Builder keepRuleBuilder = - UnusedArgumentRule.builder().setOrigin(origin).setStart(start); + KeepUnusedArgumentRule.Builder keepRuleBuilder = + KeepUnusedArgumentRule.builder().setOrigin(origin).setStart(start); parseClassSpec(keepRuleBuilder, false); Position end = getPosition(); keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java index 2f7d3f4..2832262 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -111,12 +111,9 @@ new DependentMinimumKeepInfoCollection(); private final LinkedHashMap<DexReference, DexReference> reasonAsked = new LinkedHashMap<>(); private final Set<DexMethod> alwaysInline = Sets.newIdentityHashSet(); - private final Set<DexMethod> neverInline = Sets.newIdentityHashSet(); private final Set<DexMethod> neverInlineDueToSingleCaller = Sets.newIdentityHashSet(); private final Set<DexMethod> bypassClinitforInlining = Sets.newIdentityHashSet(); private final Set<DexMethod> whyAreYouNotInlining = Sets.newIdentityHashSet(); - private final Set<DexMethod> keepParametersWithConstantValue = Sets.newIdentityHashSet(); - private final Set<DexMethod> keepUnusedArguments = Sets.newIdentityHashSet(); private final Set<DexMethod> reprocess = Sets.newIdentityHashSet(); private final Set<DexMethod> neverReprocess = Sets.newIdentityHashSet(); private final PredicateSet<DexType> alwaysClassInline = new PredicateSet<>(); @@ -267,11 +264,12 @@ } else if (rule instanceof NoFieldTypeStrengtheningRule) { markMatchingFields(clazz, memberKeepRules, rule, null, ifRule); } else if (rule instanceof InlineRule - || rule instanceof ConstantArgumentRule + || rule instanceof KeepConstantArgumentRule + || rule instanceof KeepUnusedReturnValueRule || rule instanceof NoMethodStaticizingRule || rule instanceof NoParameterTypeStrengtheningRule || rule instanceof NoReturnTypeStrengtheningRule - || rule instanceof UnusedArgumentRule + || rule instanceof KeepUnusedArgumentRule || rule instanceof ReprocessMethodRule || rule instanceof WhyAreYouNotInliningRule) { markMatchingMethods(clazz, memberKeepRules, rule, null, ifRule); @@ -364,18 +362,13 @@ alwaysInline, bypassClinitforInlining); } - assert Sets.intersection(neverInline, alwaysInline).isEmpty() - : "A method cannot be marked as both -neverinline and -alwaysinline."; return new RootSet( dependentMinimumKeepInfo, ImmutableList.copyOf(reasonAsked.values()), alwaysInline, - neverInline, neverInlineDueToSingleCaller, bypassClinitforInlining, whyAreYouNotInlining, - keepParametersWithConstantValue, - keepUnusedArguments, reprocess, neverReprocess, alwaysClassInline, @@ -456,7 +449,6 @@ ConsequentRootSet buildConsequentRootSet() { return new ConsequentRootSet( - neverInline, neverInlineDueToSingleCaller, neverClassInline, dependentMinimumKeepInfo, @@ -1301,11 +1293,6 @@ } } else if (context instanceof ProguardIdentifierNameStringRule) { evaluateIdentifierNameStringRule(item, context, ifRule); - } else if (context instanceof ConstantArgumentRule) { - if (item.isMethod()) { - keepParametersWithConstantValue.add(item.asMethod().getReference()); - context.markAsUsed(); - } } else if (context instanceof ReprocessClassInitializerRule) { DexProgramClass clazz = item.asProgramClass(); if (clazz != null && clazz.hasClassInitializer()) { @@ -1336,11 +1323,27 @@ } context.markAsUsed(); } - } else if (context instanceof UnusedArgumentRule) { - if (item.isMethod()) { - keepUnusedArguments.add(item.asMethod().getReference()); - context.markAsUsed(); - } + } else if (context instanceof KeepConstantArgumentRule) { + assert item.isProgramMethod(); + dependentMinimumKeepInfo + .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference()) + .asMethodJoiner() + .disallowConstantArgumentOptimization(); + context.markAsUsed(); + } else if (context instanceof KeepUnusedArgumentRule) { + assert item.isProgramMethod(); + dependentMinimumKeepInfo + .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference()) + .asMethodJoiner() + .disallowUnusedArgumentOptimization(); + context.markAsUsed(); + } else if (context instanceof KeepUnusedReturnValueRule) { + assert item.isProgramMethod(); + dependentMinimumKeepInfo + .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference()) + .asMethodJoiner() + .disallowUnusedReturnValueOptimization(); + context.markAsUsed(); } else { throw new Unreachable(); } @@ -1673,8 +1676,6 @@ public final Set<DexMethod> alwaysInline; public final Set<DexMethod> bypassClinitForInlining; public final Set<DexMethod> whyAreYouNotInlining; - public final Set<DexMethod> keepConstantArguments; - public final Set<DexMethod> keepUnusedArguments; public final Set<DexMethod> reprocess; public final Set<DexMethod> neverReprocess; public final PredicateSet<DexType> alwaysClassInline; @@ -1692,12 +1693,9 @@ DependentMinimumKeepInfoCollection dependentMinimumKeepInfo, ImmutableList<DexReference> reasonAsked, Set<DexMethod> alwaysInline, - Set<DexMethod> neverInline, Set<DexMethod> neverInlineDueToSingleCaller, Set<DexMethod> bypassClinitForInlining, Set<DexMethod> whyAreYouNotInlining, - Set<DexMethod> keepConstantArguments, - Set<DexMethod> keepUnusedArguments, Set<DexMethod> reprocess, Set<DexMethod> neverReprocess, PredicateSet<DexType> alwaysClassInline, @@ -1725,8 +1723,6 @@ this.alwaysInline = alwaysInline; this.bypassClinitForInlining = bypassClinitForInlining; this.whyAreYouNotInlining = whyAreYouNotInlining; - this.keepConstantArguments = keepConstantArguments; - this.keepUnusedArguments = keepUnusedArguments; this.reprocess = reprocess; this.neverReprocess = neverReprocess; this.alwaysClassInline = alwaysClassInline; @@ -2044,7 +2040,6 @@ public static class ConsequentRootSet extends RootSetBase { ConsequentRootSet( - Set<DexMethod> neverInline, Set<DexMethod> neverInlineDueToSingleCaller, Set<DexType> neverClassInline, DependentMinimumKeepInfoCollection dependentMinimumKeepInfo, @@ -2110,9 +2105,6 @@ Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), - Collections.emptySet(), PredicateSet.empty(), Collections.emptySet(), Collections.emptySet(),
diff --git a/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java b/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java new file mode 100644 index 0000000..f797cf9 --- /dev/null +++ b/src/test/java/com/android/tools/r8/KeepUnusedReturnValue.java
@@ -0,0 +1,11 @@ +// Copyright (c) 2022, 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; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +public @interface KeepUnusedReturnValue {}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java index ce82006..e1be80b 100644 --- a/src/test/java/com/android/tools/r8/R8TestBuilder.java +++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -17,6 +17,7 @@ import com.android.tools.r8.experimental.graphinfo.GraphConsumer; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.shaking.CollectingGraphConsumer; +import com.android.tools.r8.shaking.KeepUnusedReturnValueRule; import com.android.tools.r8.shaking.NoFieldTypeStrengtheningRule; import com.android.tools.r8.shaking.NoHorizontalClassMergingRule; import com.android.tools.r8.shaking.NoMethodStaticizingRule; @@ -498,6 +499,12 @@ return addOptionsModification(options -> options.testing.allowInliningOfSynthetics = false); } + public T enableKeepUnusedReturnValueAnnotations() { + return addKeepUnusedReturnValueAnnotation() + .addInternalMatchAnnotationOnMethodRule( + KeepUnusedReturnValueRule.RULE_NAME, KeepUnusedReturnValue.class); + } + public T enableNoFieldTypeStrengtheningAnnotations() { return addNoFieldTypeStrengtheningAnnotation() .addInternalMatchAnnotationOnFieldRule(
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java index 0c3b2ae..e88f882 100644 --- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java +++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -438,6 +438,10 @@ return addTestingAnnotation(Keep.class); } + public final T addKeepUnusedReturnValueAnnotation() { + return addTestingAnnotation(KeepUnusedReturnValue.class); + } + public final T addMemberValuePropagationAnnotations() { return addTestingAnnotation(NeverPropagateValue.class); }