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;
}