Fix enum unboxing with large arity method
Change-Id: I5b9a19f6eecd3bba7bf48ed903ca1bb7337e1683
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index abff1ff..da1d23f 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -144,12 +144,20 @@
List<CfInstruction> instructions = new ArrayList<>();
DexMethod representative = methodMap.values().iterator().next();
CfFrame.Builder frameBuilder = CfFrame.builder();
+ int paramRegisterSize = 0;
for (DexType parameter : representative.getParameters()) {
frameBuilder.appendLocal(FrameType.initialized(parameter));
+ paramRegisterSize += parameter.getRequiredRegisters();
}
addCfSwitch(
instructions, this::addReturnInvoke, methodMap, superEnumMethod, frameBuilder, false);
- return new CfCodeWithLens(getHolder(), defaultMaxStack(), defaultMaxLocals(), instructions);
+ // We need to get an estimate of the stack and local with is greater than the actual number,
+ // IR processing will compute the exact number. There are at most 255 parameters, so this is
+ // always within unsigned 16 bits bounds.
+ assert paramRegisterSize < 256;
+ int maxStack = 2 * paramRegisterSize + 16;
+ int maxLocals = paramRegisterSize + 16;
+ return new CfCodeWithLens(getHolder(), maxStack, maxLocals, instructions);
}
private void addReturnInvoke(List<CfInstruction> instructions, DexMethod method) {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/LargeArityEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/LargeArityEnumUnboxingTest.java
new file mode 100644
index 0000000..0e9a7c1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/LargeArityEnumUnboxingTest.java
@@ -0,0 +1,162 @@
+// Copyright (c) 2023, 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.enummerging;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
+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 LargeArityEnumUnboxingTest 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();
+ }
+
+ public LargeArityEnumUnboxingTest(
+ 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(LargeArityEnumUnboxingTest.class)
+ .addKeepMainRule(LargeArityEnum.class)
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(LargeArityEnum.MyEnum.class))
+ .enableNeverClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), LargeArityEnum.class)
+ .assertSuccessWithOutputLines("171.0", "189.0", "271.0", "299.0");
+ }
+
+ static class LargeArityEnum {
+
+ @NeverClassInline
+ enum MyEnum {
+ A(1) {
+ @NeverInline
+ public double foo(
+ long op1,
+ long op2,
+ double op3,
+ double op4,
+ int op5,
+ int op6,
+ long op7,
+ long op8,
+ double op9,
+ double op10,
+ int op11,
+ int op12,
+ long op13,
+ long op14,
+ double op15,
+ double op16,
+ int op17,
+ int op18) {
+ return mul * op1 + op2 + op3 + op4 + op5 + op6 + op7 + op8 + op9 + op10 + op11 + op12
+ + op13 + op14 + op15 + op16 + op17 + op18;
+ }
+ },
+ B(3) {
+ @NeverInline
+ public double foo(
+ long op1,
+ long op2,
+ double op3,
+ double op4,
+ int op5,
+ int op6,
+ long op7,
+ long op8,
+ double op9,
+ double op10,
+ int op11,
+ int op12,
+ long op13,
+ long op14,
+ double op15,
+ double op16,
+ int op17,
+ int op18) {
+ return mul * mul * op1
+ + op2
+ + op3
+ + op4
+ + op5
+ + op6
+ + op7
+ + op8
+ + op9
+ + op10
+ + op11
+ + op12
+ + op13
+ + op14
+ + op15
+ + op16
+ + op17
+ + op18 * mul;
+ }
+ };
+
+ final int mul;
+
+ MyEnum(int mul) {
+ this.mul = mul;
+ }
+
+ // Method with large arity.
+ public abstract double foo(
+ long op1,
+ long op2,
+ double op3,
+ double op4,
+ int op5,
+ int op6,
+ long op7,
+ long op8,
+ double op9,
+ double op10,
+ int op11,
+ int op12,
+ long op13,
+ long op14,
+ double op15,
+ double op16,
+ int op17,
+ int op18);
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ public static void main(String[] args) {
+ System.out.println(
+ MyEnum.A.foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18));
+ System.out.println(
+ MyEnum.A.foo(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19));
+ System.out.println(
+ MyEnum.B.foo(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20));
+ System.out.println(
+ MyEnum.B.foo(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21));
+ }
+ }
+}