Create CfCode instances from class writer

Change-Id: I55d3de99f411cdfb51e6094d8685f0b77f8c7947
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index e612d68..327c5d0 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -79,6 +79,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.objectweb.asm.Opcodes;
 
 /** Rudimentary printer to print the source representation for creating CfCode object. */
 public class CfCodePrinter extends CfPrinter {
@@ -593,7 +594,22 @@
 
   @Override
   public void print(CfFieldInstruction insn) {
-    throw new Unreachable();
+    switch (insn.getOpcode()) {
+      case Opcodes.GETFIELD:
+        printNewInstruction("CfInstanceFieldRead", dexField(insn.getField()));
+        break;
+      case Opcodes.PUTFIELD:
+        printNewInstruction("CfInstanceFieldWrite", dexField(insn.getField()));
+        break;
+      case Opcodes.GETSTATIC:
+        printNewInstruction("CfStaticFieldRead", dexField(insn.getField()));
+        break;
+      case Opcodes.PUTSTATIC:
+        printNewInstruction("CfStaticFieldWrite", dexField(insn.getField()));
+        break;
+      default:
+        throw new Unreachable();
+    }
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/startup/InstrumentationServer.java b/src/main/java/com/android/tools/r8/startup/InstrumentationServer.java
index d0e42e8..5b839c2 100644
--- a/src/main/java/com/android/tools/r8/startup/InstrumentationServer.java
+++ b/src/main/java/com/android/tools/r8/startup/InstrumentationServer.java
@@ -9,18 +9,28 @@
 package com.android.tools.r8.startup;
 
 import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory;
 import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
 import java.util.Collections;
 
 public final class InstrumentationServer {
@@ -63,4 +73,50 @@
   private static DexEncodedMethod[] createVirtualMethods(DexItemFactory dexItemFactory) {
     return new DexEncodedMethod[0];
   }
+
+  public static CfCode createInstanceInitializerCfCode0(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.objectType,
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfReturnVoid(),
+            label1),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode1_getInstance(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        0,
+        ImmutableList.of(
+            label0,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType(
+                            "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+                    options.itemFactory.createString("getInstance")),
+                false),
+            new CfReturn(ValueType.OBJECT)),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/startup/InstrumentationServerImpl.java b/src/main/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
index 395685d..cc0ab24 100644
--- a/src/main/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
+++ b/src/main/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
@@ -10,11 +10,32 @@
 
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
+import com.android.tools.r8.cf.code.CfConstNumber;
+import com.android.tools.r8.cf.code.CfConstString;
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfGoto;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstanceFieldWrite;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStaticFieldRead;
+import com.android.tools.r8.cf.code.CfStaticFieldWrite;
+import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
@@ -22,7 +43,13 @@
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory;
 import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
+import java.util.ArrayDeque;
+import java.util.Arrays;
 import java.util.Collections;
 
 public final class InstrumentationServerImpl {
@@ -108,4 +135,435 @@
   private static DexEncodedMethod[] createVirtualMethods(DexItemFactory dexItemFactory) {
     return new DexEncodedMethod[0];
   }
+
+  public static CfCode createClassInitializerCfCode(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        0,
+        ImmutableList.of(
+            label0,
+            new CfNew(
+                options.itemFactory.createType(
+                    "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStaticFieldWrite(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createString("INSTANCE"))),
+            new CfReturnVoid()),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createInstanceInitializerCfCode1(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServer;"),
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfNew(options.itemFactory.stringBuilderType),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfInstanceFieldWrite(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createString("builder"))),
+            label2,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInstanceFieldWrite(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.booleanType,
+                    options.itemFactory.createString("writeToLogcat"))),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfConstString(options.itemFactory.createString("r8")),
+            new CfInstanceFieldWrite(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.stringType,
+                    options.itemFactory.createString("logcatTag"))),
+            label4,
+            new CfReturnVoid(),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode2_addLine(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createString("builder"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(
+                        options.itemFactory.stringBuilderType, options.itemFactory.stringType),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfConstNumber(10, ValueType.INT),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(
+                        options.itemFactory.stringBuilderType, options.itemFactory.charType),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label1,
+            new CfReturnVoid(),
+            label2),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode3_addNonSyntheticMethod(
+      InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType(
+                            "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+                    options.itemFactory.createString("getInstance")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.voidType, options.itemFactory.stringType),
+                    options.itemFactory.createString("addLine")),
+                false),
+            label1,
+            new CfReturnVoid(),
+            label2),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode4_addSyntheticMethod(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        1,
+        ImmutableList.of(
+            label0,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType(
+                            "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+                    options.itemFactory.createString("getInstance")),
+                false),
+            new CfNew(options.itemFactory.stringBuilderType),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfConstNumber(83, ValueType.INT),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(
+                        options.itemFactory.stringBuilderType, options.itemFactory.charType),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(
+                        options.itemFactory.stringBuilderType, options.itemFactory.stringType),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(options.itemFactory.stringType),
+                    options.itemFactory.createString("toString")),
+                false),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.voidType, options.itemFactory.stringType),
+                    options.itemFactory.createString("addLine")),
+                false),
+            label1,
+            new CfReturnVoid(),
+            label2),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode5_getInstance(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        0,
+        ImmutableList.of(
+            label0,
+            new CfStaticFieldRead(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.createString("INSTANCE"))),
+            new CfReturn(ValueType.OBJECT)),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode6_writeToFile(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/io/FileOutputStream;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/io/FileOutputStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.voidType,
+                        options.itemFactory.createType("Ljava/io/File;")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                options.itemFactory.createField(
+                    options.itemFactory.createType(
+                        "Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createString("builder"))),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringBuilderType,
+                    options.itemFactory.createProto(options.itemFactory.stringType),
+                    options.itemFactory.createString("toString")),
+                false),
+            new CfConstString(options.itemFactory.createString("UTF-8")),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/nio/charset/Charset;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/nio/charset/Charset;"),
+                        options.itemFactory.stringType),
+                    options.itemFactory.createString("forName")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.stringType,
+                    options.itemFactory.createProto(
+                        options.itemFactory.byteArrayType,
+                        options.itemFactory.createType("Ljava/nio/charset/Charset;")),
+                    options.itemFactory.createString("getBytes")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/io/FileOutputStream;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.voidType, options.itemFactory.byteArrayType),
+                    options.itemFactory.createString("write")),
+                false),
+            label2,
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/io/FileOutputStream;"),
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("close")),
+                false),
+            label3,
+            new CfGoto(label6),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType(
+                              "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType("Ljava/io/File;")),
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType("Ljava/io/FileOutputStream;"))
+                    }),
+                new ArrayDeque<>(
+                    Arrays.asList(
+                        FrameType.initializedNonNullReference(options.itemFactory.throwableType)))),
+            new CfStore(ValueType.OBJECT, 3),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/io/FileOutputStream;"),
+                    options.itemFactory.createProto(options.itemFactory.voidType),
+                    options.itemFactory.createString("close")),
+                false),
+            label5,
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfThrow(),
+            label6,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType(
+                              "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType("Ljava/io/File;")),
+                      FrameType.initializedNonNullReference(
+                          options.itemFactory.createType("Ljava/io/FileOutputStream;"))
+                    })),
+            new CfReturnVoid(),
+            label7),
+        ImmutableList.of(
+            new CfTryCatch(
+                label1,
+                label2,
+                ImmutableList.of(options.itemFactory.throwableType),
+                ImmutableList.of(label4))),
+        ImmutableList.of());
+  }
+
+  public static CfCode createCfCode7_writeToLogcat(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        2,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfConstString(options.itemFactory.createString("r8")),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Landroid/util/Log;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.intType,
+                        options.itemFactory.stringType,
+                        options.itemFactory.stringType),
+                    options.itemFactory.createString("v")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label1,
+            new CfReturnVoid(),
+            label2),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
index fd9429c..d924288 100644
--- a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
+++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfClassGenerator.java
@@ -6,15 +6,28 @@
 
 import static com.android.tools.r8.utils.PredicateUtils.not;
 
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.cf.CfCodePrinter;
+import com.android.tools.r8.graph.ClassKind;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.FieldAccessFlags;
+import com.android.tools.r8.graph.JarApplicationReader;
+import com.android.tools.r8.graph.JarClassFileReader;
 import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.function.Predicate;
 
 public abstract class CfClassGenerator extends CodeGenerationBase {
@@ -32,21 +45,30 @@
     return formatRawOutput(generateRawOutput());
   }
 
