Fix performance of unneeded catch handler removal.
Reduces the compilation time for the reproduction
case from 12 minutes to 6 seconds on my machine. :-\
R=mikaelpeltier@google.com, sgjesse@google.com
Bug: 77182828
Change-Id: Ia84724f6c4cd2ab1ec13bc848996862c212d2f76
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 ee2c6ab..163c20b 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
@@ -569,13 +569,15 @@
}
/**
- * Unlinks this block from a single predecessor and successor.
+ * Unlinks the current block based on the assumption that it is a catch handler.
*
- * @return Returns the unlinked successor
+ * Catch handlers always have only one predecessor and at most one successor.
+ * That is because we have edge-split form for all exceptional flow.
*/
- public BasicBlock unlinkSingle() {
- unlinkSinglePredecessor();
- return unlinkSingleSuccessor();
+ public void unlinkCatchHandler() {
+ assert predecessors.size() == 1;
+ predecessors.get(0).removeSuccessor(this);
+ predecessors.clear();
}
public void detachAllSuccessors() {
@@ -590,34 +592,41 @@
assert successor.predecessors.contains(this);
List<BasicBlock> removedBlocks = new ArrayList<>();
for (BasicBlock dominated : dominator.dominatedBlocks(successor)) {
+ dominated.cleanForRemoval();
removedBlocks.add(dominated);
- for (BasicBlock block : dominated.successors) {
- block.removePredecessor(dominated);
- }
- dominated.successors.clear();
- for (BasicBlock block : dominated.predecessors) {
- block.removeSuccessor(dominated);
- }
- dominated.predecessors.clear();
- for (Phi phi : dominated.getPhis()) {
- for (Value operand : phi.getOperands()) {
- operand.removePhiUser(phi);
- }
- }
- dominated.getPhis().clear();
- for (Instruction instruction : dominated.getInstructions()) {
- for (Value value : instruction.inValues) {
- value.removeUser(instruction);
- }
- for (Value value : instruction.getDebugValues()) {
- value.removeDebugUser(instruction);
- }
- }
}
assert blocksClean(removedBlocks);
return removedBlocks;
}
+ public void cleanForRemoval() {
+ for (BasicBlock block : successors) {
+ block.removePredecessor(this);
+ }
+ successors.clear();
+ for (BasicBlock block : predecessors) {
+ block.removeSuccessor(this);
+ }
+ predecessors.clear();
+ for (Phi phi : getPhis()) {
+ for (Value operand : phi.getOperands()) {
+ operand.removePhiUser(phi);
+ }
+ }
+ getPhis().clear();
+ for (Instruction instruction : getInstructions()) {
+ if (instruction.outValue != null) {
+ instruction.outValue.clearUsers();
+ }
+ for (Value value : instruction.inValues) {
+ value.removeUser(instruction);
+ }
+ for (Value value : instruction.getDebugValues()) {
+ value.removeDebugUser(instruction);
+ }
+ }
+ }
+
public void linkCatchSuccessors(List<DexType> guards, List<BasicBlock> targets) {
List<Integer> successorIndexes = new ArrayList<>(targets.size());
for (BasicBlock target : targets) {