Version 2.0.42
Cherry pick: Allow unreachable ret instructioins in the input.
CL: https://r8-review.googlesource.com/c/r8/+/49261
Bug: 150274427
Change-Id: Ia2b3624dd35e11146836ac25dd91deb59f67dfd6
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 8faf42c..3a0340e 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "2.0.41";
+ public static final String LABEL = "2.0.42";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index e30a78d..9eedd04 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfJsrRet;
import com.android.tools.r8.cf.code.CfLabel;
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfLogicalBinop;
@@ -654,6 +655,11 @@
builder.append(type.getType().toString());
}
+ public void print(CfJsrRet ret) {
+ indent();
+ builder.append("ret ").append(ret.getLocal());
+ }
+
private String getLabel(CfLabel label) {
return labelToIndex != null ? ("L" + labelToIndex.getInt(label)) : "L?";
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
new file mode 100644
index 0000000..32c3040
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -0,0 +1,56 @@
+// 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.cf.code;
+
+import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.ir.conversion.CfSourceCode;
+import com.android.tools.r8.ir.conversion.CfState;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
+import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.MethodVisitor;
+
+public class CfJsrRet extends CfInstruction {
+
+ private static CompilationError error() {
+ throw new CompilationError(
+ "Invalid compilation of code with reachable jump subroutine RET instruction");
+ }
+
+ private final int local;
+
+ public CfJsrRet(int local) {
+ this.local = local;
+ }
+
+ @Override
+ public void write(MethodVisitor visitor, NamingLens lens) {
+ throw error();
+ }
+
+ @Override
+ public void print(CfPrinter printer) {
+ printer.print(this);
+ }
+
+ @Override
+ public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
+ throw error();
+ }
+
+ @Override
+ public ConstraintWithTarget inliningConstraint(InliningConstraints inliningConstraints,
+ DexType invocationContext, GraphLense graphLense, AppView<?> appView) {
+ throw error();
+ }
+
+ public int getLocal() {
+ return local;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index edec3a9..d012556 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfJsrRet;
import com.android.tools.r8.cf.code.CfLabel;
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfLogicalBinop;
@@ -654,7 +655,10 @@
type = ValueType.OBJECT;
break;
case Opcodes.RET:
- throw new JsrEncountered("RET should be handled by the ASM jsr inliner");
+ {
+ instructions.add(new CfJsrRet(var));
+ return;
+ }
default:
throw new Unreachable("Unexpected VarInsn opcode: " + opcode);
}
diff --git a/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java b/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java
new file mode 100644
index 0000000..3c41a63
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b150274427/JsrRetRegressionTest.java
@@ -0,0 +1,92 @@
+// 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.regress.b150274427;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.transformers.MethodTransformer;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class JsrRetRegressionTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ public JsrRetRegressionTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testUnreachableJsrRet() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(getTransformClass(false))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(RuntimeException.class);
+ }
+
+ @Test
+ public void testReachableJsrRet() throws Exception {
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addProgramClassFileData(getTransformClass(true))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(VerifyError.class);
+ return;
+ }
+ try {
+ testForD8()
+ .addProgramClassFileData(getTransformClass(true))
+ .setMinApi(parameters.getApiLevel())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorMessageThatMatches(containsString("RET"));
+ });
+ fail();
+ } catch (CompilationFailedException e) {
+ // Expected error.
+ }
+ }
+
+ private byte[] getTransformClass(boolean replaceThrow) throws IOException {
+ return transformer(TestClass.class)
+ .setVersion(50)
+ .addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitInsn(int opcode) {
+ if (opcode == Opcodes.ATHROW) {
+ if (!replaceThrow) {
+ super.visitInsn(opcode);
+ }
+ super.visitVarInsn(Opcodes.RET, 0);
+ } else {
+ super.visitInsn(opcode);
+ }
+ }
+ })
+ .transform();
+ }
+
+ private static class TestClass {
+
+ public static void main(String[] args) {
+ throw new RuntimeException();
+ // Reachable or unreachable JSR inserted here.
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 52777d9..22a91f8 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -190,6 +190,21 @@
});
}
+ public ClassFileTransformer setVersion(int newVersion) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ super.visit(newVersion, access, name, signature, superName, interfaces);
+ }
+ });
+ }
public ClassFileTransformer setMinVersion(CfVm jdk) {
return setMinVersion(jdk.getClassfileVersion());