Fix various places that do not compute max stack
Bug: 181185068
Change-Id: Ic8697018f87f24ec97b7d082e006428399e2b7c7
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java
index c919e63..d78d74d 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java
@@ -59,11 +59,14 @@
}
public CfCode synthesizeCode(DexType originalHolder) {
+ // Building the instructions will adjust maxStack and maxLocals. Build it here before invoking
+ // the CfCode constructor to ensure that the value passed in is the updated values.
+ List<CfInstruction> instructions = buildInstructions();
return new CfCode(
originalHolder,
maxStack,
maxLocals,
- buildInstructions(),
+ instructions,
Collections.emptyList(),
Collections.emptyList());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 7d07a7d..5cd32f2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -78,7 +78,8 @@
CfInvoke invoke = instruction.asInvoke();
MethodProvider methodProvider = getMethodProviderOrNull(invoke.getMethod());
return methodProvider != null
- ? methodProvider.rewriteInvoke(invoke, appView, eventConsumer, methodProcessingContext)
+ ? methodProvider.rewriteInvoke(
+ invoke, appView, eventConsumer, methodProcessingContext, localStackAllocator)
: null;
}
@@ -1364,7 +1365,8 @@
CfInvoke invoke,
AppView<?> appView,
BackportedMethodDesugaringEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext);
+ MethodProcessingContext methodProcessingContext,
+ LocalStackAllocator localStackAllocator);
}
private static final class InvokeRewriter extends MethodProvider {
@@ -1381,8 +1383,9 @@
CfInvoke invoke,
AppView<?> appView,
BackportedMethodDesugaringEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
- return rewriter.rewrite(invoke, appView.dexItemFactory());
+ MethodProcessingContext methodProcessingContext,
+ LocalStackAllocator localStackAllocator) {
+ return rewriter.rewrite(invoke, appView.dexItemFactory(), localStackAllocator);
}
}
@@ -1406,7 +1409,8 @@
CfInvoke invoke,
AppView<?> appView,
BackportedMethodDesugaringEventConsumer eventConsumer,
- MethodProcessingContext methodProcessingContext) {
+ MethodProcessingContext methodProcessingContext,
+ LocalStackAllocator localStackAllocator) {
ProgramMethod method = getSyntheticMethod(appView, methodProcessingContext);
eventConsumer.acceptBackportedMethod(method, methodProcessingContext.getMethodContext());
return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, method.getReference(), false));
@@ -1465,7 +1469,8 @@
CfInstruction rewriteSingle(CfInvoke invoke, DexItemFactory factory);
// Convenience wrapper since most rewrites are to a single instruction.
- default Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
+ default Collection<CfInstruction> rewrite(
+ CfInvoke invoke, DexItemFactory factory, LocalStackAllocator localStackAllocator) {
return ImmutableList.of(rewriteSingle(invoke, factory));
}
}
@@ -1478,6 +1483,7 @@
}
@Override
- public abstract Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory);
+ public abstract Collection<CfInstruction> rewrite(
+ CfInvoke invoke, DexItemFactory factory, LocalStackAllocator localStackAllocator);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index cbab081..6975252 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -361,9 +361,18 @@
Builder<CfInstruction> instructions,
DexItemFactory factory) {
internalAdjustType(fromType, toType, returnType, instructions, factory);
+ if (fromType == toType) {
+ return ValueType.fromDexType(fromType).requiredRegisters();
+ }
+ // Account for the potential unboxing of a wide type.
+ DexType fromTypeAsPrimitive = factory.getPrimitiveFromBoxed(fromType);
return Math.max(
ValueType.fromDexType(fromType).requiredRegisters(),
- ValueType.fromDexType(toType).requiredRegisters());
+ Math.max(
+ fromTypeAsPrimitive == null
+ ? 0
+ : ValueType.fromDexType(fromTypeAsPrimitive).requiredRegisters(),
+ ValueType.fromDexType(toType).requiredRegisters()));
}
private static void internalAdjustType(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 1865244..3a7a195 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -133,12 +133,14 @@
method,
methodProcessingContext);
if (replacement != null) {
- // Record if we increased the max number of locals for the method, and reset the
- // next temporary locals register.
+ // Record if we increased the max number of locals and stack height for the method,
+ // and reset the next temporary locals register.
maxLocalsForCode.setMax(maxLocalsForInstruction.getAndSet(cfCode.getMaxLocals()));
+ maxStackForCode.setMax(maxStackForInstruction.getAndSet(cfCode.getMaxStack()));
} else {
// The next temporary locals register should be unchanged.
assert maxLocalsForInstruction.get() == cfCode.getMaxLocals();
+ assert maxStackForInstruction.get() == cfCode.getMaxStack();
}
return replacement;
},
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
index 51949c9..8b928aa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.FullMethodInvokeRewriter;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import java.util.Collection;
import java.util.Collections;
import org.objectweb.asm.Opcodes;
@@ -34,7 +35,8 @@
public static MethodInvokeRewriter rewriteAsIdentity() {
return new FullMethodInvokeRewriter() {
@Override
- public Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
+ public Collection<CfInstruction> rewrite(
+ CfInvoke invoke, DexItemFactory factory, LocalStackAllocator localStackAllocator) {
// The invoke consumes the stack value and pushes another assumed to be the same.
return Collections.emptyList();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
index f8ab4a7..20998db 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.FullMethodInvokeRewriter;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import org.objectweb.asm.Opcodes;
@@ -32,8 +33,10 @@
return new FullMethodInvokeRewriter() {
@Override
- public Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
+ public Collection<CfInstruction> rewrite(
+ CfInvoke invoke, DexItemFactory factory, LocalStackAllocator localStackAllocator) {
// requireNonNull returns the operand, so dup top-of-stack, do getClass and pop the class.
+ localStackAllocator.allocateLocalStack(1);
return ImmutableList.of(
new CfStackInstruction(Opcode.Dup),
new CfInvoke(Opcodes.INVOKEVIRTUAL, factory.objectMembers.getClass, false),
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
index b02544d..1f3c6d0 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/FieldAccessorBuilder.java
@@ -89,6 +89,7 @@
// Load the argument.
ValueType fieldType = ValueType.fromDexType(field.getType());
instructions.add(new CfLoad(fieldType, maxLocals));
+ maxStack += fieldType.requiredRegisters();
maxLocals += fieldType.requiredRegisters();
}
@@ -102,6 +103,7 @@
instructions.add(new CfReturnVoid());
} else {
ValueType fieldType = ValueType.fromDexType(field.getType());
+ maxStack = Math.max(fieldType.requiredRegisters(), maxStack);
instructions.add(new CfReturn(fieldType));
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
index 84acf70..0c6b359 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodBuilder.java
@@ -182,6 +182,13 @@
maybeInsertArgumentCast(i, parameter, instructions);
}
instructions.add(new CfInvoke(getInvokeOpcode(), targetMethod, isInterface));
+ if (!targetMethod.getReturnType().isVoidType()) {
+ // If the return type is not void, it will push a value on the stack. We subtract the
+ // arguments pushed by the invoke to see if bumping the stack height is necessary.
+ maxStack =
+ Math.max(
+ maxStack, ValueType.fromDexType(targetMethod.getReturnType()).requiredRegisters());
+ }
if (isSourceReturnVoid()) {
assert !isConstructorDelegate;
instructions.add(new CfReturnVoid());
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 f2587df..c9ee155 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1039,7 +1039,7 @@
}
// Currently the filter is simple string equality on the qualified name.
String qualifiedName = method.qualifiedName();
- return methodsFilter.indexOf(qualifiedName) >= 0;
+ return methodsFilter.contains(qualifiedName);
}
public boolean methodMatchesLogArgumentsFilter(DexEncodedMethod method) {
@@ -1049,7 +1049,7 @@
}
// Currently the filter is simple string equality on the qualified name.
String qualifiedName = method.qualifiedName();
- return logArgumentsFilter.indexOf(qualifiedName) >= 0;
+ return logArgumentsFilter.contains(qualifiedName);
}
public enum PackageObfuscationMode {
diff --git a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
index 16d9503..0a1f760 100644
--- a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdaReceiverTest.java
@@ -7,7 +7,8 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -16,33 +17,34 @@
@RunWith(Parameterized.class)
public class InstantiatedLambdaReceiverTest extends TestBase {
- private Backend backend;
-
private static final String expectedOutput = "In C.m()";
+ private final TestParameters parameters;
- @Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return ToolHelper.getBackends();
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
- public InstantiatedLambdaReceiverTest(Backend backend) {
- this.backend = backend;
+ public InstantiatedLambdaReceiverTest(TestParameters parameters) {
+ this.parameters = parameters;
}
@Test
public void jvmTest() throws Exception {
- assumeTrue(
- "JVM test independent of Art version - only run when testing on latest",
- ToolHelper.getDexVm().getVersion().isLatest());
- testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expectedOutput);
}
@Test
- public void dexTest() throws Exception {
- testForR8(backend)
+ public void r8Test() throws Exception {
+ testForR8(parameters.getBackend())
.addInnerClasses(InstantiatedLambdaReceiverTest.class)
.addKeepMainRule(TestClass.class)
- .run(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput);
}