Add a test for lambda merging in presence of enum unboxing
Change-Id: Id79511f8a927ec23f04d217dde56e714b5ac8658
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 59c7b8e..0d6b606 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -445,6 +445,9 @@
HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses) {
assert this.horizontallyMergedLambdaClasses == null;
this.horizontallyMergedLambdaClasses = horizontallyMergedLambdaClasses;
+ testing()
+ .horizontallyMergedLambdaClassesConsumer
+ .accept(dexItemFactory(), horizontallyMergedLambdaClasses);
}
/**
@@ -471,9 +474,7 @@
public void setVerticallyMergedClasses(VerticallyMergedClasses verticallyMergedClasses) {
assert this.verticallyMergedClasses == null;
this.verticallyMergedClasses = verticallyMergedClasses;
- if (testing().verticallyMergedClassesConsumer != null) {
- testing().verticallyMergedClassesConsumer.accept(dexItemFactory(), verticallyMergedClasses);
- }
+ testing().verticallyMergedClassesConsumer.accept(dexItemFactory(), verticallyMergedClasses);
}
public EnumValueInfoMapCollection unboxedEnums() {
@@ -481,7 +482,9 @@
}
public void setUnboxedEnums(EnumValueInfoMapCollection unboxedEnums) {
+ assert this.unboxedEnums.isEmpty();
this.unboxedEnums = unboxedEnums;
+ testing().unboxedEnumsConsumer.accept(dexItemFactory(), unboxedEnums);
}
public boolean validateUnboxedEnumsHaveBeenPruned() {
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
index 505dfd5..285e397 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.ImmutableSet;
import java.util.Set;
public class HorizontallyMergedLambdaClasses implements MergedClasses {
@@ -17,6 +18,10 @@
this.sources = sources;
}
+ public static HorizontallyMergedLambdaClasses empty() {
+ return new HorizontallyMergedLambdaClasses(ImmutableSet.of());
+ }
+
@Override
public boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView) {
for (DexType source : sources) {
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 f475e89..b7964c8 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
@@ -22,8 +22,10 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.ir.analysis.TypeChecker;
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
@@ -705,6 +707,8 @@
}
if (enumUnboxer != null) {
enumUnboxer.unboxEnums(postMethodProcessorBuilder, executorService, feedback);
+ } else {
+ appView.setUnboxedEnums(EnumValueInfoMapCollection.empty());
}
if (!options.debug) {
new TrivialFieldAccessReprocessor(appView.withLiveness(), postMethodProcessorBuilder)
@@ -935,7 +939,10 @@
if (lambdaMerger != null) {
lambdaMerger.applyLambdaClassMapping(
application, this, feedback, builder, executorService);
+ } else {
+ appView.setHorizontallyMergedLambdaClasses(HorizontallyMergedLambdaClasses.empty());
}
+ assert appView.horizontallyMergedLambdaClasses() != null;
}
private void generateDesugaredLibraryAPIWrappers(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 3bb366d..ee35087 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -252,15 +252,16 @@
.filter(cls -> !appView.appInfo().isPinned(cls.type))
.filter(
cls ->
- cls.getKotlinInfo().isSyntheticClass()
- && cls.getKotlinInfo().asSyntheticClass().isLambda()
+ appView.testing().kotlinLambdaMergerFactoryForClass.apply(cls) != null
&& KotlinLambdaGroupIdFactory.hasValidAnnotations(kotlin, cls)
&& !appView.appInfo().getClassToFeatureSplitMap().isInFeature(cls))
.sorted((a, b) -> a.type.slowCompareTo(b.type)) // Ensure stable ordering.
.forEachOrdered(
lambda -> {
try {
- LambdaGroupId id = KotlinLambdaGroupIdFactory.create(appView, kotlin, lambda);
+ KotlinLambdaGroupIdFactory lambdaGroupIdFactory =
+ appView.testing().kotlinLambdaMergerFactoryForClass.apply(lambda);
+ LambdaGroupId id = lambdaGroupIdFactory.validateAndCreate(appView, kotlin, lambda);
LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup);
group.add(lambda);
lambdas.put(lambda.type, group);
@@ -341,6 +342,7 @@
ExecutorService executorService)
throws ExecutionException {
if (lambdas.isEmpty()) {
+ appView.setHorizontallyMergedLambdaClasses(HorizontallyMergedLambdaClasses.empty());
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java
index 2e4e1a9..df72677 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java
@@ -15,19 +15,22 @@
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-final class JStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
- static final JStyleLambdaGroupIdFactory INSTANCE = new JStyleLambdaGroupIdFactory();
+public final class JStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
+ private static final JStyleLambdaGroupIdFactory INSTANCE = new JStyleLambdaGroupIdFactory();
+
+ private JStyleLambdaGroupIdFactory() {}
+
+ public static JStyleLambdaGroupIdFactory getInstance() {
+ return INSTANCE;
+ }
@Override
- LambdaGroupId validateAndCreate(
+ public LambdaGroupId validateAndCreate(
AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
throws LambdaStructureError {
boolean accessRelaxed =
appView.options().getProguardConfiguration().isAccessModificationAllowed();
- assert lambda.getKotlinInfo().isSyntheticClass();
- assert lambda.getKotlinInfo().asSyntheticClass().isJavaStyleLambda();
-
// Ignore ACC_SUPER.
ClassAccessFlags copy = lambda.accessFlags.copy();
copy.unsetSuper();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java
index 6f7650b..cc212bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java
@@ -15,19 +15,22 @@
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-final class KStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
- static final KotlinLambdaGroupIdFactory INSTANCE = new KStyleLambdaGroupIdFactory();
+public final class KStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
+ private static final KStyleLambdaGroupIdFactory INSTANCE = new KStyleLambdaGroupIdFactory();
+
+ private KStyleLambdaGroupIdFactory() {}
+
+ public static KStyleLambdaGroupIdFactory getInstance() {
+ return INSTANCE;
+ }
@Override
- LambdaGroupId validateAndCreate(
+ public LambdaGroupId validateAndCreate(
AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
throws LambdaStructureError {
boolean accessRelaxed =
appView.options().getProguardConfiguration().isAccessModificationAllowed();
- assert lambda.getKotlinInfo().isSyntheticClass();
- assert lambda.getKotlinInfo().asSyntheticClass().isKotlinStyleLambda();
-
// Ignore ACC_SUPER.
ClassAccessFlags copy = lambda.accessFlags.copy();
copy.unsetSuper();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
index 5a90f80..472d861 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
@@ -23,27 +24,26 @@
KotlinLambdaGroupIdFactory() {
}
- // Creates a lambda group id for kotlin style lambda. Should never return null, if the lambda
- // does not pass pre-requirements (mostly by not meeting high-level structure expectations)
- // should throw LambdaStructureError leaving the caller to decide if/how it needs to be reported.
+ public static KotlinLambdaGroupIdFactory getFactoryForClass(DexProgramClass clazz) {
+ if (clazz.getKotlinInfo().isSyntheticClass()
+ && clazz.getKotlinInfo().asSyntheticClass().isLambda()) {
+ if (clazz.getKotlinInfo().asSyntheticClass().isKotlinStyleLambda()) {
+ return KStyleLambdaGroupIdFactory.getInstance();
+ }
+ assert clazz.getKotlinInfo().asSyntheticClass().isJavaStyleLambda();
+ return JStyleLambdaGroupIdFactory.getInstance();
+ }
+ return null;
+ }
+
+ // Creates a lambda group id for a Java or Kotlin style lambda. Never returns null, but may throw
+ // a LambdaStructureError if the lambda does not pass pre-requirements (mostly by not meeting
+ // high-level structure expectations).
//
// At this point we only perform high-level checks before qualifying the lambda as a candidate
// for merging and assigning lambda group id. We can NOT perform checks on method bodies since
// they may not be converted yet, we'll do that in KStyleLambdaClassValidator.
- public static LambdaGroupId create(
- AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
- throws LambdaStructureError {
-
- assert lambda.getKotlinInfo().isSyntheticClass();
- if (lambda.getKotlinInfo().asSyntheticClass().isKotlinStyleLambda()) {
- return KStyleLambdaGroupIdFactory.INSTANCE.validateAndCreate(appView, kotlin, lambda);
- }
-
- assert lambda.getKotlinInfo().asSyntheticClass().isJavaStyleLambda();
- return JStyleLambdaGroupIdFactory.INSTANCE.validateAndCreate(appView, kotlin, lambda);
- }
-
- abstract LambdaGroupId validateAndCreate(
+ public abstract LambdaGroupId validateAndCreate(
AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
throws LambdaStructureError;
diff --git a/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java b/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
index c1c7d5a..8d66524 100644
--- a/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ConsumerUtils.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.utils;
import java.util.Set;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class ConsumerUtils {
@@ -21,6 +22,10 @@
return ignore -> {};
}
+ public static <S, T> BiConsumer<S, T> emptyBiConsumer() {
+ return (s, t) -> {};
+ }
+
public static <T> ThrowingConsumer<T, RuntimeException> emptyThrowingConsumer() {
return ignore -> {};
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index eb2d165..60153de 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -33,14 +33,18 @@
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.optimize.Inliner;
+import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.references.Reference;
@@ -1215,6 +1219,9 @@
public BiConsumer<AppInfoWithLiveness, Enqueuer.Mode> enqueuerInspector = null;
+ public Function<DexProgramClass, KotlinLambdaGroupIdFactory> kotlinLambdaMergerFactoryForClass =
+ KotlinLambdaGroupIdFactory::getFactoryForClass;
+
public BiConsumer<ProgramMethod, MethodProcessingId> methodProcessingIdConsumer = null;
public Function<AppView<AppInfoWithLiveness>, RepackagingConfiguration>
@@ -1223,8 +1230,14 @@
new DefaultRepackagingConfiguration(
appView.dexItemFactory(), appView.options().getProguardConfiguration());
+ public BiConsumer<DexItemFactory, HorizontallyMergedLambdaClasses>
+ horizontallyMergedLambdaClassesConsumer = ConsumerUtils.emptyBiConsumer();
+
+ public BiConsumer<DexItemFactory, EnumValueInfoMapCollection> unboxedEnumsConsumer =
+ ConsumerUtils.emptyBiConsumer();
+
public BiConsumer<DexItemFactory, VerticallyMergedClasses> verticallyMergedClassesConsumer =
- null;
+ ConsumerUtils.emptyBiConsumer();
public Consumer<Deque<SortedProgramMethodSet>> waveModifier = waves -> {};
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 1fa6604..e73dec3 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -10,8 +10,6 @@
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.testing.AndroidBuildVersion;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
@@ -19,6 +17,9 @@
import com.android.tools.r8.utils.ForwardingOutputStream;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingOutputStream;
+import com.android.tools.r8.utils.codeinspector.EnumUnboxingInspector;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedLambdaClassesInspector;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import com.google.common.base.Suppliers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -28,7 +29,6 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -106,10 +106,34 @@
});
}
- public T addVerticallyMergedClassesInspector(
- BiConsumer<DexItemFactory, VerticallyMergedClasses> inspector) {
+ public T addEnumUnboxingInspector(Consumer<EnumUnboxingInspector> inspector) {
return addOptionsModification(
- options -> options.testing.verticallyMergedClassesConsumer = inspector);
+ options ->
+ options.testing.unboxedEnumsConsumer =
+ ((dexItemFactory, unboxedEnums) ->
+ inspector.accept(new EnumUnboxingInspector(dexItemFactory, unboxedEnums))));
+ }
+
+ public T addHorizontallyMergedLambdaClassesInspector(
+ Consumer<HorizontallyMergedLambdaClassesInspector> inspector) {
+ return addOptionsModification(
+ options ->
+ options.testing.horizontallyMergedLambdaClassesConsumer =
+ ((dexItemFactory, horizontallyMergedLambdaClasses) ->
+ inspector.accept(
+ new HorizontallyMergedLambdaClassesInspector(
+ dexItemFactory, horizontallyMergedLambdaClasses))));
+ }
+
+ public T addVerticallyMergedClassesInspector(
+ Consumer<VerticallyMergedClassesInspector> inspector) {
+ return addOptionsModification(
+ options ->
+ options.testing.verticallyMergedClassesConsumer =
+ ((dexItemFactory, verticallyMergedClasses) ->
+ inspector.accept(
+ new VerticallyMergedClassesInspector(
+ dexItemFactory, verticallyMergedClasses))));
}
public CR compile() throws CompilationFailedException {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ClassesHaveBeenMergedTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ClassesHaveBeenMergedTest.java
index 11330ba..6ed6dd9 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ClassesHaveBeenMergedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ClassesHaveBeenMergedTest.java
@@ -13,9 +13,8 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -48,12 +47,12 @@
.assertSuccess();
}
- private void inspectVerticallyMergedClasses(
- DexItemFactory dexItemFactory, VerticallyMergedClasses verticallyMergedClasses) {
- assertMergedIntoSubtype(GenericInterface.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(GenericAbstractClass.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(Outer.SuperClass.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(SuperClass.class, dexItemFactory, verticallyMergedClasses);
+ private void inspectVerticallyMergedClasses(VerticallyMergedClassesInspector inspector) {
+ inspector.assertMergedIntoSubtype(
+ GenericInterface.class,
+ GenericAbstractClass.class,
+ Outer.SuperClass.class,
+ SuperClass.class);
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
index ababe2f..ffe849e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
@@ -12,10 +12,9 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import java.util.stream.IntStream;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,10 +48,8 @@
.assertSuccess();
}
- private void inspectVerticallyMergedClasses(
- DexItemFactory dexItemFactory, VerticallyMergedClasses verticallyMergedClasses) {
- assertMergedIntoSubtype(ExceptionA.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(Exception1.class, dexItemFactory, verticallyMergedClasses);
+ private void inspectVerticallyMergedClasses(VerticallyMergedClassesInspector inspector) {
+ inspector.assertMergedIntoSubtype(ExceptionA.class, Exception1.class);
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/NoIllegalClassAccessWithAccessModificationsTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/NoIllegalClassAccessWithAccessModificationsTest.java
index a0e15f7..35e27eb 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/NoIllegalClassAccessWithAccessModificationsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/NoIllegalClassAccessWithAccessModificationsTest.java
@@ -15,9 +15,8 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.classmerging.vertical.testclasses.NoIllegalClassAccessWithAccessModificationsTestClasses;
import com.android.tools.r8.classmerging.vertical.testclasses.NoIllegalClassAccessWithAccessModificationsTestClasses.SimpleInterfaceFactory;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -51,10 +50,8 @@
.assertSuccess();
}
- private void inspectVerticallyMergedClasses(
- DexItemFactory dexItemFactory, VerticallyMergedClasses verticallyMergedClasses) {
- assertMergedIntoSubtype(SimpleInterface.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(OtherSimpleInterface.class, dexItemFactory, verticallyMergedClasses);
+ private void inspectVerticallyMergedClasses(VerticallyMergedClassesInspector inspector) {
+ inspector.assertMergedIntoSubtype(SimpleInterface.class, OtherSimpleInterface.class);
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/SyntheticBridgeSignaturesTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/SyntheticBridgeSignaturesTest.java
index 7282401..829e56b 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/SyntheticBridgeSignaturesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/SyntheticBridgeSignaturesTest.java
@@ -13,11 +13,10 @@
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import org.junit.Test;
@@ -74,10 +73,8 @@
}
}
- private void inspectVerticallyMergedClasses(
- DexItemFactory dexItemFactory, VerticallyMergedClasses verticallyMergedClasses) {
- assertMergedIntoSubtype(A.class, dexItemFactory, verticallyMergedClasses);
- assertMergedIntoSubtype(B.class, dexItemFactory, verticallyMergedClasses);
+ private void inspectVerticallyMergedClasses(VerticallyMergedClassesInspector inspector) {
+ inspector.assertMergedIntoSubtype(A.class, B.class);
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTestBase.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTestBase.java
index 106c8c0..c11fcbd 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTestBase.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTestBase.java
@@ -20,13 +20,6 @@
this.parameters = parameters;
}
- public static void assertMergedIntoSubtype(
- Class<?> clazz,
- DexItemFactory dexItemFactory,
- VerticallyMergedClasses verticallyMergedClasses) {
- assertTrue(verticallyMergedClasses.hasBeenMergedIntoSubtype(toDexType(clazz, dexItemFactory)));
- }
-
public void runDebugTest(Class<?> mainClass, R8TestCompileResult compileResult) throws Throwable {
assertTrue(parameters.isDexRuntime());
new VerticalClassMergerDebugTestRunner(mainClass.getTypeName(), temp)
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
new file mode 100644
index 0000000..eb7b242
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -0,0 +1,122 @@
+// Copyright (c) 2020, 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.kotlin.lambda;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.ir.optimize.lambda.kotlin.JStyleLambdaGroupIdFactory;
+import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
+import com.android.tools.r8.kotlin.lambda.JStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class JStyleKotlinLambdaMergingWithEnumUnboxingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public JStyleKotlinLambdaMergingWithEnumUnboxingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options ->
+ options.testing.kotlinLambdaMergerFactoryForClass =
+ this::getKotlinLambdaMergerFactoryForClass)
+ .addHorizontallyMergedLambdaClassesInspector(
+ inspector -> inspector.assertMerged(Lambda1.class, Lambda2.class))
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(EnumUnboxingCandidate.class))
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Lambda1.method()", "Lambda2.method()");
+ }
+
+ private KotlinLambdaGroupIdFactory getKotlinLambdaMergerFactoryForClass(DexProgramClass clazz) {
+ String typeName = clazz.getType().toSourceString();
+ if (typeName.equals(Lambda1.class.getTypeName())
+ || typeName.equals(Lambda2.class.getTypeName())) {
+ return JStyleLambdaGroupIdFactory.getInstance();
+ }
+ return null;
+ }
+
+ static class Main {
+
+ @NeverClassInline
+ public enum EnumUnboxingCandidate {
+ LAMBDA1,
+ LAMBDA2
+ }
+
+ public static void main(String[] args) {
+ accept(createLambda(EnumUnboxingCandidate.LAMBDA1));
+ accept(createLambda(EnumUnboxingCandidate.LAMBDA2));
+ }
+
+ @NeverInline
+ static I createLambda(EnumUnboxingCandidate value) {
+ switch (value) {
+ case LAMBDA1:
+ return new Lambda1();
+ case LAMBDA2:
+ return new Lambda2();
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ @NeverInline
+ static void accept(I instance) {
+ instance.method();
+ }
+ }
+
+ interface I {
+
+ void method();
+ }
+
+ @NeverClassInline
+ public static final class Lambda1 implements I {
+
+ @NeverInline
+ @Override
+ public final void method() {
+ System.out.println("Lambda1.method()");
+ }
+ }
+
+ @NeverClassInline
+ public static final class Lambda2 implements I {
+
+ @NeverInline
+ @Override
+ public final void method() {
+ System.out.println("Lambda2.method()");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
new file mode 100644
index 0000000..61abad2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -0,0 +1,129 @@
+// Copyright (c) 2020, 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.kotlin.lambda;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.ir.optimize.lambda.kotlin.KStyleLambdaGroupIdFactory;
+import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
+import com.android.tools.r8.kotlin.lambda.KStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KStyleKotlinLambdaMergingWithEnumUnboxingTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public KStyleKotlinLambdaMergingWithEnumUnboxingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options ->
+ options.testing.kotlinLambdaMergerFactoryForClass =
+ this::getKotlinLambdaMergerFactoryForClass)
+ .addHorizontallyMergedLambdaClassesInspector(
+ inspector -> inspector.assertMerged(Lambda1.class, Lambda2.class))
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(EnumUnboxingCandidate.class))
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Lambda1.method()", "Lambda2.method()");
+ }
+
+ private KotlinLambdaGroupIdFactory getKotlinLambdaMergerFactoryForClass(DexProgramClass clazz) {
+ String typeName = clazz.getType().toSourceString();
+ if (typeName.equals(Lambda1.class.getTypeName())
+ || typeName.equals(Lambda2.class.getTypeName())) {
+ return KStyleLambdaGroupIdFactory.getInstance();
+ }
+ return null;
+ }
+
+ static class Main {
+
+ @NeverClassInline
+ public enum EnumUnboxingCandidate {
+ LAMBDA1,
+ LAMBDA2
+ }
+
+ public static void main(String[] args) {
+ accept(createLambda(EnumUnboxingCandidate.LAMBDA1));
+ accept(createLambda(EnumUnboxingCandidate.LAMBDA2));
+ }
+
+ @NeverInline
+ static kotlin.jvm.functions.Function0<kotlin.Unit> createLambda(EnumUnboxingCandidate value) {
+ switch (value) {
+ case LAMBDA1:
+ return new Lambda1();
+ case LAMBDA2:
+ return new Lambda2();
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ @NeverInline
+ static void accept(kotlin.jvm.functions.Function0<kotlin.Unit> instance) {
+ instance.invoke();
+ }
+ }
+
+ @NeverClassInline
+ public static final class Lambda1 extends kotlin.jvm.internal.Lambda<kotlin.Unit>
+ implements kotlin.jvm.functions.Function0<kotlin.Unit> {
+
+ public Lambda1() {
+ super(0);
+ }
+
+ @NeverInline
+ @Override
+ public final kotlin.Unit invoke() {
+ System.out.println("Lambda1.method()");
+ return null;
+ }
+ }
+
+ @NeverClassInline
+ public static final class Lambda2 extends kotlin.jvm.internal.Lambda<kotlin.Unit>
+ implements kotlin.jvm.functions.Function0<kotlin.Unit> {
+
+ public Lambda2() {
+ super(0);
+ }
+
+ @NeverInline
+ @Override
+ public final kotlin.Unit invoke() {
+ System.out.println("Lambda2.method()");
+ return null;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
new file mode 100644
index 0000000..2ca4579
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, 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.utils.codeinspector;
+
+import static com.android.tools.r8.TestBase.toDexType;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.EnumValueInfoMapCollection;
+
+public class EnumUnboxingInspector {
+
+ private final DexItemFactory dexItemFactory;
+ private final EnumValueInfoMapCollection unboxedEnums;
+
+ public EnumUnboxingInspector(
+ DexItemFactory dexItemFactory, EnumValueInfoMapCollection unboxedEnums) {
+ this.dexItemFactory = dexItemFactory;
+ this.unboxedEnums = unboxedEnums;
+ }
+
+ public EnumUnboxingInspector assertUnboxed(Class<? extends Enum<?>> clazz) {
+ assertTrue(unboxedEnums.containsEnum(toDexType(clazz, dexItemFactory)));
+ return this;
+ }
+
+ public EnumUnboxingInspector assertUnboxed(Class<? extends Enum<?>>... classes) {
+ for (Class<? extends Enum<?>> clazz : classes) {
+ assertUnboxed(clazz);
+ }
+ return this;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java
new file mode 100644
index 0000000..4b3579f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, 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.utils.codeinspector;
+
+import static com.android.tools.r8.TestBase.toDexType;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
+
+public class HorizontallyMergedLambdaClassesInspector {
+
+ private final DexItemFactory dexItemFactory;
+ private final HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses;
+
+ public HorizontallyMergedLambdaClassesInspector(
+ DexItemFactory dexItemFactory,
+ HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses) {
+ this.dexItemFactory = dexItemFactory;
+ this.horizontallyMergedLambdaClasses = horizontallyMergedLambdaClasses;
+ }
+
+ public HorizontallyMergedLambdaClassesInspector assertMerged(Class<?> clazz) {
+ assertTrue(horizontallyMergedLambdaClasses.hasBeenMerged(toDexType(clazz, dexItemFactory)));
+ return this;
+ }
+
+ public HorizontallyMergedLambdaClassesInspector assertMerged(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ assertMerged(clazz);
+ }
+ return this;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java
new file mode 100644
index 0000000..bd64711
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/VerticallyMergedClassesInspector.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, 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.utils.codeinspector;
+
+import static com.android.tools.r8.TestBase.toDexType;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
+
+public class VerticallyMergedClassesInspector {
+
+ private final DexItemFactory dexItemFactory;
+ private final VerticallyMergedClasses verticallyMergedClasses;
+
+ public VerticallyMergedClassesInspector(
+ DexItemFactory dexItemFactory, VerticallyMergedClasses verticallyMergedClasses) {
+ this.dexItemFactory = dexItemFactory;
+ this.verticallyMergedClasses = verticallyMergedClasses;
+ }
+
+ public VerticallyMergedClassesInspector assertMergedIntoSubtype(Class<?> clazz) {
+ assertTrue(verticallyMergedClasses.hasBeenMergedIntoSubtype(toDexType(clazz, dexItemFactory)));
+ return this;
+ }
+
+ public VerticallyMergedClassesInspector assertMergedIntoSubtype(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ assertMergedIntoSubtype(clazz);
+ }
+ return this;
+ }
+}