Output fields in smali disassembler
Change-Id: If3a4a2a77596a7981919a38bc750f9f0c048b7af
diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java
index 7c4ac49..6f68e5b 100644
--- a/src/main/java/com/android/tools/r8/Disassemble.java
+++ b/src/main/java/com/android/tools/r8/Disassemble.java
@@ -243,7 +243,7 @@
new ApplicationReader(app, options, timing).read(command.proguardMap, executor);
DexByteCodeWriter writer =
command.useSmali()
- ? new SmaliWriter(application, options)
+ ? new SmaliWriter(application, options, !command.noCode())
: new AssemblyWriter(
application, options, command.allInfo, command.useIr(), !command.noCode());
if (command.getOutputPath() != null) {
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 4ed66d8..a583683 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -116,10 +116,19 @@
}
@Override
- void writeFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ void writeInstanceFieldsHeader(DexProgramClass clazz, PrintStream ps) {
if (writeFields) {
ps.println("#");
- ps.println("# Fields:");
+ ps.println("# Instance fields:");
+ ps.println("#");
+ }
+ }
+
+ @Override
+ void writeStaticFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ if (writeFields) {
+ ps.println("#");
+ ps.println("# Static fields:");
ps.println("#");
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index 60ab622..8cb22f1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -89,8 +89,10 @@
private void writeClass(DexProgramClass clazz, PrintStream ps) {
writeClassHeader(clazz, ps);
- writeFieldsHeader(clazz, ps);
- clazz.forEachField(field -> writeField(field, ps));
+ writeStaticFieldsHeader(clazz, ps);
+ clazz.forEachFieldMatching(DexEncodedMember::isStatic, field -> writeField(field, ps));
+ writeInstanceFieldsHeader(clazz, ps);
+ clazz.forEachFieldMatching(DexEncodedMember::isInstance, field -> writeField(field, ps));
writeFieldsFooter(clazz, ps);
writeMethodsHeader(clazz, ps);
clazz.forEachProgramMethod(method -> writeMethod(method, ps));
@@ -102,7 +104,11 @@
abstract void writeClassHeader(DexProgramClass clazz, PrintStream ps);
- void writeFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ void writeInstanceFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ // Do nothing.
+ }
+
+ void writeStaticFieldsHeader(DexProgramClass clazz, PrintStream ps) {
// Do nothing.
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index ada1c8a..5cf7530 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -20,8 +20,11 @@
import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.kotlin.KotlinFieldLevelInfo;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ConsumerUtils;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -166,7 +169,29 @@
@Override
public String toSmaliString() {
- return getReference().toSmaliString();
+ StringBuilder builder = new StringBuilder();
+ builder.append(".field ");
+ builder.append(accessFlags.toSmaliString());
+ builder.append(" ");
+ builder.append(getName().toSmaliString());
+ builder.append(":");
+ builder.append(getType().toSmaliString());
+ return builder.toString();
+ }
+
+ public String toSmaliString(ClassNameMapper naming) {
+ FieldSignature fieldSignature =
+ naming != null
+ ? naming.originalSignatureOf(getReference())
+ : FieldSignature.fromDexField(getReference());
+ StringBuilder builder = new StringBuilder();
+ builder.append(".field ");
+ builder.append(accessFlags.toSmaliString());
+ builder.append(" ");
+ builder.append(fieldSignature.getName());
+ builder.append(":");
+ builder.append(DescriptorUtils.javaTypeToDescriptor(fieldSignature.getTypeName()));
+ return builder.toString();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
index e1bb25e..b68c45b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -57,6 +57,10 @@
return this;
}
+ public final boolean isInstance() {
+ return !isStatic();
+ }
+
public final boolean isPrivate() {
return getAccessFlags().isPrivate();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 6bd54aa..ff92837 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -594,10 +594,6 @@
return (accessFlags.isPrivate() || accessFlags.isConstructor()) && !accessFlags.isStatic();
}
- public boolean isInstance() {
- return !isStatic();
- }
-
@Override
public boolean isStatic() {
checkIfObsolete();
@@ -896,6 +892,10 @@
}
public String toSmaliString(ClassNameMapper naming) {
+ return toSmaliString(naming, true);
+ }
+
+ public String toSmaliString(ClassNameMapper naming, boolean writeCode) {
checkIfObsolete();
StringBuilder builder = new StringBuilder();
builder.append(".method ");
@@ -904,7 +904,7 @@
builder.append(getReference().name.toSmaliString());
builder.append(getReference().proto.toSmaliString());
builder.append("\n");
- if (code != null) {
+ if (writeCode && hasCode()) {
DexCode dexCode = code.asDexCode();
builder.append(" .registers ");
builder.append(dexCode.registerSize);
diff --git a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
index e676697..f98ef60 100644
--- a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
@@ -16,9 +16,11 @@
public class SmaliWriter extends DexByteCodeWriter {
- public SmaliWriter(DexApplication application,
- InternalOptions options) {
+ private final boolean writeCode;
+
+ public SmaliWriter(DexApplication application, InternalOptions options, boolean writeCode) {
super(application, options);
+ this.writeCode = writeCode;
}
/** Return smali source for the application code. */
@@ -27,7 +29,7 @@
try (PrintStream ps = new PrintStream(os)) {
DexApplication dexApplication =
new ApplicationReader(application, options, Timing.empty()).read();
- SmaliWriter writer = new SmaliWriter(dexApplication, options);
+ SmaliWriter writer = new SmaliWriter(dexApplication, options, true);
writer.write(ps);
} catch (IOException e) {
throw new CompilationError("Failed to generate smali sting", e);
@@ -46,17 +48,25 @@
ps.append(clazz.accessFlags.toSmaliString());
ps.append(" ");
ps.append(clazz.type.toSmaliString());
- ps.append("\n\n");
+ ps.append('\n');
+
if (clazz.type != application.dexItemFactory.objectType) {
ps.append(".super ");
ps.append(clazz.superType.toSmaliString());
- ps.append("\n");
+ ps.append('\n');
+ }
+ ps.append('\n');
+
+ if (!clazz.getInterfaces().isEmpty()) {
+ ps.append("# interfaces").append('\n');
for (DexType iface : clazz.interfaces.values) {
ps.append(".implements ");
ps.append(iface.toSmaliString());
- ps.append("\n");
+ ps.append('\n');
}
+ ps.append('\n');
}
+ ps.append('\n');
}
@Override
@@ -64,17 +74,35 @@
ps.append("# End of class ");
ps.append(clazz.type.toSmaliString());
ps.append("\n");
+ ps.append("\n");
}
@Override
void writeMethod(ProgramMethod method, PrintStream ps) {
ps.append("\n");
- ps.append(method.getDefinition().toSmaliString(application.getProguardMap()));
+ ps.append(method.getDefinition().toSmaliString(application.getProguardMap(), writeCode));
ps.append("\n");
}
@Override
+ void writeInstanceFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ if (clazz.hasStaticFields()) {
+ ps.append('\n');
+ }
+ if (clazz.hasInstanceFields()) {
+ ps.append("# instance fields").append('\n');
+ }
+ }
+
+ @Override
+ void writeStaticFieldsHeader(DexProgramClass clazz, PrintStream ps) {
+ if (clazz.hasStaticFields()) {
+ ps.append("# static fields").append('\n');
+ }
+ }
+
+ @Override
void writeField(DexEncodedField field, PrintStream ps) {
- // Not yet implemented.
+ ps.append(field.toSmaliString(application.getProguardMap())).append('\n').append('\n');
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index bf0a8dd..1d024b3 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -187,6 +187,14 @@
field.type.toSourceString());
}
+ public String getName() {
+ return name;
+ }
+
+ public String getTypeName() {
+ return type;
+ }
+
public DexField toDexField(DexItemFactory factory, DexType clazz) {
return factory.createField(
clazz,