-  private String generateRawOutput() {
+  private String generateRawOutput() throws IOException {
     String classDeclaration = generateClassDeclaration();
     return StringUtils.lines(getHeaderString(), imports.generateImports(), classDeclaration);
   }
 
-  private String generateClassDeclaration() {
+  private String generateClassDeclaration() throws IOException {
     JavaStringBuilder builder = new JavaStringBuilder();
     builder.append("public final class " + getGeneratedClassName() + " ").appendOpeningBrace();
     generateCreateClassMethod(builder);
     generateCreateFieldsMethod(builder, "createInstanceFields", not(FieldAccessFlags::isStatic));
     generateCreateFieldsMethod(builder, "createStaticFields", FieldAccessFlags::isStatic);
+    CfCodePrinter codePrinter = new CfCodePrinter();
+    Map<MethodReference, String> createCfCodeMethodNames = generateCreateCfCodeMethods(codePrinter);
     generateCreateMethodsMethod(
-        builder, "createDirectMethods", MethodAccessFlags::belongsToDirectPool);
+        builder,
+        "createDirectMethods",
+        MethodAccessFlags::belongsToDirectPool,
+        createCfCodeMethodNames);
     generateCreateMethodsMethod(
-        builder, "createVirtualMethods", MethodAccessFlags::belongsToVirtualPool);
+        builder,
+        "createVirtualMethods",
+        MethodAccessFlags::belongsToVirtualPool,
+        createCfCodeMethodNames);
+    codePrinter.getMethods().forEach(builder::appendLine);
     builder.appendClosingBrace();
     return builder.toString();
   }
