Remove InitClass instructions in output

Change-Id: I315ad5618e388a1ea874174b7aa331737a89fdbf
diff --git a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java b/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
deleted file mode 100644
index 47a4392..0000000
--- a/src/main/java/com/android/tools/r8/dex/code/DexInitClass.java
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.dex.code;
-
-import com.android.tools.r8.dex.IndexedItemCollection;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ObjectToOffsetMapping;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.ir.code.FieldMemberType;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.utils.RetracerForCodePrinting;
-import com.android.tools.r8.utils.structural.CompareToVisitor;
-import com.android.tools.r8.utils.structural.HashingVisitor;
-import com.android.tools.r8.utils.structural.StructuralSpecification;
-import java.nio.ShortBuffer;
-
-public class DexInitClass extends DexBase2Format {
-
-  public static final int OPCODE = 0x60;
-  public static final String NAME = "InitClass";
-  public static final String SMALI_NAME = "initclass";
-
-  private final int dest;
-  private final DexType clazz;
-
-  private static void specify(StructuralSpecification<DexInitClass, ?> spec) {
-    spec.withInt(i -> i.dest).withItem(i -> i.clazz);
-  }
-
-  public DexInitClass(int dest, DexType clazz) {
-    assert clazz.isClassType();
-    this.dest = dest;
-    this.clazz = clazz;
-  }
-
-  @Override
-  public void buildIR(IRBuilder builder) {
-    builder.addInitClass(dest, clazz);
-  }
-
-  @Override
-  public void collectIndexedItems(
-      AppView<?> appView,
-      GraphLens codeLens,
-      IndexedItemCollection indexedItems,
-      ProgramMethod context,
-      LensCodeRewriterUtils rewriter) {
-    // We intentionally apply the graph lens first, and then the init class lens, using the fact
-    // that the init class lens maps classes in the final program to fields in the final program.
-    DexType rewrittenClass = appView.graphLens().lookupType(clazz, codeLens);
-    DexField clinitField = appView.initClassLens().getInitClassField(rewrittenClass);
-    clinitField.collectIndexedItems(appView, indexedItems);
-  }
-
-  @Override
-  public boolean canThrow() {
-    return true;
-  }
-
-  @Override
-  public String getName() {
-    return NAME;
-  }
-
-  @Override
-  public String getSmaliName() {
-    return SMALI_NAME;
-  }
-
-  @Override
-  public int getOpcode() {
-    throw new Unreachable();
-  }
-
-  @Override
-  int getCompareToId() {
-    return DexCompareHelper.INIT_CLASS_COMPARE_ID;
-  }
-
-  private int getOpcode(DexField field) {
-    FieldMemberType type = FieldMemberType.fromDexType(field.type);
-    switch (type) {
-      case INT:
-      case FLOAT:
-        return DexSget.OPCODE;
-      case LONG:
-      case DOUBLE:
-        return DexSgetWide.OPCODE;
-      case OBJECT:
-        return DexSgetObject.OPCODE;
-      case BOOLEAN:
-        return DexSgetBoolean.OPCODE;
-      case BYTE:
-        return DexSgetByte.OPCODE;
-      case CHAR:
-        return DexSgetChar.OPCODE;
-      case SHORT:
-        return DexSgetShort.OPCODE;
-      default:
-        throw new Unreachable("Unexpected type: " + type);
-    }
-  }
-
-  @Override
-  public void registerUse(UseRegistry<?> registry) {
-    registry.registerInitClass(clazz);
-  }
-
-  @Override
-  public void write(
-      ShortBuffer buffer,
-      ProgramMethod context,
-      GraphLens graphLens,
-      GraphLens codeLens,
-      ObjectToOffsetMapping mapping,
-      LensCodeRewriterUtils rewriter) {
-    // We intentionally apply the graph lens first, and then the init class lens, using the fact
-    // that the init class lens maps classes in the final program to fields in the final program.
-    DexType rewrittenClass = graphLens.lookupType(clazz, codeLens);
-    DexField clinitField = mapping.getClinitField(rewrittenClass);
-    writeFirst(dest, buffer, getOpcode(clinitField));
-    write16BitReference(clinitField, buffer, mapping);
-  }
-
-  @Override
-  public int hashCode() {
-    return ((clazz.hashCode() << 8) | dest) ^ getClass().hashCode();
-  }
-
-  @Override
-  final int internalAcceptCompareTo(DexInstruction other, CompareToVisitor visitor) {
-    return visitor.visit(this, (DexInitClass) other, DexInitClass::specify);
-  }
-
-  @Override
-  void internalAcceptHashing(HashingVisitor visitor) {
-    visitor.visit(this, DexInitClass::specify);
-  }
-
-  @Override
-  public String toSmaliString(RetracerForCodePrinting retracer) {
-    return formatSmaliString("v" + dest + ", " + clazz.toSmaliString());
-  }
-
-  @Override
-  public String toString(RetracerForCodePrinting retracer) {
-    return formatString("v" + dest + ", " + retracer.toDescriptor(clazz));
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InitClass.java b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
index bb3e50d..c9039c1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InitClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
@@ -5,9 +5,8 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.cf.LoadStoreHelper;
-import com.android.tools.r8.cf.code.CfInitClass;
 import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.dex.code.DexInitClass;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
@@ -73,13 +72,12 @@
 
   @Override
   public void buildDex(DexBuilder builder) {
-    int dest = builder.allocatedRegister(outValue(), getNumber());
-    builder.add(this, new DexInitClass(dest, clazz));
+    throw new Unreachable();
   }
 
   @Override
   public void buildCf(CfBuilder builder) {
-    builder.add(new CfInitClass(clazz), this);
+    throw new Unreachable();
   }
 
   @Override
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 f168d4e..941930c 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
@@ -18,6 +18,7 @@
 import com.android.tools.r8.ir.conversion.passes.ConstResourceNumberRewriter;
 import com.android.tools.r8.ir.conversion.passes.DexItemBasedConstStringRemover;
 import com.android.tools.r8.ir.conversion.passes.FilledNewArrayRewriter;
+import com.android.tools.r8.ir.conversion.passes.InitClassRemover;
 import com.android.tools.r8.ir.conversion.passes.StringSwitchRemover;
 import com.android.tools.r8.ir.optimize.ConstantCanonicalizer;
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
@@ -143,6 +144,7 @@
             new AdaptClassStringsRewriter(appView),
             new ConstResourceNumberRemover(appView),
             new DexItemBasedConstStringRemover(appView),
+            new InitClassRemover(appView),
             new RecordInvokeDynamicInvokeCustomRewriter(appView),
             new FilledNewArrayRewriter(appView),
             new StringSwitchRemover(appView));
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/InitClassRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/InitClassRemover.java
new file mode 100644
index 0000000..bde3df6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/InitClassRemover.java
@@ -0,0 +1,51 @@
+// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.conversion.passes;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InitClass;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
+
+public class InitClassRemover extends CodeRewriterPass<AppInfoWithClassHierarchy> {
+
+  public InitClassRemover(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    super(appView);
+  }
+
+  @Override
+  protected String getRewriterId() {
+    return "InitClassRemover";
+  }
+
+  @Override
+  protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
+    return code.metadata().mayHaveInitClass();
+  }
+
+  @Override
+  protected CodeRewriterResult rewriteCode(IRCode code) {
+    boolean hasChanged = false;
+    InstructionListIterator iterator = code.instructionListIterator();
+    while (iterator.hasNext()) {
+      InitClass instruction = iterator.next().asInitClass();
+      if (instruction != null) {
+        DexField field = appView.initClassLens().getInitClassField(instruction.getClassValue());
+        StaticGet replacement =
+            StaticGet.builder()
+                .setField(field)
+                .setFreshOutValue(code, field.getType().toTypeElement(appView))
+                .build();
+        iterator.replaceCurrentInstruction(replacement);
+        hasChanged = true;
+      }
+    }
+    return CodeRewriterResult.hasChanged(hasChanged);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/classinit/InitClassPopCfTest.java b/src/test/java/com/android/tools/r8/debug/classinit/InitClassPopCfTest.java
index 86ff2c4..7ffe710 100644
--- a/src/test/java/com/android/tools/r8/debug/classinit/InitClassPopCfTest.java
+++ b/src/test/java/com/android/tools/r8/debug/classinit/InitClassPopCfTest.java
@@ -4,9 +4,6 @@
 
 package com.android.tools.r8.debug.classinit;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 import com.android.tools.r8.AlwaysInline;
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
@@ -17,10 +14,6 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.Iterator;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -52,7 +45,8 @@
         .addKeepRules("-keep class * { static java.lang.Object f; }")
         .addKeepMainRule(Main.class)
         .compile()
-        .inspect(InitClassPopCfTest::verifyInitClassFollowedByPopInCf);
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("0", "clinit A", "5504", "5");
   }
 
   private void modifyIR(IRCode irCode, AppView<?> appView) {
@@ -73,22 +67,6 @@
     }
   }
 
-  private static void verifyInitClassFollowedByPopInCf(CodeInspector i) {
-    MethodSubject main = i.clazz(Main.class).mainMethod();
-    Iterator<InstructionSubject> iterator = main.iterateInstructions();
-    int index = 0;
-    while (iterator.hasNext()) {
-      InstructionSubject next = iterator.next();
-      // All static gets on non System are init class.
-      if (next.isStaticGet()
-          && !next.getField().getHolderType().toString().equals("java.lang.System")) {
-        assertTrue(iterator.next().isPop());
-        index++;
-      }
-    }
-    assertEquals(4, index);
-  }
-
   public static class A {
     static {
       System.out.println("clinit A");