Synthesize -assumenosideeffects rule for MIN_SDK
Bug: 111763015
Change-Id: Ie8b11fd1d62ff76b3ed89448172d43dc39c735e7
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 624d6fe..e01b4ed 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -309,13 +309,11 @@
// Add synthesized -assumevalues from min api if relevant.
if (options.isGeneratingDex()) {
- if (!ProguardConfigurationUtils.hasExplicitAssumeValuesRuleForMinSdk(
- options.itemFactory,
- options.getProguardConfiguration().getRules())) {
+ if (!ProguardConfigurationUtils.hasExplicitAssumeValuesOrAssumeNoSideEffectsRuleForMinSdk(
+ options.itemFactory, options.getProguardConfiguration().getRules())) {
synthesizedProguardRules.add(
- ProguardConfigurationUtils.buildAssumeValuesForApiLevel(
- options.itemFactory,
- AndroidApiLevel.getAndroidApiLevel(options.minApiLevel)));
+ ProguardConfigurationUtils.buildAssumeNoSideEffectsRuleForApiLevel(
+ options.itemFactory, AndroidApiLevel.getAndroidApiLevel(options.minApiLevel)));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index d229fa4..df73ae8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -81,15 +81,19 @@
}
private boolean mayPropagateValueFor(DexEncodedField field) {
- return field.isProgramField(appView)
- ? appView.appInfo().mayPropagateValueFor(field.field)
- : appView.appInfo().assumedValues.containsKey(field.field);
+ if (field.isProgramField(appView)) {
+ return appView.appInfo().mayPropagateValueFor(field.field);
+ }
+ return appView.appInfo().assumedValues.containsKey(field.field)
+ || appView.appInfo().noSideEffects.containsKey(field.field);
}
private boolean mayPropagateValueFor(DexEncodedMethod method) {
- return method.isProgramMethod(appView)
- ? appView.appInfo().mayPropagateValueFor(method.method)
- : appView.appInfo().assumedValues.containsKey(method.method);
+ if (method.isProgramMethod(appView)) {
+ return appView.appInfo().mayPropagateValueFor(method.method);
+ }
+ return appView.appInfo().assumedValues.containsKey(method.method)
+ || appView.appInfo().noSideEffects.containsKey(method.method);
}
private ProguardMemberRuleLookup lookupMemberRule(DexDefinition definition) {
@@ -319,7 +323,6 @@
}
ProguardMemberRuleLookup lookup = lookupMemberRule(target);
if (lookup != null
- && lookup.type == RuleType.ASSUME_VALUES
&& tryConstantReplacementFromProguard(
code, affectedValues, blocks, iterator, current, lookup)) {
return;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
index 39e5e9a..c5dcb0c 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
@@ -85,7 +85,7 @@
return builder.build();
}
- public static ProguardAssumeValuesRule buildAssumeValuesForApiLevel(
+ public static ProguardAssumeNoSideEffectRule buildAssumeNoSideEffectsRuleForApiLevel(
DexItemFactory factory, AndroidApiLevel apiLevel) {
Origin synthesizedFromApiLevel =
new Origin(Origin.root()) {
@@ -100,36 +100,35 @@
publicStaticFinalFlags.setStatic();
publicStaticFinalFlags.setFinal();
- return ProguardAssumeValuesRule
- .builder()
+ return ProguardAssumeNoSideEffectRule.builder()
.setOrigin(synthesizedFromApiLevel)
.setClassType(ProguardClassType.CLASS)
.setClassNames(
ProguardClassNameList.singletonList(
ProguardTypeMatcher.create(factory.createType("Landroid/os/Build$VERSION;"))))
- .setMemberRules(ImmutableList.of(
- ProguardMemberRule.builder()
- .setAccessFlags(publicStaticFinalFlags)
- .setRuleType(ProguardMemberType.FIELD)
- .setTypeMatcher(ProguardTypeMatcher.create(factory.intType))
- .setName(IdentifierPatternWithWildcards.withoutWildcards("SDK_INT"))
- .setReturnValue(
- new ProguardMemberRuleReturnValue(
- new LongInterval(apiLevel.getLevel(), Integer.MAX_VALUE)))
- .build()
- ))
+ .setMemberRules(
+ ImmutableList.of(
+ ProguardMemberRule.builder()
+ .setAccessFlags(publicStaticFinalFlags)
+ .setRuleType(ProguardMemberType.FIELD)
+ .setTypeMatcher(ProguardTypeMatcher.create(factory.intType))
+ .setName(IdentifierPatternWithWildcards.withoutWildcards("SDK_INT"))
+ .setReturnValue(
+ new ProguardMemberRuleReturnValue(
+ new LongInterval(apiLevel.getLevel(), Integer.MAX_VALUE)))
+ .build()))
.build();
}
/**
- * Check if an explicit rule matching the field
- * public static final int android.os.Build$VERSION.SDK_INT
- * is present.
+ * Check if an explicit rule matching the field public static final int
+ * android.os.Build$VERSION.SDK_INT is present.
*/
- public static boolean hasExplicitAssumeValuesRuleForMinSdk(
+ public static boolean hasExplicitAssumeValuesOrAssumeNoSideEffectsRuleForMinSdk(
DexItemFactory factory, List<ProguardConfigurationRule> rules) {
for (ProguardConfigurationRule rule : rules) {
- if (!(rule instanceof ProguardAssumeValuesRule)) {
+ if (!(rule instanceof ProguardAssumeValuesRule
+ || rule instanceof ProguardAssumeNoSideEffectRule)) {
continue;
}
if (rule.getClassType() != ProguardClassType.CLASS) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MinSdkMemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MinSdkMemberValuePropagationTest.java
new file mode 100644
index 0000000..caad10b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/MinSdkMemberValuePropagationTest.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2019, 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.ir.optimize.membervaluepropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MinSdkMemberValuePropagationTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final String rule;
+
+ @Parameterized.Parameters(name = "{0}, rule: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().build(),
+ ImmutableList.of("assumenosideeffects", "assumevalues"));
+ }
+
+ public MinSdkMemberValuePropagationTest(TestParameters parameters, String rule) {
+ this.parameters = parameters;
+ this.rule = rule;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-" + rule + " class " + Library.class.getTypeName() + " {",
+ " static int MIN_SDK return 42;",
+ "}")
+ .addLibraryClasses(Library.class)
+ .addLibraryFiles(runtimeJar(parameters))
+ .setMinApi(parameters.getRuntime())
+ .compile()
+ .inspect(this::verifyOutput)
+ .addRunClasspathFiles(
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Library.class)
+ .addKeepAllClassesRule()
+ .setMinApi(parameters.getRuntime())
+ .compile()
+ .writeToZip())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void verifyOutput(CodeInspector inspector) {
+ ClassSubject classSubject = inspector.clazz(TestClass.class);
+ assertThat(classSubject, isPresent());
+
+ MethodSubject mainSubject = classSubject.mainMethod();
+ assertThat(mainSubject, isPresent());
+
+ boolean readsMinSdkField =
+ mainSubject
+ .streamInstructions()
+ .anyMatch(x -> x.isStaticGet() && x.getField().name.toString().equals("MIN_SDK"));
+ assertEquals(rule.equals("assumevalues"), readsMinSdkField);
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ if (Library.MIN_SDK == 42) {
+ System.out.println("Hello world!");
+ }
+ }
+ }
+
+ static class Library {
+
+ static int MIN_SDK = -1;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
index 610f63b..66e49e6 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -19,8 +18,7 @@
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
-import com.android.tools.r8.shaking.ProguardAssumeValuesRule;
-import com.android.tools.r8.shaking.ProguardConfiguration;
+import com.android.tools.r8.shaking.ProguardAssumeNoSideEffectRule;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -138,7 +136,7 @@
private void checkSynthesizedRuleExpectation(
List<ProguardConfigurationRule> synthesizedRules, SynthesizedRule expected) {
for (ProguardConfigurationRule rule : synthesizedRules) {
- if (rule instanceof ProguardAssumeValuesRule
+ if (rule instanceof ProguardAssumeNoSideEffectRule
&& rule.getOrigin().part().contains("SYNTHESIZED_FROM_API_LEVEL")) {
assertEquals(expected, SynthesizedRule.PRESENT);
return;
@@ -147,12 +145,8 @@
assertEquals(expected, SynthesizedRule.NOT_PRESENT);
}
- private void noSynthesizedRules(ProguardConfiguration proguardConfiguration) {
- for (ProguardConfigurationRule rule : proguardConfiguration.getRules()) {
- if (rule instanceof ProguardAssumeValuesRule) {
- assertFalse(rule.getOrigin().part().contains("SYNTHESIZED_FROM_API_LEVEL"));
- }
- }
+ private void noSynthesizedRules(List<ProguardConfigurationRule> synthesizedRules) {
+ assertTrue(synthesizedRules.isEmpty());
}
private void runTest(
@@ -187,7 +181,7 @@
.addKeepMainRule(mainClassName)
.addKeepRules(additionalKeepRules)
.compile()
- .inspectProguardConfiguration(this::noSynthesizedRules)
+ .inspectSyntheticProguardRules(this::noSynthesizedRules)
.addRunClasspathFiles(
ImmutableList.of(mockAndroidRuntimeLibrary(AndroidApiLevel.D.getLevel())))
.run(mainClassName)