@@ -218,7 +240,10 @@
   }
 
   private void generateCreateMethodsMethod(
-      JavaStringBuilder builder, String methodName, Predicate<MethodAccessFlags> predicate) {
+      JavaStringBuilder builder,
+      String methodName,
+      Predicate<MethodAccessFlags> predicate,
+      Map<MethodReference, String> createCfCodeMethodNames) {
     builder
         .startLine()
         .append("private static ")
@@ -239,6 +264,41 @@
     builder.appendClosingBrace();
   }
 
+  private Map<MethodReference, String> generateCreateCfCodeMethods(CfCodePrinter codePrinter)
+      throws IOException {
+    Map<MethodReference, String> createCfCodeMethodNames = new HashMap<>();
+    InternalOptions options = new InternalOptions(factory, new Reporter());
+    options.testing.readInputStackMaps = true;
+    JarClassFileReader<DexProgramClass> reader =
+        new JarClassFileReader<>(
+            new JarApplicationReader(options),
+            clazz -> {
+              int index = 0;
+              for (DexEncodedMethod method : clazz.allMethodsSorted()) {
+                if (!method.hasCode()) {
+                  continue;
+                }
+                String generatedMethodName = getCreateCfCodeMethodName(method, index);
+                codePrinter.visitMethod(generatedMethodName, method.getCode().asCfCode());
+                index++;
+              }
+            },
+            ClassKind.PROGRAM);
+    reader.read(Origin.unknown(), ToolHelper.getClassAsBytes(getGeneratedClass()));
+    codePrinter.getImports().forEach(imports::addImport);
+    return createCfCodeMethodNames;
+  }
+
+  private String getCreateCfCodeMethodName(DexEncodedMethod method, int index) {
+    if (method.isClassInitializer()) {
+      return "createClassInitializerCfCode";
+    }
+    if (method.isInstanceInitializer()) {
+      return "createInstanceInitializerCfCode" + index;
+    }
+    return "createCfCode" + index + "_" + method.getName().toString();
+  }
+
   public void writeClassToFile() throws IOException {
     FileUtils.writeToFile(getGeneratedFile(), null, generateClass().getBytes());
   }
diff --git a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfCodeGeneratorImportCollection.java b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfCodeGeneratorImportCollection.java
index bde89aa..4072619 100644
--- a/src/test/java/com/android/tools/r8/cfmethodgeneration/CfCodeGeneratorImportCollection.java
+++ b/src/test/java/com/android/tools/r8/cfmethodgeneration/CfCodeGeneratorImportCollection.java
@@ -95,7 +95,7 @@
     return name;
   }
 
-  private String addImport(String name) {
+  String addImport(String name) {
     imports.add(name);
     return name;
   }