Refactor throw block outliner to use shared state per outline candidate

Change-Id: I1cf5d84cf943f5bfc2c0467364e94e1640409942
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerScanner.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerScanner.java
index 42f3a4f..bfa9c4b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerScanner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/exceptions/ThrowBlockOutlinerScanner.java
@@ -73,7 +73,16 @@
   }
 
   public void run(IRCode code) {
-    new ThrowBlockOutlinerScannerForCode(code).run();
+    assert !code.metadata().mayHaveThrowBlockOutlineMarker();
+    for (BasicBlock block : getThrowBlocks(code)) {
+      new ThrowBlockOutlinerScannerForBlock(code, block).processThrowBlock();
+    }
+    if (code.metadata().mayHaveThrowBlockOutlineMarker()) {
+      assert code.getConversionOptions().isGeneratingDex();
+      code.mutateConversionOptions(MutableMethodConversionOptions::setIsGeneratingLir);
+    } else {
+      assert code.streamInstructions().noneMatch(Instruction::isThrowBlockOutlineMarker);
+    }
   }
 
   public AbstractValueFactory getAbstractValueFactory() {
@@ -86,47 +95,38 @@
     return outlines.values();
   }
 
-  private class ThrowBlockOutlinerScannerForCode {
+  private List<BasicBlock> getThrowBlocks(IRCode code) {
+    boolean seenReturn = false;
+    List<BasicBlock> throwBlocks = new ArrayList<>();
+    for (BasicBlock block : code.getBlocks()) {
+      if (block.exit().isReturn()) {
+        seenReturn = true;
+      } else if (block.exit().isThrow()) {
+        throwBlocks.add(block);
+      }
+    }
+    // Never outline from methods that always throw.
+    return seenReturn ? throwBlocks : emptyList();
+  }
+
+  private class ThrowBlockOutlinerScannerForBlock {
 
     private final IRCode code;
+    private final Value exceptionValue;
+    private final BasicBlock throwBlock;
+    private final Throw throwInstruction;
 
-    ThrowBlockOutlinerScannerForCode(IRCode code) {
+    ThrowBlockOutlinerScannerForBlock(IRCode code, BasicBlock throwBlock) {
       this.code = code;
+      this.throwBlock = throwBlock;
+      this.throwInstruction = throwBlock.exit().asThrow();
+      this.exceptionValue = throwInstruction.exception();
     }
 
-    private void run() {
-      assert !code.metadata().mayHaveThrowBlockOutlineMarker();
-      for (BasicBlock block : getThrowBlocks()) {
-        processThrowBlock(block);
-      }
-      if (code.metadata().mayHaveThrowBlockOutlineMarker()) {
-        assert code.getConversionOptions().isGeneratingDex();
-        code.mutateConversionOptions(MutableMethodConversionOptions::setIsGeneratingLir);
-      } else {
-        assert code.streamInstructions().noneMatch(Instruction::isThrowBlockOutlineMarker);
-      }
-    }
-
-    private List<BasicBlock> getThrowBlocks() {
-      boolean seenReturn = false;
-      List<BasicBlock> throwBlocks = new ArrayList<>();
-      for (BasicBlock block : code.getBlocks()) {
-        if (block.exit().isReturn()) {
-          seenReturn = true;
-        } else if (block.exit().isThrow()) {
-          throwBlocks.add(block);
-        }
-      }
-      // Never outline from methods that always throw.
-      return seenReturn ? throwBlocks : emptyList();
-    }
-
-    private void processThrowBlock(BasicBlock block) {
+    private void processThrowBlock() {
       // Recursively build up the outline method. On successful outline creation, the resulting
       // LirCode is passed to the continuation function.
       processThrowInstruction(
-          block,
-          block.exit().asThrow(),
           outlineBuilder -> {
             // On successful outline creation, store the outline for later processing.
             LirCode<?> lirCode = outlineBuilder.buildLirCode(appView, code.context());
@@ -143,20 +143,18 @@
             // Insert a synthetic marker instruction that references the outline so that we know
             // where to materialize the outline call.
             Instruction insertionPoint = outlineBuilder.getFirstOutlinedInstruction();
-            assert insertionPoint.getBlock() == block;
+            assert insertionPoint.getBlock() == throwBlock;
             ThrowBlockOutlineMarker marker =
                 ThrowBlockOutlineMarker.builder()
                     .setArguments(arguments)
                     .setOutline(outline)
                     .setPosition(Position.none())
                     .build();
-            block.listIterator(insertionPoint).add(marker);
+            throwBlock.listIterator(insertionPoint).add(marker);
           });
     }
 
-    private void processThrowInstruction(
-        BasicBlock throwBlock, Throw throwInstruction, Consumer<OutlineBuilder> continuation) {
-      Value exceptionValue = throwInstruction.exception();
+    private void processThrowInstruction(Consumer<OutlineBuilder> continuation) {
       if (!exceptionValue.isDefinedByInstructionSatisfying(
           i -> i.isNewInstance() && i.getBlock() == throwBlock)) {
         // Exception is not created in the throw block.
@@ -165,7 +163,6 @@
       assert throwInstruction.hasPrev();
       // We always expect the constructor call corresponding to the thrown exception to be last.
       processExceptionConstructorCall(
-          throwBlock,
           throwInstruction.getPrev(),
           outlineBuilder -> {
             Value outlinedExceptionValue = outlineBuilder.getOutlinedValue(exceptionValue);
@@ -183,28 +180,26 @@
     }
 
     private void processInstruction(
-        BasicBlock throwBlock, Instruction instruction, Consumer<OutlineBuilder> continuation) {
+        Instruction instruction, Consumer<OutlineBuilder> continuation) {
       switch (instruction.opcode()) {
         case CONST_NUMBER:
         case CONST_STRING:
-          processConstInstruction(throwBlock, instruction.asConstInstruction(), continuation);
+          processConstInstruction(instruction.asConstInstruction(), continuation);
           return;
         case INVOKE_DIRECT:
           if (instruction.isInvokeConstructor(factory)) {
-            processStringBuilderConstructorCall(
-                throwBlock, instruction.asInvokeDirect(), continuation);
+            processStringBuilderConstructorCall(instruction.asInvokeDirect(), continuation);
             return;
           }
           break;
         case INVOKE_STATIC:
-          processStringFormatOrValueOf(throwBlock, instruction.asInvokeStatic(), continuation);
+          processStringFormatOrValueOf(instruction.asInvokeStatic(), continuation);
           return;
         case INVOKE_VIRTUAL:
-          processStringBuilderAppendOrToString(
-              throwBlock, instruction.asInvokeVirtual(), continuation);
+          processStringBuilderAppendOrToString(instruction.asInvokeVirtual(), continuation);
           return;
         case NEW_INSTANCE:
-          processNewInstanceInstruction(throwBlock, instruction.asNewInstance(), continuation);
+          processNewInstanceInstruction(instruction.asNewInstance(), continuation);
           return;
         default:
           break;
@@ -214,40 +209,38 @@
     }
 
     private void processConstInstruction(
-        BasicBlock throwBlock,
         ConstInstruction instruction,
         Consumer<OutlineBuilder> continuation) {
-      processPredecessorInstructionOrStartOutline(throwBlock, instruction, continuation);
+      processPredecessorInstructionOrStartOutline(instruction, continuation);
     }
 
     private void processPredecessorInstructionOrFail(
-        BasicBlock throwBlock, Instruction instruction, Consumer<OutlineBuilder> continuation) {
+        Instruction instruction, Consumer<OutlineBuilder> continuation) {
       if (instruction.hasPrev()) {
-        processInstruction(throwBlock, instruction.getPrev(), continuation);
+        processInstruction(instruction.getPrev(), continuation);
       } else {
         // Intentionally empty. Not calling the continuation corresponds to dropping the outline.
       }
     }
 
     private void processPredecessorInstructionOrStartOutline(
-        BasicBlock throwBlock, Instruction instruction, Consumer<OutlineBuilder> continuation) {
+        Instruction instruction, Consumer<OutlineBuilder> continuation) {
       if (instruction.hasPrev()) {
-        processInstruction(throwBlock, instruction.getPrev(), continuation);
+        processInstruction(instruction.getPrev(), continuation);
       } else {
         startOutline(instruction, continuation);
       }
     }
 
     private void processNewInstanceInstruction(
-        BasicBlock throwBlock, NewInstance newInstance, Consumer<OutlineBuilder> continuation) {
-      if (newInstance.outValue() != throwBlock.exit().asThrow().exception()
+        NewInstance newInstance, Consumer<OutlineBuilder> continuation) {
+      if (newInstance.outValue() != exceptionValue
           && newInstance.getType().isNotIdenticalTo(appView.dexItemFactory().stringBuilderType)) {
         // Unhandled instruction.
         startOutline(newInstance.getNext(), continuation);
         return;
       }
       processPredecessorInstructionOrStartOutline(
-          throwBlock,
           newInstance,
           outlineBuilder -> {
             outlineNewInstanceInstruction(newInstance, outlineBuilder);
@@ -270,14 +263,12 @@
     }
 
     private void processExceptionConstructorCall(
-        BasicBlock throwBlock, Instruction instruction, Consumer<OutlineBuilder> continuation) {
+        Instruction instruction, Consumer<OutlineBuilder> continuation) {
       InvokeDirect invoke = instruction.asInvokeConstructor(factory);
       if (invoke == null) {
         // Not a constructor call.
         return;
       }
-      Throw throwInstruction = throwBlock.exit().asThrow();
-      Value exceptionValue = throwInstruction.exception();
       assert !exceptionValue.hasDebugUsers();
       assert !exceptionValue.hasPhiUsers();
       if (invoke.getReceiver() != exceptionValue) {
@@ -288,7 +279,6 @@
       // instruction checks if the new-instance instruction is in the throw block.
       assert instruction.hasPrev();
       processPredecessorInstructionOrFail(
-          throwBlock,
           invoke,
           outlineBuilder -> {
             if (outlineBuilder.getOutlinedValue(exceptionValue) == null) {
@@ -318,14 +308,13 @@
     }
 
     private void processStringBuilderConstructorCall(
-        BasicBlock throwBlock, InvokeDirect invoke, Consumer<OutlineBuilder> continuation) {
+        InvokeDirect invoke, Consumer<OutlineBuilder> continuation) {
       if (!factory.stringBuilderMethods.isConstructorMethod(invoke.getInvokedMethod())) {
         // Unhandled instruction.
         startOutline(invoke.getNext(), continuation);
         return;
       }
       processPredecessorInstructionOrFail(
-          throwBlock,
           invoke,
           outlineBuilder -> {
             if (outlineBuilder.getOutlinedValue(invoke.getReceiver()) == null) {
@@ -345,7 +334,7 @@
     }
 
     private void processStringFormatOrValueOf(
-        BasicBlock throwBlock, InvokeStatic invoke, Consumer<OutlineBuilder> continuation) {
+        InvokeStatic invoke, Consumer<OutlineBuilder> continuation) {
       DexMethod invokedMethod = invoke.getInvokedMethod();
       if (!invokedMethod.isIdenticalTo(factory.stringMembers.format)
           && !invokedMethod.isIdenticalTo(factory.stringMembers.valueOf)) {
@@ -354,7 +343,6 @@
         return;
       }
       processPredecessorInstructionOrStartOutline(
-          throwBlock,
           invoke,
           outlineBuilder -> {
             InvokeStatic.Builder outlinedInvokeBuilder =
@@ -378,7 +366,7 @@
     }
 
     private void processStringBuilderAppendOrToString(
-        BasicBlock throwBlock, InvokeVirtual invoke, Consumer<OutlineBuilder> continuation) {
+        InvokeVirtual invoke, Consumer<OutlineBuilder> continuation) {
       DexMethod invokedMethod = invoke.getInvokedMethod();
       if (!factory.stringBuilderMethods.isAppendMethod(invokedMethod)
           && !invokedMethod.match(factory.stringBuilderMethods.toString)) {
@@ -387,7 +375,6 @@
         return;
       }
       processPredecessorInstructionOrStartOutline(
-          throwBlock,
           invoke,
           outlineBuilder -> {
             InvokeVirtual.Builder outlinedInvokeBuilder =