Extend LIR phase past bridge hoisting

Bug: b/225838009
Change-Id: Ie41f1757fd388fc6b63ca6255c469e66054bb663
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 608e3cf..2ebb574 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -584,10 +584,7 @@
                   shrinker.rewriteDeadBuilderReferencesFromDynamicMethods(
                       conversionOptions, appViewWithLiveness, executorService, timing));
 
-          if (!options.isShrinking()) {
-            // TODO(b/225838009): Support tracing and building LIR in Enqueuer.
-            PrimaryR8IRConverter.finalizeLirToOutputFormat(appView, timing, executorService);
-          } else {
+          if (options.isShrinking()) {
             // Mark dead proto extensions fields as neither being read nor written. This step must
             // run prior to the tree pruner.
             TreePrunerConfiguration treePrunerConfiguration =
@@ -611,8 +608,6 @@
                   options.reporter, options.usageInformationConsumer);
             }
 
-            // TODO(b/225838009): Support bridge hoisting from LIR code.
-            PrimaryR8IRConverter.finalizeLirToOutputFormat(appView, timing, executorService);
             new BridgeHoisting(appViewWithLiveness).run(executorService, timing);
 
             assert Inliner.verifyAllSingleCallerMethodsHaveBeenPruned(appViewWithLiveness);
@@ -657,6 +652,9 @@
           timing.end();
         }
 
+        // TODO(b/225838009): Support LIR in proto shrinking.
+        PrimaryR8IRConverter.finalizeLirToOutputFormat(appView, timing, executorService);
+
         if (appView.options().protoShrinking().isProtoShrinkingEnabled()) {
           if (appView.options().protoShrinking().isEnumLiteProtoShrinkingEnabled()) {
             appView.protoShrinker().enumLiteProtoShrinker.verifyDeadEnumLiteMapsAreDead();
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index 0fccf4e..b14c481 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -31,6 +31,7 @@
 import com.android.tools.r8.ir.conversion.MethodConversionOptions;
 import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.RetracerForCodePrinting;
 import com.google.common.collect.ImmutableMap;
@@ -39,6 +40,7 @@
 import java.util.Map;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 public class LirCode<EV> extends Code implements Iterable<LirInstructionView> {
 
@@ -90,7 +92,7 @@
   }
 
   public static class TryCatchTable {
-    final Int2ReferenceMap<CatchHandlers<Integer>> tryCatchHandlers;
+    private final Int2ReferenceMap<CatchHandlers<Integer>> tryCatchHandlers;
 
     public TryCatchTable(Int2ReferenceMap<CatchHandlers<Integer>> tryCatchHandlers) {
       assert !tryCatchHandlers.isEmpty();
@@ -101,6 +103,10 @@
     public CatchHandlers<Integer> getHandlersForBlock(int blockIndex) {
       return tryCatchHandlers.get(blockIndex);
     }
+
+    public void forEachHandler(BiConsumer<Integer, CatchHandlers<Integer>> fn) {
+      tryCatchHandlers.forEach(fn);
+    }
   }
 
   public static class DebugLocalInfoTable<EV> {
@@ -451,4 +457,23 @@
       positionConsumer.accept(entry.getPosition(method));
     }
   }
+
+  public LirCode<EV> newCodeWithRewrittenConstantPool(Function<DexItem, DexItem> rewriter) {
+    DexItem[] rewrittenConstants = ArrayUtils.map(constants, rewriter, new DexItem[0]);
+    if (constants == rewrittenConstants) {
+      return this;
+    }
+    return new LirCode<>(
+        irMetadata,
+        rewrittenConstants,
+        positionTable,
+        argumentCount,
+        instructions,
+        instructionCount,
+        tryCatchTable,
+        debugLocalInfoTable,
+        strategyInfo,
+        useDexEstimationStrategy,
+        metadataMap);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index cfe1a08..dfbea22 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -90,8 +90,7 @@
     if (code.getTryCatchTable() != null) {
       builder.append("try-catch-handlers:\n");
       code.getTryCatchTable()
-          .tryCatchHandlers
-          .forEach(
+          .forEachHandler(
               (index, handlers) -> {
                 builder.append(index).append(":\n");
                 for (CatchHandler<Integer> handler : handlers) {
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index ae0133f..4a737f4 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -29,6 +29,7 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.bridge.VirtualBridgeInfo;
+import com.android.tools.r8.lightir.LirCode;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
@@ -326,6 +327,9 @@
 
   private Code createCodeForVirtualBridge(ProgramMethod representative, DexMethod methodToInvoke) {
     Code code = representative.getDefinition().getCode();
+    if (code.isLirCode()) {
+      return createLirCodeForVirtualBridge(code.asLirCode(), methodToInvoke);
+    }
     if (code.isCfCode()) {
       return createCfCodeForVirtualBridge(code.asCfCode(), methodToInvoke);
     }
@@ -335,6 +339,18 @@
     throw new Unreachable("Unexpected code object of type " + code.getClass().getTypeName());
   }
 
+  private LirCode<Integer> createLirCodeForVirtualBridge(
+      LirCode<Integer> code, DexMethod methodToInvoke) {
+    return code.newCodeWithRewrittenConstantPool(
+        item -> {
+          if (item instanceof DexMethod) {
+           assert methodToInvoke.match((DexMethod) item);
+           return methodToInvoke;
+          }
+          return item;
+        });
+  }
+
   private CfCode createCfCodeForVirtualBridge(CfCode code, DexMethod methodToInvoke) {
     List<CfInstruction> newInstructions = new ArrayList<>();
     boolean modified = false;