[ApiModel] Add support for outlining methods in D8
Bug: 213552119
Change-Id: Iebbfe7a8a337710f4cf7ab3ea7e742ed8b468241
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 43868c3..f80403a 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -323,7 +323,7 @@
finalizeApplication(appView, executor);
- if (options.apiModelingOptions().enableStubbingOfClasses && !appView.options().debug) {
+ if (options.apiModelingOptions().enableStubbingOfClasses) {
new ApiReferenceStubber(appView).run(executor);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 4fecb6d..6c0c957 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.ClassConverterResult;
import com.android.tools.r8.ir.conversion.D8MethodProcessor;
+import com.android.tools.r8.ir.desugar.apimodel.ApiInvokeOutlinerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicClass;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicDesugaringEventConsumer;
@@ -57,7 +58,8 @@
InterfaceMethodDesugaringEventConsumer,
DesugaredLibraryRetargeterInstructionEventConsumer,
DesugaredLibraryAPIConverterEventConsumer,
- ClasspathEmulatedInterfaceSynthesizerEventConsumer {
+ ClasspathEmulatedInterfaceSynthesizerEventConsumer,
+ ApiInvokeOutlinerDesugaringEventConsumer {
public static D8CfInstructionDesugaringEventConsumer createForD8(
D8MethodProcessor methodProcessor) {
@@ -266,6 +268,11 @@
assert synthesizedConstantDynamicClasses.isEmpty();
return true;
}
+
+ @Override
+ public void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context) {
+ methodProcessor.scheduleDesugaredMethodForProcessing(outlinedMethod);
+ }
}
public static class R8CfInstructionDesugaringEventConsumer
@@ -459,5 +466,10 @@
// Remove all '$deserializeLambda$' methods which are not supported by desugaring.
LambdaDeserializationMethodRemover.run(appView, classesWithSerializableLambdas);
}
+
+ @Override
+ public void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context) {
+ // Intentionally empty. The method will be hit by tracing if required.
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index e642655..06fadd9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -63,7 +63,9 @@
methodProcessingContext.createUniqueContext(),
instruction.asInvoke(),
computedApiLevel,
- dexItemFactory);
+ dexItemFactory,
+ eventConsumer,
+ context);
}
return null;
}
@@ -146,14 +148,17 @@
}
private Collection<CfInstruction> desugarLibraryCall(
- UniqueContext context,
+ UniqueContext uniqueContext,
CfInvoke invoke,
ComputedApiLevel computedApiLevel,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ ApiInvokeOutlinerDesugaringEventConsumer eventConsumer,
+ ProgramMethod context) {
DexMethod method = invoke.getMethod();
- ProgramMethod programMethod =
- ensureOutlineMethod(context, method, computedApiLevel, factory, invoke);
- return ImmutableList.of(new CfInvoke(INVOKESTATIC, programMethod.getReference(), false));
+ ProgramMethod outlinedMethod =
+ ensureOutlineMethod(uniqueContext, method, computedApiLevel, factory, invoke);
+ eventConsumer.acceptOutlinedMethod(outlinedMethod, context);
+ return ImmutableList.of(new CfInvoke(INVOKESTATIC, outlinedMethod.getReference(), false));
}
private ProgramMethod ensureOutlineMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java
new file mode 100644
index 0000000..873d5e5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaringEventConsumer.java
@@ -0,0 +1,12 @@
+// 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.ir.desugar.apimodel;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface ApiInvokeOutlinerDesugaringEventConsumer {
+
+ void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context);
+}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
index 2e96c90..31f5bda 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineDuplicateMethodTest.java
@@ -16,6 +16,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Method;
@@ -62,6 +64,8 @@
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForMethod(addedOn23(), methodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -72,19 +76,34 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -101,47 +120,44 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- int classCount =
- parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel)
- ? 4
- : 3;
- assertEquals(classCount, inspector.allClasses().size());
- Method testMethod = TestClass.class.getDeclaredMethod("test");
- verifyThat(inspector, parameters, addedOn23())
- .isOutlinedFromUntil(testMethod, methodApiLevel);
- if (parameters.isDexRuntime()
- && parameters.getApiLevel().isLessThan(methodApiLevel)) {
- // Verify that we invoke the synthesized outline, addedOn23, twice.
- Optional<FoundMethodSubject> synthesizedAddedOn23 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn23").matches(methodSubject))
- .findFirst();
- assertTrue(synthesizedAddedOn23.isPresent());
- MethodSubject testMethodSubject = inspector.method(testMethod);
- assertThat(testMethodSubject, isPresent());
- assertEquals(
- 2,
- testMethodSubject
- .streamInstructions()
- .filter(
- instructionSubject -> {
- if (!instructionSubject.isInvoke()) {
- return false;
- }
- return instructionSubject
- .getMethod()
- .asMethodReference()
- .equals(synthesizedAddedOn23.get().asMethodReference());
- })
- .count());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ int classCount =
+ parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel) ? 4 : 3;
+ assertEquals(classCount, inspector.allClasses().size());
+ Method testMethod = TestClass.class.getDeclaredMethod("test");
+ verifyThat(inspector, parameters, addedOn23()).isOutlinedFromUntil(testMethod, methodApiLevel);
+ if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(methodApiLevel)) {
+ // Verify that we invoke the synthesized outline, addedOn23, twice.
+ Optional<FoundMethodSubject> synthesizedAddedOn23 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn23").matches(methodSubject))
+ .findFirst();
+ assertTrue(synthesizedAddedOn23.isPresent());
+ MethodSubject testMethodSubject = inspector.method(testMethod);
+ assertThat(testMethodSubject, isPresent());
+ assertEquals(
+ 2,
+ testMethodSubject
+ .streamInstructions()
+ .filter(
+ instructionSubject -> {
+ if (!instructionSubject.isInvoke()) {
+ return false;
+ }
+ return instructionSubject
+ .getMethod()
+ .asMethodReference()
+ .equals(synthesizedAddedOn23.get().asMethodReference());
+ })
+ .count());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
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 497e0fd..d00efb9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineHorizontalMergingTest.java
@@ -13,6 +13,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -22,6 +23,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import java.util.List;
import java.util.stream.Collectors;
@@ -72,6 +74,8 @@
.apply(
setMockApiLevelForMethod(
OtherLibraryClass.class.getMethod("addedOn27"), secondMethodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -85,12 +89,13 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(
@@ -98,8 +103,49 @@
b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(
+ inspector -> {
+ // TODO(b/187675788): Update when horizontal merging is enabled for D8.
+ if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
+ // We have generated 4 outlines two having api level 23 and two having api level 27.
+ assertEquals(7, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
+ assertEquals(5, inspector.allClasses().size());
+ } else {
+ // No outlining on this api level.
+ assertEquals(3, inspector.allClasses().size());
+ }
+ });
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(
+ addToBootClasspath(),
+ b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(
+ inspector -> {
+ // TODO(b/187675788): Update when horizontal merging is enabled for D8.
+ if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
+ // We have generated 4 outlines two having api level 23 and two having api level 27.
+ assertEquals(7, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
+ assertEquals(5, inspector.allClasses().size());
+ } else {
+ // No outlining on this api level.
+ assertEquals(3, inspector.allClasses().size());
+ }
+ });
}
@Test
@@ -118,64 +164,64 @@
b -> b.addBootClasspathClasses(LibraryClass.class, OtherLibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- // No need to check further on CF.
- List<FoundMethodSubject> outlinedAddedOn23 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn23").matches(methodSubject))
- .collect(Collectors.toList());
- List<FoundMethodSubject> outlinedAddedOn27 =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("addedOn27").matches(methodSubject))
- .collect(Collectors.toList());
- if (parameters.isCfRuntime()) {
- assertTrue(outlinedAddedOn23.isEmpty());
- assertTrue(outlinedAddedOn27.isEmpty());
- assertEquals(3, inspector.allClasses().size());
- } else if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
- // We have generated 4 outlines two having api level 23 and two having api level 27.
- // Check that the levels are horizontally merged.
- assertEquals(5, inspector.allClasses().size());
- assertEquals(2, outlinedAddedOn23.size());
- assertTrue(
- outlinedAddedOn23.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn23.get(0).getMethod().getHolderType()));
- assertEquals(2, outlinedAddedOn27.size());
- assertTrue(
- outlinedAddedOn27.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn27.get(0).getMethod().getHolderType()));
- } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
- assertTrue(outlinedAddedOn23.isEmpty());
- assertEquals(4, inspector.allClasses().size());
- assertEquals(2, outlinedAddedOn27.size());
- assertTrue(
- outlinedAddedOn27.stream()
- .allMatch(
- outline ->
- outline.getMethod().getHolderType()
- == outlinedAddedOn27.get(0).getMethod().getHolderType()));
- } else {
- // No outlining on this api level.
- assertTrue(outlinedAddedOn23.isEmpty());
- assertTrue(outlinedAddedOn27.isEmpty());
- assertEquals(3, inspector.allClasses().size());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ List<FoundMethodSubject> outlinedAddedOn23 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn23").matches(methodSubject))
+ .collect(Collectors.toList());
+ List<FoundMethodSubject> outlinedAddedOn27 =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("addedOn27").matches(methodSubject))
+ .collect(Collectors.toList());
+ if (parameters.isCfRuntime()) {
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertTrue(outlinedAddedOn27.isEmpty());
+ assertEquals(3, inspector.allClasses().size());
+ } else if (parameters.getApiLevel().isLessThan(firstMethodApiLevel)) {
+ // We have generated 4 outlines two having api level 23 and two having api level 27.
+ // Check that the levels are horizontally merged.
+ assertEquals(5, inspector.allClasses().size());
+ assertEquals(2, outlinedAddedOn23.size());
+ assertTrue(
+ outlinedAddedOn23.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn23.get(0).getMethod().getHolderType()));
+ assertEquals(2, outlinedAddedOn27.size());
+ assertTrue(
+ outlinedAddedOn27.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn27.get(0).getMethod().getHolderType()));
+ } else if (parameters.getApiLevel().isLessThan(secondMethodApiLevel)) {
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertEquals(4, inspector.allClasses().size());
+ assertEquals(2, outlinedAddedOn27.size());
+ assertTrue(
+ outlinedAddedOn27.stream()
+ .allMatch(
+ outline ->
+ outline.getMethod().getHolderType()
+ == outlinedAddedOn27.get(0).getMethod().getHolderType()));
+ } else {
+ // No outlining on this api level.
+ assertTrue(outlinedAddedOn23.isEmpty());
+ assertTrue(outlinedAddedOn27.isEmpty());
+ assertEquals(3, inspector.allClasses().size());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
index 89c2f76..2411e94 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodAndStubClassTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
@@ -20,6 +21,7 @@
import com.android.tools.r8.apimodel.ApiModelMockClassTest.TestClass;
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;
@@ -51,6 +53,8 @@
.addDefaultRuntimeLibrary(parameters)
.setMinApi(parameters.getApiLevel())
.addAndroidBuildVersion()
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableStubbingOfClasses)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(setMockApiLevelForClass(LibraryClass.class, libraryClassLevel))
@@ -64,19 +68,35 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -92,13 +112,14 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
- verifyThat(inspector, parameters, apiMethod())
- .isOutlinedFromUntil(
- Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryClassLevel);
+ verifyThat(inspector, parameters, apiMethod())
+ .isOutlinedFromUntil(
+ Main.class.getDeclaredMethod("main", String[].class), libraryMethodLevel);
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index 8ee8ad4..cf440c9 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -16,6 +16,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -25,6 +26,7 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Method;
@@ -69,6 +71,8 @@
LibraryClass.class, initialLibraryMockLevel))
.apply(setMockApiLevelForMethod(addedOn23(), initialLibraryMockLevel))
.apply(setMockApiLevelForMethod(addedOn27(), finalLibraryMethodLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -82,19 +86,34 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8(parameters.getBackend())
+ .setMode(CompilationMode.DEBUG)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- // TODO(b/213552119): Assert that we did not outline any methods.
- .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses);
+ .inspect(this::inspect);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8(parameters.getBackend())
+ .setMode(CompilationMode.RELEASE)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput)
+ .inspect(this::inspect);
}
@Test
@@ -111,40 +130,37 @@
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
.run(parameters.getRuntime(), Main.class)
.apply(this::checkOutput)
- .inspect(
- inspector -> {
- // No need to check further on CF.
- if (parameters.isCfRuntime()) {
- assertEquals(3, inspector.allClasses().size());
- return;
- }
- Method testMethod = TestClass.class.getDeclaredMethod("test");
- MethodSubject testMethodSubject = inspector.method(testMethod);
- assertThat(testMethodSubject, isPresent());
- Optional<FoundMethodSubject> synthesizedMissingNotReferenced =
- inspector.allClasses().stream()
- .flatMap(clazz -> clazz.allMethods().stream())
- .filter(
- methodSubject ->
- methodSubject.isSynthetic()
- && invokesMethodWithName("missingNotReferenced")
- .matches(methodSubject))
- .findFirst();
- assertFalse(synthesizedMissingNotReferenced.isPresent());
- verifyThat(inspector, parameters, addedOn23()).isNotOutlinedFrom(testMethod);
- verifyThat(inspector, parameters, addedOn27())
- .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
- verifyThat(
- inspector,
- parameters,
- LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
- .isNotOutlinedFrom(testMethod);
- if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
- assertEquals(4, inspector.allClasses().size());
- } else {
- assertEquals(3, inspector.allClasses().size());
- }
- });
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) throws Exception {
+ // No need to check further on CF.
+ if (parameters.isCfRuntime()) {
+ assertEquals(3, inspector.allClasses().size());
+ return;
+ }
+ Method testMethod = TestClass.class.getDeclaredMethod("test");
+ MethodSubject testMethodSubject = inspector.method(testMethod);
+ assertThat(testMethodSubject, isPresent());
+ Optional<FoundMethodSubject> synthesizedMissingNotReferenced =
+ inspector.allClasses().stream()
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .filter(
+ methodSubject ->
+ methodSubject.isSynthetic()
+ && invokesMethodWithName("missingNotReferenced").matches(methodSubject))
+ .findFirst();
+ assertFalse(synthesizedMissingNotReferenced.isPresent());
+ verifyThat(inspector, parameters, addedOn23()).isNotOutlinedFrom(testMethod);
+ verifyThat(inspector, parameters, addedOn27())
+ .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
+ verifyThat(inspector, parameters, LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
+ .isNotOutlinedFrom(testMethod);
+ if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
+ assertEquals(4, inspector.allClasses().size());
+ } else {
+ assertEquals(3, inspector.allClasses().size());
+ }
}
private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
index 4428a33..d63e01b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodProtectedTest.java
@@ -10,6 +10,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.SingleTestRunResult;
@@ -73,6 +74,8 @@
.transform())
.setMinApi(AndroidApiLevel.B)
.addAndroidBuildVersion(runApiLevel())
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
.apply(setMockApiLevelForDefaultInstanceInitializer(LibraryClass.class, classApiLevel))
.apply(
@@ -89,12 +92,28 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
.applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
index 2461448..940864c 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodUnknownTest.java
@@ -8,6 +8,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
@@ -42,6 +43,8 @@
.setMinApi(parameters.getApiLevel())
.addAndroidBuildVersion()
.apply(setMockApiLevelForClass(LibraryClass.class, classApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@@ -52,12 +55,30 @@
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()
&& parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ // Assert that we did not outline any methods.
+ .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
+ .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkOutput);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeFalse(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.RELEASE)
.apply(this::setupTestBuilder)
.compile()
// Assert that we did not outline any methods.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
index 9e8115d..94ae936 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlinePackagePrivateTest.java
@@ -9,6 +9,7 @@
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -83,12 +84,31 @@
.apply(
setMockApiLevelForMethod(
LibraryClass.class.getDeclaredMethod("addedOn10"), methodApiLevel))
+ // TODO(b/213552119): Remove when enabled by default.
+ .apply(ApiModelingTestHelper::enableApiCallerIdentification)
.apply(ApiModelingTestHelper::enableOutliningOfMethods)
.apply(ApiModelingTestHelper::disableStubbingOfClasses);
}
@Test
- public void testD8() throws Exception {
+ public void testD8Debug() throws Exception {
+ // TODO(b/197078995): Make this work on 12+.
+ assumeTrue(
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0));
+ testForD8()
+ .setMode(CompilationMode.DEBUG)
+ .apply(this::setupTestBuilder)
+ .compile()
+ // Assert that we did not outline any methods.
+ .inspect(ApiModelingTestHelper::assertNoSynthesizedClasses)
+ .applyIf(willInvokeLibraryMethods(), b -> b.addBootClasspathClasses(LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::checkResultOnBootClassPath);
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
// TODO(b/197078995): Make this work on 12+.
assumeTrue(
parameters.isDexRuntime()