Version: 2.1.60
Cherry-pick: Handle no-exceptions case when inlining synchronized methods.
CL: https://r8-review.googlesource.com/c/r8/+/52747
Bug: 161154276
Change-Id: I13e5d0b7566f2fa514be6a78056f849126b459d6
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index ea76867..1f7c9d4 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.1.59";
+ public static final String LABEL = "2.1.60";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 17cea8b..8f07681 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -652,29 +652,32 @@
moveExceptionBlocks.add(moveExceptionBlock);
}
- // Create a phi for the exception values such that we can rethrow the exception if needed.
- Value exceptionValue;
- if (moveExceptionBlocks.size() == 1) {
- exceptionValue =
- ListUtils.first(moveExceptionBlocks).getInstructions().getFirst().outValue();
- } else {
- Phi phi = code.createPhi(monitorExitBlock, throwableType);
- List<Value> operands =
- ListUtils.map(
- moveExceptionBlocks, block -> block.getInstructions().getFirst().outValue());
- phi.addOperands(operands);
- exceptionValue = phi;
+ InstructionListIterator monitorExitBlockIterator = null;
+ if (!moveExceptionBlocks.isEmpty()) {
+ // Create a phi for the exception values such that we can rethrow the exception if needed.
+ Value exceptionValue;
+ if (moveExceptionBlocks.size() == 1) {
+ exceptionValue =
+ ListUtils.first(moveExceptionBlocks).getInstructions().getFirst().outValue();
+ } else {
+ Phi phi = code.createPhi(monitorExitBlock, throwableType);
+ List<Value> operands =
+ ListUtils.map(
+ moveExceptionBlocks, block -> block.getInstructions().getFirst().outValue());
+ phi.addOperands(operands);
+ exceptionValue = phi;
+ }
+
+ monitorExitBlockIterator = monitorExitBlock.listIterator(code);
+ monitorExitBlockIterator.setInsertionPosition(Position.syntheticNone());
+ monitorExitBlockIterator.add(new Throw(exceptionValue));
+ monitorExitBlock.getMutablePredecessors().addAll(moveExceptionBlocks);
+
+ // Insert the newly created blocks.
+ code.blocks.addAll(moveExceptionBlocks);
+ code.blocks.add(monitorExitBlock);
}
- InstructionListIterator monitorExitBlockIterator = monitorExitBlock.listIterator(code);
- monitorExitBlockIterator.setInsertionPosition(Position.syntheticNone());
- monitorExitBlockIterator.add(new Throw(exceptionValue));
- monitorExitBlock.getMutablePredecessors().addAll(moveExceptionBlocks);
-
- // Insert the newly created blocks.
- code.blocks.addAll(moveExceptionBlocks);
- code.blocks.add(monitorExitBlock);
-
// Create a block for holding the monitor-enter instruction. Note that, since this block
// is created after we attach catch-all handlers to the code, this block will not have any
// catch handlers.
@@ -702,9 +705,11 @@
// Insert the monitor-enter and monitor-exit instructions.
monitorEnterBlockIterator.add(new Monitor(Monitor.Type.ENTER, lockValue));
- monitorExitBlockIterator.previous();
- monitorExitBlockIterator.add(new Monitor(Monitor.Type.EXIT, lockValue));
- monitorExitBlock.close(null);
+ if (monitorExitBlockIterator != null) {
+ monitorExitBlockIterator.previous();
+ monitorExitBlockIterator.add(new Monitor(Monitor.Type.EXIT, lockValue));
+ monitorExitBlock.close(null);
+ }
for (BasicBlock block : code.blocks) {
if (block.exit().isReturn()) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedMethodTest.java
new file mode 100644
index 0000000..45997a8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynchronizedMethodTest.java
@@ -0,0 +1,67 @@
+// 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.ir.optimize.inliner;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InlineSynchronizedMethodTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ }
+
+ public InlineSynchronizedMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(InlineSynchronizedMethodTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(
+ inspector -> {
+ // TODO(b/163007704): Identify and remove trivial/unobservable monitor enter/exit
+ // pairs.
+ assertEquals(
+ 2,
+ inspector
+ .clazz(TestClass.class)
+ .uniqueMethodWithName("main")
+ .streamInstructions()
+ .filter(i -> i.isMonitorEnter() || i.isMonitorExit())
+ .count());
+ });
+ }
+
+ static class TestClass {
+
+ public static synchronized String foo(String msg) {
+ // No throwing instructions, so no need to join exceptions on exit.
+ return msg;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(foo(args.length == 1 ? args[0] : "Hello, world"));
+ }
+ }
+}