Merge "Fix local variable table in CF backend when inserting CfFrames."
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index f5b0a31..35ce779 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -76,6 +76,7 @@
private final Int2ReferenceMap<DebugLocalInfo> emittedLocals = new Int2ReferenceOpenHashMap<>();
private Int2ReferenceMap<DebugLocalInfo> pendingLocals = null;
private boolean pendingLocalChanges = false;
+ private BasicBlock pendingFrame = null;
private final List<LocalVariableInfo> localVariablesTable = new ArrayList<>();
private final Int2ReferenceMap<LocalVariableInfo> openLocalVariables =
@@ -259,7 +260,6 @@
BasicBlock block = blockIterator.next();
CfLabel tryCatchStart = null;
CatchHandlers<BasicBlock> tryCatchHandlers = CatchHandlers.EMPTY_BASIC_BLOCK;
- BasicBlock pendingFrame = null;
boolean previousFallthrough = false;
do {
assert stack.isEmpty();
@@ -286,17 +286,6 @@
pendingFrame = block;
emitLabel(getLabel(block));
}
- if (pendingFrame != null) {
- boolean advancesPC = hasMaterializingInstructions(block, nextBlock);
- // If block has no materializing instructions, then we postpone emitting the frame
- // until the next block. In this case, nextBlock must be non-null
- // (or we would fall off the edge of the method).
- assert advancesPC || nextBlock != null;
- if (advancesPC) {
- addFrame(pendingFrame, Collections.emptyList());
- pendingFrame = null;
- }
- }
JumpInstruction exit = block.exit();
boolean fallthrough =
(exit.isGoto() && exit.asGoto().getTarget() == nextBlock)
@@ -308,7 +297,7 @@
pendingLocals = new Int2ReferenceOpenHashMap<>(locals);
pendingLocalChanges = true;
}
- buildCfInstructions(block, fallthrough, stack);
+ buildCfInstructions(block, nextBlock, fallthrough, stack);
block = nextBlock;
previousFallthrough = fallthrough;
} while (block != null);
@@ -346,7 +335,19 @@
return false;
}
- private void buildCfInstructions(BasicBlock block, boolean fallthrough, Stack stack) {
+ private void buildCfInstructions(
+ BasicBlock block, BasicBlock nextBlock, boolean fallthrough, Stack stack) {
+ if (pendingFrame != null) {
+ boolean advancesPC = hasMaterializingInstructions(block, nextBlock);
+ // If block has no materializing instructions, then we postpone emitting the frame
+ // until the next block. In this case, nextBlock must be non-null
+ // (or we would fall off the edge of the method).
+ assert advancesPC || nextBlock != null;
+ if (advancesPC) {
+ addFrame(pendingFrame, Collections.emptyList());
+ pendingFrame = null;
+ }
+ }
InstructionIterator it = block.iterator();
while (it.hasNext()) {
Instruction instruction = it.next();
@@ -394,30 +395,7 @@
}
CfLabel label = ensureLabel();
if (didLocalsChange) {
- Int2ReferenceSortedMap<DebugLocalInfo> ending =
- DebugLocalInfo.endingLocals(emittedLocals, pendingLocals);
- Int2ReferenceSortedMap<DebugLocalInfo> starting =
- DebugLocalInfo.startingLocals(emittedLocals, pendingLocals);
- assert !ending.isEmpty() || !starting.isEmpty();
- for (Entry<DebugLocalInfo> entry : ending.int2ReferenceEntrySet()) {
- int localIndex = entry.getIntKey();
- LocalVariableInfo info = openLocalVariables.remove(localIndex);
- info.setEnd(label);
- localVariablesTable.add(info);
- DebugLocalInfo removed = emittedLocals.remove(localIndex);
- assert removed == entry.getValue();
- }
- if (!starting.isEmpty()) {
- for (Entry<DebugLocalInfo> entry : starting.int2ReferenceEntrySet()) {
- int localIndex = entry.getIntKey();
- assert !emittedLocals.containsKey(localIndex);
- assert !openLocalVariables.containsKey(localIndex);
- openLocalVariables.put(
- localIndex, new LocalVariableInfo(localIndex, entry.getValue(), label));
- emittedLocals.put(localIndex, entry.getValue());
- }
- }
- pendingLocalChanges = false;
+ updateLocals(label);
}
if (didPositionChange) {
add(new CfPosition(label, position));
@@ -425,6 +403,33 @@
}
}
+ private void updateLocals(CfLabel label) {
+ Int2ReferenceSortedMap<DebugLocalInfo> ending =
+ DebugLocalInfo.endingLocals(emittedLocals, pendingLocals);
+ Int2ReferenceSortedMap<DebugLocalInfo> starting =
+ DebugLocalInfo.startingLocals(emittedLocals, pendingLocals);
+ assert !ending.isEmpty() || !starting.isEmpty();
+ for (Entry<DebugLocalInfo> entry : ending.int2ReferenceEntrySet()) {
+ int localIndex = entry.getIntKey();
+ LocalVariableInfo info = openLocalVariables.remove(localIndex);
+ info.setEnd(label);
+ localVariablesTable.add(info);
+ DebugLocalInfo removed = emittedLocals.remove(localIndex);
+ assert removed == entry.getValue();
+ }
+ if (!starting.isEmpty()) {
+ for (Entry<DebugLocalInfo> entry : starting.int2ReferenceEntrySet()) {
+ int localIndex = entry.getIntKey();
+ assert !emittedLocals.containsKey(localIndex);
+ assert !openLocalVariables.containsKey(localIndex);
+ openLocalVariables.put(
+ localIndex, new LocalVariableInfo(localIndex, entry.getValue(), label));
+ emittedLocals.put(localIndex, entry.getValue());
+ }
+ }
+ pendingLocalChanges = false;
+ }
+
private boolean localsChanged() {
if (!pendingLocalChanges) {
return false;
@@ -461,11 +466,25 @@
Collection<Value> locals = registerAllocator.getLocalsAtBlockEntry(block);
Int2ReferenceSortedMap<FrameType> mapping = new Int2ReferenceAVLTreeMap<>();
-
for (Value local : locals) {
mapping.put(getLocalRegister(local), getFrameType(block, local));
}
- instructions.add(new CfFrame(mapping, stackTypes));
+ CfFrame frame = new CfFrame(mapping, stackTypes);
+
+ // Make sure to end locals on this transition before the synthetic CfFrame instruction.
+ // Otherwise we might extend the live range of a local across a CfFrame instruction that
+ // the local is not live across. For example if we have a return followed by a move exception
+ // where the locals end. Inserting a CfFrame instruction between the return and the move
+ // exception without ending the locals will lead to having the local alive on the CfFrame
+ // instruction which is not correct and will cause us to not be able to build IR from the
+ // CfCode.
+ boolean didLocalsChange = localsChanged();
+ if (didLocalsChange) {
+ CfLabel label = ensureLabel();
+ updateLocals(label);
+ }
+
+ instructions.add(frame);
}
private FrameType getFrameType(BasicBlock liveBlock, Value local) {