[ApiModel] Disable instance outlining on dalvik
Bug: b/269097876
Change-Id: I4df9ee7fd204a479f8e2d2212dd2c7f731f80e35
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 16ad20d..72d5998 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
@@ -96,6 +96,7 @@
import com.android.tools.r8.shaking.KeepMethodInfo;
import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
import com.android.tools.r8.utils.Action;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -247,7 +248,8 @@
? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
: null;
if (appView.options().desugarState.isOn()
- && appView.options().apiModelingOptions().enableOutliningOfMethods) {
+ && appView.options().apiModelingOptions().enableOutliningOfMethods
+ && appView.options().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
this.instanceInitializerOutliner = new InstanceInitializerOutliner(appView);
} else {
this.instanceInitializerOutliner = null;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldAssignNewInstanceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldAssignNewInstanceTest.java
index 51dc157..f2a6859 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldAssignNewInstanceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelFieldAssignNewInstanceTest.java
@@ -7,9 +7,8 @@
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static com.android.tools.r8.synthesis.SyntheticItemsTestUtils.syntheticApiOutlineClass;
+import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
@@ -23,6 +22,7 @@
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.lang.reflect.Method;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -141,14 +141,12 @@
.apply(result -> checkOutput(result, true));
}
- private void inspect(CodeInspector inspector) {
+ private void inspect(CodeInspector inspector) throws Exception {
assertThat(inspector.clazz(Main.class), isPresent());
assertThat(inspector.clazz(Helper.class), isPresent());
- if (!parameters.isCfRuntime()) {
- assertThat(
- inspector.clazz(syntheticApiOutlineClass(Helper.class, 0)),
- notIf(isPresent(), parameters.getApiLevel().isGreaterThanOrEqualTo(mockApiLevel)));
- }
+ Method getLibraryClass = Helper.class.getMethod("setLibraryClass");
+ verifyThat(inspector, parameters, SubLibraryClass.class.getConstructor())
+ .isOutlinedFromBetween(getLibraryClass, AndroidApiLevel.L, mockApiLevel);
}
private void checkOutput(SingleTestRunResult<?> runResult, boolean apiModelingEnabled) {
@@ -156,9 +154,6 @@
runResult.assertFailureWithErrorThatThrows(ClassNotFoundException.class);
} else if (getMaxSupportedApiLevel().isGreaterThanOrEqualTo(mockApiLevel)) {
runResult.assertSuccessWithOutputLines("SubLibraryClass::foo");
- } else if (parameters.getDexRuntimeVersion().isDalvik() && apiModelingEnabled) {
- // TODO(b/b/269097876): We should not cause a verification error.
- runResult.assertFailureWithErrorThatThrows(VerifyError.class);
} else {
runResult.assertSuccessWithOutputLines("LibraryClass::foo");
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
index 978d068..7646f63 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
@@ -100,7 +100,9 @@
.inspect(
inspector -> {
// TODO(b/187675788): Update when horizontal merging is enabled for D8 for debug mode.
- if (parameters.getApiLevel().isLessThan(libraryClassApiLevel)) {
+ if (parameters.getApiLevel().isLessThan(AndroidApiLevel.L)) {
+ assertEquals(7, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(libraryClassApiLevel)) {
// We have generated 4 outlines two having api level 23 and two having api level 27
// and 2 outlines for each instance initializer.
assertEquals(11, inspector.allClasses().size());
@@ -172,9 +174,10 @@
// If less than the library api level then we have synthesized two instance initializer
// outlines as well.
// Check that the levels are horizontally merged.
- assertEquals(
- parameters.getApiLevel().isLessThan(libraryClassApiLevel) ? 6 : 5,
- inspector.allClasses().size());
+ boolean willOutlineInitializers =
+ parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L)
+ && parameters.getApiLevel().isLessThan(libraryClassApiLevel);
+ assertEquals(willOutlineInitializers ? 6 : 5, inspector.allClasses().size());
assertEquals(2, outlinedAddedOn23.size());
assertTrue(
outlinedAddedOn23.stream()
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerSuperTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerSuperTest.java
index a362bd3..ed4b250 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerSuperTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerSuperTest.java
@@ -108,8 +108,9 @@
ProgramExtendsLibraryClass.class.getMethod("print"),
isR8 ? AndroidApiLevel.B : classApiLevel);
verifyThat(inspector, parameters, LibraryClass.class.getDeclaredConstructor(String.class))
- .isOutlinedFromUntil(
+ .isOutlinedFromBetween(
ProgramExtendsLibraryClass.class.getDeclaredConstructor(String.class),
+ AndroidApiLevel.L,
isR8 ? AndroidApiLevel.B : classApiLevel);
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerTest.java
index b0a5fb7..0d16797 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineInstanceInitializerTest.java
@@ -113,11 +113,13 @@
private void inspect(CodeInspector inspector, boolean isR8) throws Exception {
Method mainMethod = Main.class.getMethod("main", String[].class);
verifyThat(inspector, parameters, Argument.class.getDeclaredConstructor(String.class))
- .isOutlinedFromUntil(mainMethod, classApiLevel);
+ .isOutlinedFromBetween(mainMethod, AndroidApiLevel.L, classApiLevel);
verifyThat(inspector, parameters, LibraryClass.class.getDeclaredConstructor(Argument.class))
- .isOutlinedFromUntil(mainMethod, classApiLevel);
+ .isOutlinedFromBetween(mainMethod, AndroidApiLevel.L, classApiLevel);
+ // For R8 we inline into the method with an instance initializer when we do not outline it.
verifyThat(inspector, parameters, LibraryClass.class.getMethod("print"))
- .isOutlinedFromUntil(mainMethod, classApiLevel);
+ .isOutlinedFromBetween(
+ mainMethod, isR8 ? AndroidApiLevel.L : AndroidApiLevel.B, classApiLevel);
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index e437943..6a487a9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -447,6 +447,17 @@
}
}
+ void isOutlinedFromBetween(
+ Executable method, AndroidApiLevel lowerBoundInclusive, AndroidApiLevel upperBound) {
+ if (parameters.isDexRuntime()
+ && parameters.getApiLevel().isLessThan(upperBound)
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(lowerBoundInclusive)) {
+ isOutlinedFrom(method);
+ } else {
+ isNotOutlinedFrom(method);
+ }
+ }
+
void isOutlinedFrom(Executable method) {
// Check that the call is in a synthetic class.
List<FoundMethodSubject> outlinedMethod =