Extend the liveness of the receiver to the entire method.
This is necessary to avoid Art crashes when there is a
debugger attached to break on exception in a release build.
Art will crash if asked for the |this| object in a JIT
compiled method where the receiver register has been
clobbered.
We were already doing this live range extension for anything
with min-sdk that includes Lollipop devices because the
verifier had a similar assumption about the receiver
register not being clobbered back then. Therefore,
this should not be visible to most users.
This loses 5kB on GMSCore when comparing R8 compilations
with and without the extension of the live range.
R=sgjesse@google.com, zerny@google.com
Bug: 116837585
Change-Id: Id06f745fd5a540d26b89e13f8d503dcb95a0a4a9
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 75bf9c0..b4995c9 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -2465,7 +2465,8 @@
// This assumption is used during verification. Allowing the receiver register to be
// overwritten can therefore lead to verification errors. If we could be targeting one of these
// VMs we block the receiver register throughout the method.
- if (options.canHaveThisTypeVerifierBug() && !code.method.accessFlags.isStatic()) {
+ if ((options.canHaveThisTypeVerifierBug() || options.canHaveThisJitCodeDebuggingBug())
+ && !code.method.accessFlags.isStatic()) {
for (Instruction instruction : code.blocks.get(0).getInstructions()) {
if (instruction.isArgument() && instruction.outValue().isThis()) {
Value thisValue = instruction.outValue();
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 c7d6561..e0e4227 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -577,6 +577,17 @@
return minApiLevel < AndroidApiLevel.M.getLevel();
}
+ // Art crashes if we do dead reference elimination of the receiver in release mode and Art
+ // is asked for the |this| object over a JDWP connection at a point where the receiver
+ // register has been clobbered.
+ //
+ // See b/116683601 and b/116837585.
+ public boolean canHaveThisJitCodeDebuggingBug() {
+ // TODO(b/116841249): Make this an actual min-sdk guard once we know that Art no longer crashes
+ // on these accesses.
+ return true;
+ }
+
// The dalvik jit had a bug where the long operations add, sub, or, xor and and would write
// the first part of the result long before reading the second part of the input longs.
public boolean canHaveOverlappingLongRegisterBug() {