Reenable startup tests
Bug: b/271822426
Change-Id: I1a303235e6250468b8137cc799f506d3989c3c61
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
index e8be76e..b85dbaa 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -62,14 +62,7 @@
missingItemsDiagnosticBuilderFactory) {
StartupProfile startupProfile =
StartupProfile.parseStartupProfile(options, missingItemsDiagnosticBuilderFactory);
- if (startupProfile == null || startupProfile.isEmpty()) {
- return empty();
- }
- StartupProfile.Builder builder = StartupProfile.builder();
- for (StartupProfileRule startupItem : startupProfile.getRules()) {
- builder.addStartupItem(startupItem);
- }
- return builder.build();
+ return startupProfile != null ? startupProfile : empty();
}
public static StartupProfile createInitialStartupProfileForD8(AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java
index a5145f4..bb1bbc9 100644
--- a/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java
@@ -37,6 +37,10 @@
return COMPARATOR;
}
+ public static TypeReference getVoidType() {
+ return null;
+ }
+
public static DexProto toDexProto(
List<TypeReference> formalTypes, TypeReference returnType, DexItemFactory dexItemFactory) {
return toDexProto(
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
index 703c916..92d3129 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.graph.DexProgramClass;
@@ -29,6 +30,7 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.TypeReferenceUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -36,11 +38,11 @@
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -50,6 +52,11 @@
@RunWith(Parameterized.class)
public class StartupSyntheticPlacementTest extends TestBase {
+ private enum Compiler {
+ D8,
+ R8
+ }
+
@Parameter(0)
public TestParameters parameters;
@@ -120,12 +127,11 @@
.compile()
.inspectMultiDex(
r8CompileResult.writeProguardMap(), this::inspectPrimaryDex, this::inspectSecondaryDex)
+ .apply(this::checkCompleteness)
.run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
.assertSuccessWithOutputLines(getExpectedOutput());
}
- // TODO(b/271822426): Reenable test.
- @Ignore("b/271822426")
@Test
public void testLayoutUsingR8() throws Exception {
// First generate a startup list for the original app.
@@ -161,11 +167,17 @@
.setMinApi(parameters)
.compile()
.inspectMultiDex(this::inspectPrimaryDex, this::inspectSecondaryDex)
+ .apply(this::checkCompleteness)
.run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
- .applyIf(
- enableStartupCompletenessCheck && useLambda,
- runResult -> runResult.assertFailureWithErrorThatThrows(NullPointerException.class),
- runResult -> runResult.assertSuccessWithOutputLines(getExpectedOutput()));
+ .assertSuccessWithOutputLines(getExpectedOutput());
+ }
+
+ private void checkCompleteness(TestCompileResult<?, ?> compileResult) throws Exception {
+ if (enableStartupCompletenessCheck && !useLambda) {
+ compileResult
+ .run(parameters.getRuntime(), Main.class, "true")
+ .assertFailureWithErrorThatThrows(NullPointerException.class);
+ }
}
private void configureStartupOptions(
@@ -182,7 +194,7 @@
options
.getTestingOptions()
.setMixedSectionLayoutStrategyInspector(
- getMixedSectionLayoutInspector(inspector));
+ getMixedSectionLayoutInspector(inspector, testBuilder.isD8TestBuilder()));
})
.apply(ignore -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList));
}
@@ -212,12 +224,35 @@
Reference.methodFromMethod(B.class.getDeclaredMethod("b", boolean.class)))
.build());
if (useLambda) {
+ builder.add(
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ Reference.methodFromMethod(B.class.getDeclaredMethod("synthesize")))
+ .build());
if (isStartupListForOriginalApp) {
- // TODO(b/271822426): Update after rewriting startup profile.
- /*builder.add(
- ExternalSyntheticStartupMethod.builder()
- .setSyntheticContextReference(Reference.classFromClass(B.class))
- .build());*/
+ ClassReference syntheticLambdaClassReference = getSyntheticLambdaClassReference();
+ builder.add(
+ ExternalStartupClass.builder().setClassReference(syntheticLambdaClassReference).build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ MethodReferenceUtils.instanceConstructor(syntheticLambdaClassReference))
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ Reference.method(
+ syntheticLambdaClassReference,
+ "accept",
+ Collections.singletonList(Reference.classFromClass(Object.class)),
+ TypeReferenceUtils.getVoidType()))
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ Reference.method(
+ Reference.classFromClass(B.class),
+ "lambda$synthesize$0",
+ Collections.singletonList(Reference.classFromClass(Object.class)),
+ TypeReferenceUtils.getVoidType()))
+ .build());
} else {
ClassSubject bClassSubject = inspector.clazz(B.class);
@@ -264,7 +299,8 @@
builder.add(
ExternalStartupMethod.builder()
.setMethodReference(
- Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0", Object.class)))
+ Reference.methodFromMethod(
+ B.class.getDeclaredMethod("lambda$synthesize$0", Object.class)))
.build());
}
builder.add(
@@ -276,7 +312,7 @@
}
private List<ClassReference> getExpectedClassDataLayout(
- CodeInspector inspector, int virtualFile) {
+ CodeInspector inspector, boolean isD8, int virtualFile) {
ClassSubject syntheticLambdaClassSubject = inspector.clazz(getSyntheticLambdaClassReference());
// The synthetic lambda should only be placed alongside its synthetic context (B) if it is used.
@@ -287,10 +323,17 @@
Reference.classFromClass(Main.class),
Reference.classFromClass(A.class),
Reference.classFromClass(B.class));
- if (useLambda) {
- layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference());
+ if (isD8) {
+ if (useLambda) {
+ layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference());
+ }
+ layoutBuilder.add(Reference.classFromClass(C.class));
+ } else {
+ layoutBuilder.add(Reference.classFromClass(C.class));
+ if (useLambda) {
+ layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference());
+ }
}
- layoutBuilder.add(Reference.classFromClass(C.class));
}
if (!useLambda) {
if (!enableMinimalStartupDex || virtualFile == 1) {
@@ -300,12 +343,14 @@
return layoutBuilder.build();
}
- private MixedSectionLayoutInspector getMixedSectionLayoutInspector(CodeInspector inspector) {
+ private MixedSectionLayoutInspector getMixedSectionLayoutInspector(
+ CodeInspector inspector, boolean isD8) {
return new MixedSectionLayoutInspector() {
@Override
public void inspectClassDataLayout(int virtualFile, Collection<DexProgramClass> layout) {
assertThat(
- layout, isEqualToClassDataLayout(getExpectedClassDataLayout(inspector, virtualFile)));
+ layout,
+ isEqualToClassDataLayout(getExpectedClassDataLayout(inspector, isD8, virtualFile)));
}
};
}
@@ -355,11 +400,15 @@
static void b(boolean useLambda) {
String message = System.currentTimeMillis() > 0 ? "B" : null;
if (useLambda) {
- Consumer<Object> consumer = obj -> {};
- consumer.accept(consumer);
+ synthesize();
}
System.out.println(message);
}
+
+ static void synthesize() {
+ Consumer<Object> consumer = obj -> {};
+ consumer.accept(consumer);
+ }
}
static class C {
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
index 9bde49b..14a1e1b 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
@@ -26,14 +26,15 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.TypeReferenceUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -61,10 +62,8 @@
BooleanUtils.values());
}
- // TODO(b/271822426): Reenable test.
- @Ignore("b/271822426")
@Test
- public void test() throws Exception {
+ public void testR8() throws Exception {
LinkedHashSet<ExternalStartupItem> startupList = new LinkedHashSet<>();
testForD8(parameters.getBackend())
.addInnerClasses(getClass())
@@ -121,10 +120,21 @@
ExternalStartupMethod.builder()
.setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("b")))
.build(),
- // TODO(b/271822426): Update after rewriting startup profile.
- /*ExternalSyntheticStartupMethod.builder()
- .setSyntheticContextReference(Reference.classFromClass(B.class))
- .build(),*/
+ ExternalStartupClass.builder()
+ .setClassReference(getSyntheticLambdaClassReference(B.class))
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ MethodReferenceUtils.instanceConstructor(getSyntheticLambdaClassReference(B.class)))
+ .build(),
+ ExternalStartupMethod.builder()
+ .setMethodReference(
+ Reference.method(
+ getSyntheticLambdaClassReference(B.class),
+ "run",
+ Collections.emptyList(),
+ TypeReferenceUtils.getVoidType()))
+ .build(),
ExternalStartupMethod.builder()
.setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0")))
.build(),
@@ -140,8 +150,8 @@
builder.add(
Reference.classFromClass(Main.class),
Reference.classFromClass(A.class),
- getSyntheticLambdaClassReference(B.class),
- Reference.classFromClass(C.class));
+ Reference.classFromClass(C.class),
+ getSyntheticLambdaClassReference(B.class));
}
if (!enableMinimalStartupDex || virtualFile == 1) {
builder.add(getSyntheticLambdaClassReference(Main.class));
@@ -186,13 +196,15 @@
public static void main(String[] args) {
A.a();
- Runnable r = System.currentTimeMillis() > 0 ? B.b() : Main::error;
+ Runnable r = System.currentTimeMillis() > 0 ? B.b() : error();
r.run();
C.c();
}
- static void error() {
- throw new RuntimeException();
+ static Runnable error() {
+ return () -> {
+ throw new RuntimeException();
+ };
}
}
@@ -203,6 +215,8 @@
}
}
+ // Class B will be pruned as a result of inlining, yet the synthetic derived from B.b() remains in
+ // the startup list.
static class B {
static Runnable b() {
diff --git a/src/test/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnosticTest.java b/src/test/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnosticTest.java
index c7c5eef..5cf70dd 100644
--- a/src/test/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnosticTest.java
+++ b/src/test/java/com/android/tools/r8/startup/diagnostic/MissingStartupProfileItemsDiagnosticTest.java
@@ -9,6 +9,7 @@
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
+import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
@@ -23,7 +24,6 @@
import com.android.tools.r8.utils.StringUtils;
import java.util.Collection;
import java.util.Collections;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,29 +41,35 @@
return getTestParameters().withNoneRuntime().build();
}
- // TODO(b/271822426): Reenable test.
- @Ignore("b/271822426")
@Test
public void testD8() throws Exception {
+ // In D8 the startup profile is used to relayout an existing apk. Therefore, we first compile
+ // the program to dex, and then relayout the dex using D8 with a startup profile.
+ D8TestCompileResult compileResult =
+ testForD8(Backend.DEX)
+ .addProgramClasses(Main.class)
+ .release()
+ .setMinApi(AndroidApiLevel.LATEST)
+ .compile();
testForD8(Backend.DEX)
- .addProgramClasses(Main.class)
+ .addProgramFiles(compileResult.writeToZip())
.addStartupProfileProviders(getStartupProfileProviders())
.release()
.setMinApi(AndroidApiLevel.LATEST)
.compileWithExpectedDiagnostics(this::inspectDiagnostics);
}
- // TODO(b/271822426): Reenable test.
- @Ignore("b/271822426")
@Test
public void testR8() throws Exception {
+ // In R8 we expect a startup profile that matches the input app. Since profiles gathered from
+ // running on ART will include synthetics, and these synthetics are not in the input app, we do
+ // not raise warnings if some rules in the profile do not match anything.
testForR8(Backend.DEX)
.addProgramClasses(Main.class)
.addKeepMainRule(Main.class)
.addStartupProfileProviders(getStartupProfileProviders())
- .allowDiagnosticWarningMessages()
.setMinApi(AndroidApiLevel.LATEST)
- .compileWithExpectedDiagnostics(this::inspectDiagnostics);
+ .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages);
}
private static Collection<StartupProfileProvider> getStartupProfileProviders() {
@@ -73,7 +79,6 @@
public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) {
ClassReference fooClassReference = Reference.classFromTypeName("Foo");
ClassReference barClassReference = Reference.classFromTypeName("Bar");
- ClassReference bazClassReference = Reference.classFromTypeName("Baz");
ClassReference jDollarClassReference = Reference.classFromTypeName("j$.Foo");
startupProfileBuilder
.addStartupClass(
@@ -82,11 +87,6 @@
startupMethodBuilder ->
startupMethodBuilder.setMethodReference(
MethodReferenceUtils.mainMethod(barClassReference)))
- // TODO(b/271822426): Update after rewriting startup profile.
- /*.addSyntheticStartupMethod(
- syntheticStartupMethodBuilder ->
- syntheticStartupMethodBuilder.setSyntheticContextReference(
- bazClassReference))*/
.addStartupClass(
startupClassBuilder ->
startupClassBuilder.setClassReference(jDollarClassReference));
@@ -108,7 +108,6 @@
equalTo(
StringUtils.joinLines(
"Startup method not found: void Bar.main(java.lang.String[])",
- "Startup class not found: Baz",
"Startup class not found: Foo")))));
}