Add --ir option to Disassemble
Extend AssemblyWriter with a boolean flag writeIR that makes it use
IRConverter and CfgPrinter to output the IR of each method before and
after optimization (instead of outputting the JAR/DEX disassembly).
Change-Id: Idffbc2e7b379f19ffbfb571f36240fc9605b9dbe
diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java
index 9b1599f..7b17ec8 100644
--- a/src/main/java/com/android/tools/r8/Disassemble.java
+++ b/src/main/java/com/android/tools/r8/Disassemble.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -33,6 +32,7 @@
private Path proguardMapFile = null;
private boolean useSmali = false;
private boolean allInfo = false;
+ private boolean useIr;
@Override
Builder self() {
@@ -63,6 +63,11 @@
return this;
}
+ public Builder setUseIr(boolean useIr) {
+ this.useIr = useIr;
+ return this;
+ }
+
@Override
protected DisassembleCommand makeCommand() {
// If printing versions ignore everything else.
@@ -74,24 +79,26 @@
getOutputPath(),
proguardMapFile == null ? null : StringResource.fromFile(proguardMapFile),
allInfo,
- useSmali);
+ useSmali,
+ useIr);
}
}
- static final String USAGE_MESSAGE = String.join("\n", ImmutableList.of(
- "Usage: disasm [options] <input-files>",
- " where <input-files> are dex files",
- " and options are:",
- " --all # Include all information in disassembly.",
- " --smali # Disassemble using smali syntax.",
- " --pg-map <file> # Proguard map <file> for mapping names.",
- " --output # Specify a file or directory to write to.",
- " --version # Print the version of r8.",
- " --help # Print this message."));
-
+ static final String USAGE_MESSAGE =
+ "Usage: disasm [options] <input-files>\n"
+ + " where <input-files> are dex files\n"
+ + " and options are:\n"
+ + " --all # Include all information in disassembly.\n"
+ + " --smali # Disassemble using smali syntax.\n"
+ + " --ir # Print IR before and after optimization.\n"
+ + " --pg-map <file> # Proguard map <file> for mapping names.\n"
+ + " --output # Specify a file or directory to write to.\n"
+ + " --version # Print the version of r8.\n"
+ + " --help # Print this message.";
private final boolean allInfo;
private final boolean useSmali;
+ private final boolean useIr;
public static Builder builder() {
return new Builder();
@@ -112,10 +119,12 @@
builder.setPrintHelp(true);
} else if (arg.equals("--version")) {
builder.setPrintVersion(true);
- } else if (arg.equals("--all")) {
+ } else if (arg.equals("--all")) {
builder.setAllInfo(true);
} else if (arg.equals("--smali")) {
builder.setUseSmali(true);
+ } else if (arg.equals("--ir")) {
+ builder.setUseIr(true);
} else if (arg.equals("--pg-map")) {
builder.setProguardMapFile(Paths.get(args[++i]));
} else if (arg.equals("--output")) {
@@ -132,13 +141,18 @@
}
private DisassembleCommand(
- AndroidApp inputApp, Path outputPath, StringResource proguardMap,
- boolean allInfo, boolean useSmali) {
+ AndroidApp inputApp,
+ Path outputPath,
+ StringResource proguardMap,
+ boolean allInfo,
+ boolean useSmali,
+ boolean useIr) {
super(inputApp);
this.outputPath = outputPath;
this.proguardMap = proguardMap;
this.allInfo = allInfo;
this.useSmali = useSmali;
+ this.useIr = useIr;
}
private DisassembleCommand(boolean printHelp, boolean printVersion) {
@@ -147,6 +161,7 @@
proguardMap = null;
allInfo = false;
useSmali = false;
+ useIr = false;
}
public Path getOutputPath() {
@@ -157,6 +172,10 @@
return useSmali;
}
+ public boolean useIr() {
+ return useIr;
+ }
+
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions();
@@ -190,9 +209,10 @@
try {
DexApplication application =
new ApplicationReader(app, options, timing).read(command.proguardMap, executor);
- DexByteCodeWriter writer = command.useSmali()
- ? new SmaliWriter(application, options)
- : new AssemblyWriter(application, options, command.allInfo);
+ DexByteCodeWriter writer =
+ command.useSmali()
+ ? new SmaliWriter(application, options)
+ : new AssemblyWriter(application, options, command.allInfo, command.useIr());
if (command.getOutputPath() != null) {
writer.write(command.getOutputPath());
} else {
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 89abadd..23dbfbf 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -3,9 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.OptimizationFeedback;
+import com.android.tools.r8.ir.conversion.OptimizationFeedbackIgnore;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
+import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Timing;
import java.io.PrintStream;
public class AssemblyWriter extends DexByteCodeWriter {
@@ -13,12 +19,29 @@
private final boolean writeAllClassInfo;
private final boolean writeFields;
private final boolean writeAnnotations;
+ private final boolean writeIR;
+ private final AppInfoWithSubtyping appInfo;
+ private final Timing timing = new Timing("AssemblyWriter");
+ private final OptimizationFeedback ignoreOptimizationFeedback = new OptimizationFeedbackIgnore();
- public AssemblyWriter(DexApplication application, InternalOptions options, boolean allInfo) {
+ public AssemblyWriter(
+ DexApplication application, InternalOptions options, boolean allInfo, boolean writeIR) {
super(application, options);
this.writeAllClassInfo = allInfo;
this.writeFields = allInfo;
this.writeAnnotations = allInfo;
+ this.writeIR = writeIR;
+ if (writeIR) {
+ this.appInfo = new AppInfoWithSubtyping(application.toDirect());
+ if (options.programConsumer == null) {
+ // Use class-file backend, since the CF frontend for testing does not support desugaring of
+ // synchronized methods for the DEX backend (b/109789541).
+ options.programConsumer = ClassFileConsumer.emptyConsumer();
+ }
+ options.outline.enabled = false;
+ } else {
+ this.appInfo = null;
+ }
}
@Override
@@ -88,10 +111,21 @@
ps.println();
Code code = method.getCode();
if (code != null) {
- ps.println(code.toString(method, naming));
+ if (writeIR) {
+ writeIR(method, ps);
+ } else {
+ ps.println(code.toString(method, naming));
+ }
}
}
+ private void writeIR(DexEncodedMethod method, PrintStream ps) {
+ CfgPrinter printer = new CfgPrinter();
+ new IRConverter(appInfo, options, timing, printer)
+ .processMethod(method, ignoreOptimizationFeedback, null, null, null);
+ ps.println(printer.toString());
+ }
+
private void writeAnnotations(DexAnnotationSet annotations, PrintStream ps) {
if (writeAnnotations) {
if (!annotations.isEmpty()) {