Version 1.3.48.
Merge: Workaround another mediatek Lollipop VM bug.
CL: https://r8-review.googlesource.com/c/r8/+/32261
R=christofferqa@google.com, zerny@google.com
Bug: 117907456, 119895393
Change-Id: I6f4e55204eb74ada52eeac27367a061fa80e6ac4
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 62b346a..8fb488f 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 = "1.3.47";
+ public static final String LABEL = "1.3.48";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index fe63f46..5251aa2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -363,6 +363,14 @@
return descriptor.content[0] == 'Z';
}
+ public boolean isLongType() {
+ return descriptor.content[0] == 'J';
+ }
+
+ public boolean isDoubleType() {
+ return descriptor.content[0] == 'D';
+ }
+
public boolean isIntType() {
return descriptor.content[0] == 'I';
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
index 8927476..e1bfb24 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexBuilder.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
+import com.android.tools.r8.code.Const4;
+import com.android.tools.r8.code.ConstWide16;
import com.android.tools.r8.code.FillArrayData;
import com.android.tools.r8.code.FillArrayDataPayload;
import com.android.tools.r8.code.Format31t;
@@ -33,6 +35,8 @@
import com.android.tools.r8.code.MoveWide16;
import com.android.tools.r8.code.MoveWideFrom16;
import com.android.tools.r8.code.Nop;
+import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.code.ReturnWide;
import com.android.tools.r8.code.Throw;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
@@ -212,14 +216,22 @@
if (options.canHaveTracingPastInstructionsStreamBug()
&& dexInstructions.get(dexInstructions.size() - 1) instanceof Throw
&& hasBackwardsBranch) {
- Nop nop = new Nop();
- dexInstructions.add(nop);
- nop.setOffset(offset);
- offset += nop.getSize();
- Goto go = new Goto(-nop.getSize());
- dexInstructions.add(go);
- go.setOffset(offset);
- offset += go.getSize();
+ List<Instruction> instructions = new ArrayList<>();
+ DexType returnType = ir.method.method.proto.returnType;
+ if (returnType.isVoidType()) {
+ instructions.add(new ReturnVoid());
+ } else if (returnType.isDoubleType() || returnType.isLongType()) {
+ instructions.add(new ConstWide16(0, 0));
+ instructions.add(new ReturnWide(0));
+ } else {
+ instructions.add(new Const4(0, 0));
+ instructions.add(new com.android.tools.r8.code.Return(0));
+ }
+ for (Instruction instruction : instructions) {
+ instruction.setOffset(offset);
+ offset += instruction.getSize();
+ dexInstructions.add(instruction);
+ }
}
// Compute switch payloads.
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 1299091..5e23686 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -743,12 +743,15 @@
}
// The Dalvik tracing JIT can trace past the end of the instruction stream and end up
- // parsing non-code bytes as code (typically leading to a crash).
+ // parsing non-code bytes as code (typically leading to a crash). See b/117907456.
//
- // In order to workaround this we insert "nop; goto -1;" after the throw when the instruction
- // stream ends with a throw and there are backwards branches in the code.
+ // In order to workaround this we insert a return of the right type after the throw
+ // when the instruction stream ends with a throw and there are backwards branches
+ // in the code.
//
- // See b/117907456.
+ // We used to insert a empty loop at the end, however, mediatek has an optimizer
+ // on lollipop devices that cannot deal with an unreachable infinite loop, so we
+ // couldn't do that. See b/119895393.
public boolean canHaveTracingPastInstructionsStreamBug() {
return minApiLevel < AndroidApiLevel.L.getLevel();
}
diff --git a/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java b/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
index 0d83011..98ac685 100644
--- a/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
+++ b/src/test/java/com/android/tools/r8/regress/b117907456/B117907456.java
@@ -6,14 +6,17 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Goto;
import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Nop;
+import com.android.tools.r8.code.Return;
+import com.android.tools.r8.code.ReturnVoid;
+import com.android.tools.r8.code.ReturnWide;
import com.android.tools.r8.code.Throw;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -36,16 +39,21 @@
}
public class B117907456 extends TestBase {
+
+ private boolean isReturn(Instruction lastInstruction) {
+ return lastInstruction instanceof ReturnVoid
+ || lastInstruction instanceof Return
+ || lastInstruction instanceof ReturnWide;
+ }
+
@Test
public void testNopDupInsertionForDalvikTracingBug()
throws IOException, CompilationFailedException, ExecutionException {
MethodSubject method = getMethodSubject(AndroidApiLevel.K);
Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
Instruction lastInstruction = instructions[instructions.length - 1];
- assert !(lastInstruction instanceof Throw);
- assert lastInstruction instanceof Goto;
- Instruction previous = instructions[instructions.length - 2];
- assert previous instanceof Nop;
+ assertFalse(lastInstruction instanceof Throw);
+ assertTrue(isReturn(lastInstruction));
}
@Test
@@ -54,7 +62,7 @@
MethodSubject method = getMethodSubject(AndroidApiLevel.L);
Instruction[] instructions = method.getMethod().getCode().asDexCode().instructions;
Instruction lastInstruction = instructions[instructions.length - 1];
- assert lastInstruction instanceof Throw;
+ assertTrue(lastInstruction instanceof Throw);
}
private MethodSubject getMethodSubject(AndroidApiLevel level)