Enum unboxing and lambda cf to cf
Bug: 204174455
Change-Id: I5e65ba322ebcc5179c5bb5992946f1b81369247b
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 0353705..dd5b328 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
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
@@ -26,6 +27,8 @@
import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -78,15 +81,34 @@
isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
List<DexValue> newArgs =
rewriteBootstrapArguments(callSite.bootstrapArgs, methodHandleUse, context);
+ DexString newMethodName = computeNewMethodName(callSite, context, isLambdaMetaFactory);
if (!newMethodProto.equals(callSite.methodProto)
+ || newMethodName != callSite.methodName
|| newBootstrapMethod != callSite.bootstrapMethod
|| !newArgs.equals(callSite.bootstrapArgs)) {
return dexItemFactory.createCallSite(
- callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
+ newMethodName, newMethodProto, newBootstrapMethod, newArgs);
}
return callSite;
}
+ private DexString computeNewMethodName(
+ DexCallSite callSite, ProgramMethod context, boolean isLambdaMetaFactory) {
+ if (!isLambdaMetaFactory) {
+ return callSite.methodName;
+ }
+ assert callSite.getBootstrapArgs().size() > 0;
+ assert callSite.getBootstrapArgs().get(0).isDexValueMethodType();
+ // The targeted method may have been renamed, we need to update the name if that is the case.
+ DexMethod method =
+ LambdaDescriptor.getMainFunctionalInterfaceMethodReference(
+ callSite, definitions.dexItemFactory());
+ return graphLens
+ .lookupMethod(method, context.getReference(), Invoke.Type.INTERFACE)
+ .getReference()
+ .getName();
+ }
+
public DexMethodHandle rewriteDexMethodHandle(
DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) {
if (methodHandle.isMethodHandle()) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index edfa934..887f18e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -255,6 +255,15 @@
return descriptor == MATCH_FAILED ? null : descriptor;
}
+ public static DexMethod getMainFunctionalInterfaceMethodReference(
+ DexCallSite callSite, DexItemFactory factory) {
+ DexProto proto = callSite.getBootstrapArgs().get(0).asDexValueMethodType().value;
+ DexProto lambdaFactoryProto = callSite.methodProto;
+ DexType mainInterface = lambdaFactoryProto.returnType;
+ DexString funcMethodName = callSite.methodName;
+ return factory.createMethod(mainInterface, proto, funcMethodName);
+ }
+
public static boolean isLambdaMetafactoryMethod(
DexCallSite callSite, DexDefinitionSupplier definitions) {
return callSite.bootstrapMethod.type.isInvokeStatic()
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
new file mode 100644
index 0000000..288ace4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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 com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+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 LambdaEnumUnboxingEmptyEnumTest 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 LambdaEnumUnboxingEmptyEnumTest(
+ 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())
+ .enableNeverClassInliningAnnotations()
+ .noMinification()
+ .enableNoVerticalClassMergingAnnotations()
+ .enableInliningAnnotations()
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .addEnumUnboxingInspector(
+ inspector -> inspector.assertUnboxedIf(enumKeepRules.isNone(), MyEnum.class))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("null");
+ }
+
+ @NeverClassInline
+ enum MyEnum {}
+
+ @NoVerticalClassMerging
+ interface MyEnumConsumer {
+
+ void accept(MyEnum e);
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ execute(e -> System.out.println(String.valueOf(e)));
+ }
+
+ @NeverInline
+ static void execute(MyEnumConsumer consumer) {
+ consumer.accept(null);
+ }
+ }
+}