Rewrite invoke-custom instructions using enum unboxing lens
Bug: 172568606
Change-Id: Ia845ad4b78adbc70e4e1678880483292be7ba530
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 77a7d70..ad1663a 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -301,8 +301,7 @@
}
}
ObjectToOffsetMapping objectMapping =
- virtualFile.computeMapping(
- appView.appInfo(), graphLens, namingLens, initClassLens);
+ virtualFile.computeMapping(appView, graphLens, namingLens, initClassLens);
MethodToCodeObjectMapping codeMapping =
rewriteCodeWithJumboStrings(
objectMapping, virtualFile.classes(), appView.appInfo().app());
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index b808097..108df1d 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.features.ClassToFeatureSplitMap;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexField;
@@ -210,10 +209,10 @@
}
public ObjectToOffsetMapping computeMapping(
- AppInfo appInfo, GraphLens graphLens, NamingLens namingLens, InitClassLens initClassLens) {
+ AppView<?> appView, GraphLens graphLens, NamingLens namingLens, InitClassLens initClassLens) {
assert transaction.isEmpty();
return new ObjectToOffsetMapping(
- appInfo,
+ appView,
graphLens,
namingLens,
initClassLens,
@@ -742,7 +741,7 @@
this.graphLens = graphLens;
this.initClassLens = initClassLens;
this.namingLens = namingLens;
- this.rewriter = new LensCodeRewriterUtils(appView, graphLens);
+ this.rewriter = new LensCodeRewriterUtils(appView);
}
private <T extends DexItem> boolean maybeInsert(T item, Set<T> set, Set<T> baseSet) {
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index b4797a9..c78f5ba 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -42,7 +42,7 @@
private DexString firstJumboString;
public ObjectToOffsetMapping(
- AppInfo appInfo,
+ AppView<?> appView,
GraphLens graphLens,
NamingLens namingLens,
InitClassLens initClassLens,
@@ -54,7 +54,7 @@
Collection<DexString> strings,
Collection<DexCallSite> callSites,
Collection<DexMethodHandle> methodHandles) {
- assert appInfo != null;
+ assert appView != null;
assert graphLens != null;
assert classes != null;
assert protos != null;
@@ -68,8 +68,8 @@
this.graphLens = graphLens;
this.namingLens = namingLens;
this.initClassLens = initClassLens;
- this.lensCodeRewriter = new LensCodeRewriterUtils(appInfo, graphLens);
- this.classes = sortClasses(appInfo, classes, namingLens);
+ this.lensCodeRewriter = new LensCodeRewriterUtils(appView);
+ this.classes = sortClasses(appView.appInfo(), classes, namingLens);
this.protos = createSortedMap(protos, compare(namingLens), this::failOnOverflow);
this.types = createSortedMap(types, compare(namingLens), this::failOnOverflow);
this.methods = createSortedMap(methods, compare(namingLens), this::failOnOverflow);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index 4b44ada..ae5e3f9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -33,20 +33,28 @@
public class LensCodeRewriterUtils {
+ private final AppView<?> appView;
private final DexDefinitionSupplier definitions;
private final GraphLens graphLens;
private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>();
public LensCodeRewriterUtils(AppView<?> appView) {
- this(appView, appView.graphLens());
+ this.appView = appView;
+ this.definitions = appView;
+ this.graphLens = null;
}
public LensCodeRewriterUtils(DexDefinitionSupplier definitions, GraphLens graphLens) {
+ this.appView = null;
this.definitions = definitions;
this.graphLens = graphLens;
}
+ private GraphLens graphLens() {
+ return appView != null ? appView.graphLens() : graphLens;
+ }
+
public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) {
DexItemFactory dexItemFactory = definitions.dexItemFactory();
DexProto newMethodProto = rewriteProto(callSite.methodProto);
@@ -74,7 +82,7 @@
DexMethod invokedMethod = methodHandle.asMethod();
MethodHandleType oldType = methodHandle.type;
MethodLookupResult lensLookup =
- graphLens.lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
+ graphLens().lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
DexMethod rewrittenTarget = lensLookup.getReference();
DexMethod actualTarget;
MethodHandleType newType;
@@ -115,7 +123,7 @@
}
} else {
DexField field = methodHandle.asField();
- DexField actualField = graphLens.lookupField(field);
+ DexField actualField = graphLens().lookupField(field);
if (actualField != field) {
return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
}
@@ -158,7 +166,7 @@
return rewriteDexMethodType(value.asDexValueMethodType());
case TYPE:
DexType oldType = value.asDexValueType().value;
- DexType newType = graphLens.lookupType(oldType);
+ DexType newType = graphLens().lookupType(oldType);
return newType != oldType ? new DexValueType(newType) : value;
default:
return value;
@@ -168,7 +176,7 @@
public DexProto rewriteProto(DexProto proto) {
return definitions
.dexItemFactory()
- .applyClassMappingToProto(proto, graphLens::lookupType, protoFixupCache);
+ .applyClassMappingToProto(proto, graphLens()::lookupType, protoFixupCache);
}
private DexValueMethodHandle rewriteDexValueMethodHandle(
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index b48e0a93..0fe19bc 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
@@ -23,9 +24,11 @@
private ObjectToOffsetMapping emptyObjectTObjectMapping() {
return new ObjectToOffsetMapping(
- AppInfo.createInitialAppInfo(
- DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null)
- .build()),
+ AppView.createForD8(
+ AppInfo.createInitialAppInfo(
+ DexApplication.builder(
+ new InternalOptions(new DexItemFactory(), new Reporter()), null)
+ .build())),
GraphLens.getIdentityLens(),
NamingLens.getIdentityLens(),
InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
index ab837d3..c494152 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumUnboxingTestBase.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
@@ -86,10 +87,12 @@
}
static List<Object[]> enumUnboxingTestParameters() {
- return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- BooleanUtils.values(),
- getAllEnumKeepRules());
+ return enumUnboxingTestParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ static List<Object[]> enumUnboxingTestParameters(TestParametersCollection testParameters) {
+ return buildParameters(testParameters, BooleanUtils.values(), getAllEnumKeepRules());
}
protected static EnumKeepRules[] getAllEnumKeepRules() {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingTest.java
new file mode 100644
index 0000000..d6eb6d1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingTest.java
@@ -0,0 +1,97 @@
+// 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.enumunboxing;
+
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import java.util.List;
+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 LambdaEnumUnboxingTest extends EnumUnboxingTestBase {
+
+ private final TestParameters parameters;
+ private final boolean enumValueOptimization;
+ private final EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+ public static List<Object[]> data() {
+ return enumUnboxingTestParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public LambdaEnumUnboxingTest(
+ TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+ this.parameters = parameters;
+ this.enumValueOptimization = enumValueOptimization;
+ this.enumKeepRules = enumKeepRules;
+ }
+
+ @Test
+ public void testEnumUnboxing() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addOptionsModification(
+ options -> {
+ if (options.isGeneratingClassFiles()) {
+ // TODO(b/172568606): Remove this when enabled for CF by default.
+ assertFalse(options.enableEnumUnboxing);
+ options.enableEnumUnboxing = true;
+ }
+ })
+ .enableNeverClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .addOptionsModification(options -> options.testing.enableEnumUnboxingDebugLogs = false)
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("0", "0", "1", "0", "0");
+ }
+
+ @NeverClassInline
+ enum MyEnum {
+ A,
+ B,
+ C
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(MyEnum.A.ordinal());
+ boolean[] booleans = new boolean[] {true, false};
+ forEach(booleans, Main::printAndGetEnum);
+ System.out.println(printAndGetEnum(true).ordinal());
+ }
+
+ @NeverInline
+ private static MyEnum printAndGetEnum(boolean b) {
+ MyEnum myEnum = b ? MyEnum.A : MyEnum.B;
+ System.out.println(myEnum.ordinal());
+ return myEnum;
+ }
+
+ @NeverInline
+ static void forEach(boolean[] booleans, MyBooleanConsumer consumer) {
+ for (boolean b : booleans) {
+ consumer.accept(b);
+ }
+ }
+ }
+
+ interface MyBooleanConsumer {
+
+ void accept(Boolean b);
+ }
+}