Convert into DexItemBasedConstString in CF->LIR conversion

Bug: b/344939647
Change-Id: Ia001bfcfa55d333392156f339566646d78fee216
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7cabfb6..851df61 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -465,7 +465,7 @@
       new CfOpenClosedInterfacesAnalysis(appViewWithLiveness).run(executorService);
 
       // TODO(b/225838009): Move higher up.
-      LirConverter.enterLirSupportedPhase(appView, executorService);
+      LirConverter.enterLirSupportedPhase(appViewWithLiveness, executorService);
 
       assert verifyNoJarApplicationReaders(appView.appInfo().classes());
       assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldPut.java b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
index 488e60a..91e6d2d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
@@ -12,6 +12,8 @@
 
 public interface FieldPut {
 
+  BasicBlock getBlock();
+
   DexField getField();
 
   Position getPosition();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index ad479bd..96bfdc4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -589,13 +589,6 @@
     CheckNotNullConverter.runIfNecessary(appView, code);
     previous = printMethod(code, "IR after disable assertions (SSA)", previous);
 
-    if (identifierNameStringMarker != null) {
-      timing.begin("Decouple identifier-name strings");
-      identifierNameStringMarker.decoupleIdentifierNameStringsInMethod(code);
-      timing.end();
-      previous = printMethod(code, "IR after identifier-name strings (SSA)", previous);
-    }
-
     if (memberValuePropagation != null) {
       timing.begin("Propagate member values");
       memberValuePropagation.run(code);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index dacdd2f..c067459 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -27,8 +27,10 @@
 import com.android.tools.r8.lightir.IR2LirConverter;
 import com.android.tools.r8.lightir.LirCode;
 import com.android.tools.r8.lightir.LirStrategy;
+import com.android.tools.r8.naming.IdentifierNameStringMarker;
 import com.android.tools.r8.naming.RecordInvokeDynamicInvokeCustomRewriter;
 import com.android.tools.r8.optimize.MemberRebindingIdentityLens;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ObjectUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
@@ -39,14 +41,16 @@
 public class LirConverter {
 
   public static void enterLirSupportedPhase(
-      AppView<? extends AppInfoWithClassHierarchy> appView, ExecutorService executorService)
+      AppView<AppInfoWithLiveness> appView, ExecutorService executorService)
       throws ExecutionException {
     assert appView.testing().canUseLir(appView);
     assert appView.testing().isPreLirPhase();
     appView.testing().enterLirSupportedPhase();
     CodeRewriterPassCollection codeRewriterPassCollection =
         new CodeRewriterPassCollection(
-            new ConstResourceNumberRewriter(appView), new StringSwitchConverter(appView));
+            new ConstResourceNumberRewriter(appView),
+            new IdentifierNameStringMarker(appView),
+            new StringSwitchConverter(appView));
     // Convert code objects to LIR.
     ThreadUtils.processItems(
         appView.appInfo().classes(),
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPass.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPass.java
index 87fc847..c56ddbf 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPass.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/CodeRewriterPass.java
@@ -29,8 +29,8 @@
   }
 
   @SuppressWarnings("unchecked")
-  protected AppView<? extends T> appView() {
-    return (AppView<? extends T>) appView;
+  protected AppView<T> appView() {
+    return (AppView<T>) appView;
   }
 
   public final CodeRewriterResult run(
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 14a837a..cdec5d9 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -9,6 +9,7 @@
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.isClassNameComparison;
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
 
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
@@ -23,7 +24,7 @@
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.ConstString;
 import com.android.tools.r8.ir.code.DexItemBasedConstString;
-import com.android.tools.r8.ir.code.FieldInstruction;
+import com.android.tools.r8.ir.code.FieldPut;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
@@ -32,16 +33,19 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.passes.CodeRewriterPass;
+import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
 import com.android.tools.r8.naming.dexitembasedstring.ClassNameComputationInfo;
 import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.TextPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Streams;
 import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
-import java.util.Arrays;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Objects;
@@ -50,16 +54,33 @@
 import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
-public class IdentifierNameStringMarker {
+public class IdentifierNameStringMarker extends CodeRewriterPass<AppInfoWithLiveness> {
 
-  private final AppView<AppInfoWithLiveness> appView;
   private final Object2BooleanMap<DexMember<?, ?>> identifierNameStrings;
 
   public IdentifierNameStringMarker(AppView<AppInfoWithLiveness> appView) {
-    this.appView = appView;
+    super(appView);
     this.identifierNameStrings = appView.appInfo().identifierNameStrings;
   }
 
+  @Override
+  protected CodeRewriterResult rewriteCode(
+      IRCode code,
+      MethodProcessor methodProcessor,
+      MethodProcessingContext methodProcessingContext) {
+    return decoupleIdentifierNameStringsInBlocks(code, null);
+  }
+
+  @Override
+  protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
+    return code.metadata().mayHaveConstString();
+  }
+
+  @Override
+  protected String getRewriterId() {
+    return "IdentifierNameStringMarker";
+  }
+
   public void decoupleIdentifierNameStringsInFields(
       ExecutorService executorService) throws ExecutionException {
     ThreadUtils.processItems(
@@ -83,21 +104,18 @@
       return;
     }
     DexString original = staticValue.getValue();
-    DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
+    DexReference itemBasedString = inferMemberOrTypeFromNameString(appView(), original);
     if (itemBasedString != null) {
       encodedField.setStaticValue(
           new DexItemBasedValueString(itemBasedString, ClassNameComputationInfo.none()));
     }
   }
 
-  public void decoupleIdentifierNameStringsInMethod(IRCode code) {
-    decoupleIdentifierNameStringsInBlocks(code, null);
-    assert code.isConsistentSSA(appView);
-  }
-
-  public void decoupleIdentifierNameStringsInBlocks(IRCode code, Set<BasicBlock> blocks) {
+  public CodeRewriterResult decoupleIdentifierNameStringsInBlocks(
+      IRCode code, Set<BasicBlock> blocks) {
+    CodeRewriterResult result = CodeRewriterResult.NO_CHANGE;
     if (!code.metadata().mayHaveConstString()) {
-      return;
+      return result;
     }
     ListIterator<BasicBlock> blockIterator = code.listIterator();
     while (blockIterator.hasNext()) {
@@ -119,56 +137,69 @@
         // ...
         // v_n' <- DexItemBasedString("Lx/y/z;") // decoupled
         // this.fld <- v_n' // fieldPut
-        if (instruction.isStaticPut() || instruction.isInstancePut()) {
-          iterator =
-              decoupleIdentifierNameStringForFieldPutInstruction(
-                  code, blockIterator, iterator, instruction.asFieldInstruction());
+        if (instruction.isFieldPut()) {
+          FieldPut fieldPut = instruction.asFieldPut();
+          DexReference itemBasedString = getItemBasedStringForFieldPut(code, fieldPut);
+          if (itemBasedString != null) {
+            iterator =
+                decoupleIdentifierNameStringForFieldPutInstruction(
+                    code, blockIterator, iterator, fieldPut, itemBasedString);
+            result = CodeRewriterResult.HAS_CHANGED;
+          }
         } else if (instruction.isInvokeMethod()) {
+          InvokeMethod invoke = instruction.asInvokeMethod();
           iterator =
               decoupleIdentifierNameStringForInvokeInstruction(
-                  code, blockIterator, iterator, instruction.asInvokeMethod());
+                  code, blockIterator, iterator, invoke);
+          result = CodeRewriterResult.HAS_CHANGED;
         }
       }
     }
+    return result;
+  }
+
+  private DexReference getItemBasedStringForFieldPut(IRCode code, FieldPut fieldPut) {
+    DexField field = fieldPut.getField();
+    if (!identifierNameStrings.containsKey(field)) {
+      return null;
+    }
+    Value in = fieldPut.value();
+    if (in.isDexItemBasedConstString()) {
+      return null;
+    }
+    if (!in.isConstString()) {
+      warnUndeterminedIdentifierIfNecessary(
+          field, code.context(), fieldPut.asFieldInstruction(), null);
+      return null;
+    }
+    DexString original = in.getConstInstruction().asConstString().getValue();
+    DexReference itemBasedString = inferMemberOrTypeFromNameString(appView(), original);
+    if (itemBasedString == null) {
+      warnUndeterminedIdentifierIfNecessary(
+          field, code.context(), fieldPut.asFieldInstruction(), original);
+      return null;
+    }
+    return itemBasedString;
   }
 
   private InstructionListIterator decoupleIdentifierNameStringForFieldPutInstruction(
       IRCode code,
       ListIterator<BasicBlock> blocks,
       InstructionListIterator iterator,
-      FieldInstruction instruction) {
-    assert instruction.isInstancePut() || instruction.isStaticPut();
-    FieldInstruction fieldPut = instruction.asFieldInstruction();
-    DexField field = fieldPut.getField();
-    if (!identifierNameStrings.containsKey(field)) {
-      return iterator;
-    }
-    Value in = instruction.value();
-    if (in.isDexItemBasedConstString()) {
-      return iterator;
-    }
-    if (!in.isConstString()) {
-      warnUndeterminedIdentifierIfNecessary(field, code.context(), instruction, null);
-      return iterator;
-    }
-    DexString original = in.getConstInstruction().asConstString().getValue();
-    DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
-    if (itemBasedString == null) {
-      warnUndeterminedIdentifierIfNecessary(field, code.context(), instruction, original);
-      return iterator;
-    }
+      FieldPut fieldPut,
+      DexReference itemBasedString) {
     // Move the cursor back to $fieldPut
     assert iterator.peekPrevious() == fieldPut;
     iterator.previous();
     // Prepare $decoupled just before $fieldPut
-    Value newIn = code.createValue(in.getType(), in.getLocalInfo());
+    Value newIn = code.createValue(fieldPut.value().getType(), fieldPut.value().getLocalInfo());
     DexItemBasedConstString decoupled =
         new DexItemBasedConstString(newIn, itemBasedString, ClassNameComputationInfo.none());
     decoupled.setPosition(fieldPut.getPosition());
     // If the current block has catch handler, split into two blocks.
     // Because const-string we're about to add is also a throwing instr, we need to split
     // before adding it.
-    BasicBlock block = instruction.getBlock();
+    BasicBlock block = fieldPut.getBlock();
     BasicBlock blockWithFieldInstruction =
         block.hasCatchHandlers() ? iterator.split(code, blocks) : block;
     if (blockWithFieldInstruction != block) {
@@ -186,12 +217,13 @@
       assert iterator.peekNext() == fieldPut;
       iterator.next();
     }
-    if (instruction.isStaticPut()) {
-      iterator.replaceCurrentInstruction(new StaticPut(newIn, field));
+    if (fieldPut.isStaticPut()) {
+      iterator.replaceCurrentInstruction(new StaticPut(newIn, fieldPut.getField()));
     } else {
-      assert instruction.isInstancePut();
-      InstancePut instancePut = instruction.asInstancePut();
-      iterator.replaceCurrentInstruction(new InstancePut(field, instancePut.object(), newIn));
+      assert fieldPut.isInstancePut();
+      InstancePut instancePut = fieldPut.asInstancePut();
+      iterator.replaceCurrentInstruction(
+          new InstancePut(fieldPut.getField(), instancePut.object(), newIn));
     }
     return iterator;
   }
@@ -282,7 +314,7 @@
           continue;
         }
         DexString original = in.getConstInstruction().asConstString().getValue();
-        DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
+        DexReference itemBasedString = inferMemberOrTypeFromNameString(appView(), original);
         if (itemBasedString == null) {
           warnUndeterminedIdentifierIfNecessary(invokedMethod, code.context(), invoke, original);
           continue;
@@ -320,16 +352,17 @@
         }
       }
     }
-    if (!Arrays.stream(changes).allMatch(Objects::isNull)) {
-      List<Value> newIns =
-          Streams.mapWithIndex(
-                  ins.stream(),
-                  (in, index) -> changes[(int) index] != null ? changes[(int) index] : in)
-              .collect(Collectors.toList());
-      iterator.replaceCurrentInstruction(
-          Invoke.create(
-              invoke.getType(), invokedMethod, invokedMethod.proto, invoke.outValue(), newIns));
+    if (ArrayUtils.none(changes, Objects::nonNull)) {
+      return iterator;
     }
+    List<Value> newIns =
+        Streams.mapWithIndex(
+                ins.stream(),
+                (in, index) -> changes[(int) index] != null ? changes[(int) index] : in)
+            .collect(Collectors.toList());
+    iterator.replaceCurrentInstruction(
+        Invoke.create(
+            invoke.getType(), invokedMethod, invokedMethod.proto, invoke.outValue(), newIns));
     return iterator;
   }
 
@@ -372,8 +405,10 @@
     }
     Origin origin = method.getOrigin();
     String kind = member.isDexField() ? "field" : "method";
-    String originalMessage = original == null ? "what identifier string flows to "
-        : "what '" + original.toString() + "' refers to, which flows to ";
+    String originalMessage =
+        original == null
+            ? "what identifier string flows to "
+            : "what '" + original + "' refers to, which flows to ";
     String message =
         "Cannot determine " + originalMessage + member.toSourceString()
             + " that is specified in -identifiernamestring rules."
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringVerticallyMergedClassTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringVerticallyMergedClassTest.java
index 5e0cc75..022d375 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringVerticallyMergedClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringVerticallyMergedClassTest.java
@@ -39,8 +39,7 @@
         .setMinApi(parameters)
         .compile()
         .run(parameters.getRuntime(), Main.class)
-        // TODO(b/344939647): Should be "A".
-        .assertSuccessWithOutputLines("null");
+        .assertSuccessWithOutputLines("A");
   }
 
   static class Main {