Use an intrusive linked list for BasicBlock instructions
* Encapsulates all Instruction.setBlock() and IRMetadata.record()
calls within InstructionList so they cannot be missed.
* Updates passes that added the same instruction (temporarily) to two
different blocks (or to the same block twice).
* Instructions can now belong to only one list, so must be removed
before added again.
* Switches a handful of iterator uses to for loops (get a feel for
the style)
* I think many spots would benefit from using this style over
iterators, as it means you do not need worry about invalidating
iterators, or rewinding them.
* Changes semantics of Block.listIterator(Instruction) to match
Block.listIterator(index)
* E.g. The given instruction will be the first to be returned by
a call to next().
* Moves some instruction mutating helper logic from
BasicBlockInstructionListIterator to InstructionList & Instruction,
so that they can be used without an iterator.
* Likely makes sense to do more of this going forward, or to capture
these helpers in an InstructionUtil class.
* Leaves in some TODOs for trivial follow-up refactors in order to
not make this even larger of a change than it is.
Bug: b/376663044
Change-Id: I11005b74efbbda9fe2b463a5f848c0f486868d59
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 59fde05..5e5c563 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -47,7 +47,6 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
@@ -173,9 +172,8 @@
// Catch handler information about which successors are catch handlers and what their guards are.
private CatchHandlers<Integer> catchHandlers = CatchHandlers.EMPTY_INDICES;
- // TODO(b/270398965): Replace LinkedList.
- @SuppressWarnings("JdkObsolete")
- private LinkedList<Instruction> instructions = new LinkedList<>();
+ // Linked list of instructions belonging to this block.
+ private final InstructionList instructions = new InstructionList(this);
private int number = -1;
private List<Phi> phis = new ArrayList<>();
@@ -202,6 +200,23 @@
// Map of registers to current SSA value. Used during SSA numbering and cleared once filled.
private Map<Integer, Value> currentDefinitions = new HashMap<>();
+ // Metadata shared by all blocks of an IRCode.
+ // TODO(b/376663044): Remove |metadata| parameter from methods in this class.
+ private IRMetadata metadata;
+
+ public BasicBlock(IRMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ public IRMetadata getMetadata() {
+ return metadata;
+ }
+
+ // Required when moving a block between code objects (inlining).
+ void setMetadata(IRMetadata metadata) {
+ this.metadata = metadata;
+ }
+
public <BT, CT> TraversalContinuation<BT, CT> traverseNormalPredecessors(
BiFunction<? super BasicBlock, ? super CT, TraversalContinuation<BT, CT>> fn,
CT initialValue) {
@@ -524,7 +539,8 @@
} else if (exit().isIf()) {
if (indexOfNewBlock >= successors.size() - 2 && indexOfOldBlock >= successors.size() - 2) {
// New and old are true target and fallthrough, replace last instruction with a goto.
- Instruction instruction = getInstructions().removeLast();
+ Instruction instruction = instructions.getLast();
+ instructions.removeIgnoreValues(instruction);
// Iterate in reverse order to ensure that POP instructions are inserted in correct order.
for (int i = instruction.inValues().size() - 1; i >= 0; i--) {
Value value = instruction.inValues().get(i);
@@ -536,7 +552,6 @@
} else {
assert !(value instanceof StackValues);
Pop pop = new Pop(value);
- pop.setBlock(this);
pop.setPosition(instruction.getPosition());
getInstructions().addLast(pop);
}
@@ -546,7 +561,6 @@
}
}
Instruction exit = new Goto();
- exit.setBlock(this);
exit.setPosition(instruction.getPosition());
getInstructions().addLast(exit);
} else if (indexOfOldBlock >= successors.size() - 2) {
@@ -738,7 +752,7 @@
return nextInstructionNumber;
}
- public LinkedList<Instruction> getInstructions() {
+ public InstructionList getInstructions() {
return instructions;
}
@@ -797,22 +811,24 @@
}
public Instruction entry() {
- return instructions.get(0);
+ return instructions.getFirst();
}
public JumpInstruction exit() {
assert filled;
- assert instructions.get(instructions.size() - 1).isJumpInstruction();
- return instructions.get(instructions.size() - 1).asJumpInstruction();
+ assert instructions.getLast().isJumpInstruction();
+ return instructions.getLast().asJumpInstruction();
+ }
+
+ public Instruction getLastInstruction() {
+ return instructions.getLast();
}
public Instruction exceptionalExit() {
assert hasCatchHandlers();
- InstructionIterator it = iterator(instructions.size());
- while (it.hasPrevious()) {
- Instruction instruction = it.previous();
- if (instruction.instructionTypeCanThrow()) {
- return instruction;
+ for (Instruction ins = getLastInstruction(); ins != null; ins = ins.getPrev()) {
+ if (ins.instructionTypeCanThrow()) {
+ return ins;
}
}
return null;
@@ -892,15 +908,9 @@
phis.removeAll(phisToRemove);
}
- public void add(Instruction next, IRCode code) {
- add(next, code.metadata());
- }
-
- public void add(Instruction next, IRMetadata metadata) {
+ public void add(Instruction next, IRMetadata unused_metadata) {
assert !isFilled();
- instructions.add(next);
- metadata.record(next);
- next.setBlock(this);
+ instructions.addLast(next);
}
public void close(IRBuilder builder) {
@@ -1493,49 +1503,11 @@
return builder.toString();
}
- public void addPhiMove(Move move) {
- // TODO(ager): Consider this more, is it always the case that we should add it before the
- // exit instruction?
- Instruction branch = exit();
- instructions.set(instructions.size() - 1, move);
- instructions.add(branch);
- }
-
- public void setInstructions(LinkedList<Instruction> instructions) {
- this.instructions = instructions;
- }
-
- /**
- * Remove a number of instructions. The instructions to remove are given as indexes in the
- * instruction stream.
- */
- // TODO(b/270398965): Replace LinkedList.
- @SuppressWarnings("JdkObsolete")
- public void removeInstructions(List<Integer> toRemove) {
- if (!toRemove.isEmpty()) {
- LinkedList<Instruction> newInstructions = new LinkedList<>();
- int nextIndex = 0;
- for (Integer index : toRemove) {
- assert index >= nextIndex; // Indexes in toRemove must be sorted ascending.
- newInstructions.addAll(instructions.subList(nextIndex, index));
- instructions.get(index).clearBlock();
- nextIndex = index + 1;
- }
- if (nextIndex < instructions.size()) {
- newInstructions.addAll(instructions.subList(nextIndex, instructions.size()));
- }
- assert instructions.size() == newInstructions.size() + toRemove.size();
- setInstructions(newInstructions);
- }
- }
-
/**
* Remove an instruction.
*/
public void removeInstruction(Instruction toRemove) {
- int index = instructions.indexOf(toRemove);
- assert index >= 0;
- removeInstructions(Collections.singletonList(index));
+ instructions.removeIgnoreValues(toRemove);
}
/**
@@ -1563,7 +1535,7 @@
*/
public static BasicBlock createGotoBlock(
int blockNumber, Position position, IRMetadata metadata) {
- BasicBlock block = new BasicBlock();
+ BasicBlock block = new BasicBlock(metadata);
block.add(new Goto(), metadata);
block.close(null);
block.setNumber(blockNumber);
@@ -1580,7 +1552,7 @@
* @param theIf the if instruction
*/
public static BasicBlock createIfBlock(int blockNumber, If theIf, IRMetadata metadata) {
- BasicBlock block = new BasicBlock();
+ BasicBlock block = new BasicBlock(metadata);
block.add(theIf, metadata);
block.close(null);
block.setNumber(blockNumber);
@@ -1598,7 +1570,7 @@
*/
public static BasicBlock createIfBlock(
int blockNumber, If theIf, IRMetadata metadata, Instruction... instructions) {
- BasicBlock block = new BasicBlock();
+ BasicBlock block = new BasicBlock(metadata);
for (Instruction instruction : instructions) {
block.add(instruction, metadata);
}
@@ -1610,7 +1582,7 @@
public static BasicBlock createSwitchBlock(
int blockNumber, IntSwitch theSwitch, IRMetadata metadata) {
- BasicBlock block = new BasicBlock();
+ BasicBlock block = new BasicBlock(metadata);
block.add(theSwitch, metadata);
block.close(null);
block.setNumber(blockNumber);
@@ -1621,14 +1593,14 @@
IRCode code, Position position, DexType guard, AppView<?> appView) {
TypeElement guardTypeLattice =
TypeElement.fromDexType(guard, Nullability.definitelyNotNull(), appView);
- BasicBlock block = new BasicBlock();
+ BasicBlock block = new BasicBlock(code.metadata());
MoveException moveException =
new MoveException(code.createValue(guardTypeLattice), guard, appView.options());
moveException.setPosition(position);
Throw throwInstruction = new Throw(moveException.outValue);
throwInstruction.setPosition(position);
- block.add(moveException, code);
- block.add(throwInstruction, code);
+ block.instructions.addLast(moveException);
+ block.instructions.addLast(throwInstruction);
block.close(null);
block.setNumber(code.getNextBlockNumber());
return block;
@@ -1779,9 +1751,9 @@
// visible to exceptional successors.
private boolean verifyNoValuesAfterThrowingInstruction() {
if (hasCatchHandlers()) {
- InstructionIterator iterator = iterator(instructions.size());
- while (iterator.hasPrevious()) {
- Instruction instruction = iterator.previous();
+ for (Instruction instruction = getLastInstruction();
+ instruction != null;
+ instruction = instruction.getPrev()) {
if (instruction.instructionTypeCanThrow()) {
return true;
}
@@ -1791,58 +1763,53 @@
return true;
}
- public BasicBlockInstructionIterator iterator() {
- return new BasicBlockInstructionIterator(this);
+ public InstructionIterator iterator() {
+ return instructions.iterator();
}
- public BasicBlockInstructionIterator iterator(int index) {
- return new BasicBlockInstructionIterator(this, index);
+ public InstructionIterator iterator(Instruction instruction) {
+ return instructions.iterator(instruction);
}
- public BasicBlockInstructionIterator iterator(Instruction instruction) {
- return new BasicBlockInstructionIterator(this, instruction);
+ public BasicBlockInstructionListIterator listIterator(IRCode unused_code) {
+ return listIterator();
}
- public BasicBlockInstructionListIterator listIterator(IRCode code) {
- return listIterator(code.metadata());
+ public BasicBlockInstructionListIterator listIterator() {
+ return new BasicBlockInstructionListIterator(this);
}
- public BasicBlockInstructionListIterator listIterator(IRMetadata metadata) {
- return new BasicBlockInstructionListIterator(metadata, this);
+ public BasicBlockInstructionListIterator listIterator(IRCode unused_code, int index) {
+ // TODO(b/376663044): Convert uses of index to use Instruction instead.
+ return new BasicBlockInstructionListIterator(this, index);
}
- public BasicBlockInstructionListIterator listIterator(IRCode code, int index) {
- return new BasicBlockInstructionListIterator(code.metadata(), this, index);
- }
-
- /**
- * Creates an instruction list iterator starting at <code>instruction</code>.
- *
- * <p>The cursor will be positioned after <code>instruction</code>. Calling <code>next</code> on
- * the returned iterator will return the instruction after <code>instruction</code>. Calling
- * <code>previous</code> will return <code>instruction</code>.
- */
- public BasicBlockInstructionListIterator listIterator(IRCode code, Instruction instruction) {
- return new BasicBlockInstructionListIterator(code.metadata(), this, instruction);
+ /** Creates an instruction list iterator starting at <code>firstInstructionToReturn</code>. */
+ public BasicBlockInstructionListIterator listIterator(
+ IRCode unused_code, Instruction firstInstructionToReturn) {
+ return new BasicBlockInstructionListIterator(this, firstInstructionToReturn);
}
/**
* Creates a new empty block as a successor for this block.
*
- * The new block will have all the normal successors of the original block.
+ * <p>The new block will have all the normal successors of the original block.
*
- * The catch successors are either on the original block or the new block depending on the
+ * <p>The catch successors are either on the original block or the new block depending on the
* value of <code>keepCatchHandlers</code>.
*
- * The current block still has all the instructions, and the new block is empty instruction-wise.
+ * <p>The current block still has all the instructions, and the new block is empty
+ * instruction-wise.
*
* @param blockNumber block number for new block
* @param keepCatchHandlers keep catch successors on the original block
+ * @param firstInstructionOfNewBlock this and all following are moved to the new block
* @return the new block
*/
- BasicBlock createSplitBlock(int blockNumber, boolean keepCatchHandlers) {
+ BasicBlock createSplitBlock(
+ int blockNumber, boolean keepCatchHandlers, Instruction firstInstructionOfNewBlock) {
boolean hadCatchHandlers = hasCatchHandlers();
- BasicBlock newBlock = new BasicBlock();
+ BasicBlock newBlock = new BasicBlock(metadata);
newBlock.setNumber(blockNumber);
// Copy all successors including catch handlers to the new block, and update predecessors.
@@ -1862,6 +1829,10 @@
// Link the two blocks
link(newBlock);
+ if (firstInstructionOfNewBlock != null) {
+ newBlock.instructions.severFrom(firstInstructionOfNewBlock);
+ }
+
// Mark the new block filled and sealed.
newBlock.filled = true;
newBlock.sealed = true;
@@ -1936,7 +1907,7 @@
exceptionTypeLattice = move.getOutType();
exceptionType = move.getExceptionType();
assert move.getDebugValues().isEmpty();
- getInstructions().remove(0);
+ instructions.removeIgnoreValues(move);
}
// Create new predecessor blocks.
List<BasicBlock> newPredecessors = new ArrayList<>(predecessors.size());
@@ -1946,19 +1917,19 @@
throw new CompilationError(
"Invalid block structure: catch block reachable via non-exceptional flow.");
}
- BasicBlock newBlock = new BasicBlock();
+ BasicBlock newBlock = new BasicBlock(metadata);
newBlock.setNumber(code.getNextBlockNumber());
newPredecessors.add(newBlock);
if (hasMoveException) {
Value value = code.createValue(exceptionTypeLattice, move.getLocalInfo());
values.add(value);
MoveException newMove = new MoveException(value, exceptionType, options);
- newBlock.add(newMove, code);
+ newBlock.instructions.addLast(newMove);
newMove.setPosition(position);
}
Goto next = new Goto();
next.setPosition(position);
- newBlock.add(next, code);
+ newBlock.instructions.addLast(next);
newBlock.close(null);
newBlock.getMutableSuccessors().add(this);
newBlock.getMutablePredecessors().add(predecessor);