core: refactor info classes for store only one instance

This commit is contained in:
Skylot
2015-02-14 20:44:34 +03:00
parent 10de4ff490
commit 7844e554aa
14 changed files with 127 additions and 70 deletions
@@ -6,7 +6,6 @@ import jadx.core.codegen.CodeGen;
import jadx.core.codegen.CodeWriter;
import jadx.core.deobf.DefaultDeobfuscator;
import jadx.core.deobf.Deobfuscator;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.dex.visitors.IDexTreeVisitor;
@@ -90,7 +89,6 @@ public final class JadxDecompiler {
}
void reset() {
ClassInfo.clearCache();
classes = null;
resources = null;
xmlParser = null;
@@ -192,7 +192,7 @@ public class ClassGen {
if (type.isGenericType()) {
code.add(type.getObject());
} else {
useClass(code, ClassInfo.fromType(type));
useClass(code, ClassInfo.fromType(cls.dex(), type));
}
if (list != null && !list.isEmpty()) {
code.add(" extends ");
@@ -201,7 +201,7 @@ public class ClassGen {
if (g.isGenericType()) {
code.add(g.getObject());
} else {
useClass(code, ClassInfo.fromType(g));
useClass(code, ClassInfo.fromType(cls.dex(), g));
}
if (it.hasNext()) {
code.add(" & ");
@@ -407,7 +407,7 @@ public class ClassGen {
if (type.isGenericType()) {
code.add(type.getObject());
} else {
useClass(code, ClassInfo.fromType(type));
useClass(code, ClassInfo.fromType(cls.dex(), type));
}
} else if (stype == PrimitiveType.ARRAY) {
useType(code, type.getArrayElement());
@@ -39,7 +39,7 @@ public class MethodGen {
this.mth = mth;
this.classGen = classGen;
this.annotationGen = classGen.getAnnotationGen();
this.nameGen = new NameGen(classGen.isFallbackMode());
this.nameGen = new NameGen(mth, classGen.isFallbackMode());
}
public ClassGen getClassGen() {
@@ -14,6 +14,7 @@ import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.mods.ConstructorInsn;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.Utils;
import java.util.HashMap;
@@ -26,6 +27,7 @@ public class NameGen {
private static final Map<String, String> OBJ_ALIAS;
private final Set<String> varNames = new HashSet<String>();
private final MethodNode mth;
private final boolean fallback;
static {
@@ -45,7 +47,8 @@ public class NameGen {
OBJ_ALIAS.put("java.lang.Double", "d");
}
public NameGen(boolean fallback) {
public NameGen(MethodNode mth, boolean fallback) {
this.mth = mth;
this.fallback = fallback;
}
@@ -107,7 +110,7 @@ public class NameGen {
}
varName = name;
} else {
varName = makeNameForType(arg.getType());
varName = guessName(arg);
}
if (NameMapper.isReserved(varName)) {
return varName + "R";
@@ -119,7 +122,23 @@ public class NameGen {
return "r" + arg.getRegNum();
}
private static String makeNameForType(ArgType type) {
private String guessName(RegisterArg arg) {
SSAVar sVar = arg.getSVar();
if (sVar != null && sVar.getName() == null) {
RegisterArg assignArg = sVar.getAssign();
InsnNode assignInsn = assignArg.getParentInsn();
if (assignInsn != null) {
String name = makeNameFromInsn(assignInsn);
if (name != null && !NameMapper.isReserved(name)) {
assignArg.setName(name);
return name;
}
}
}
return makeNameForType(arg.getType());
}
private String makeNameForType(ArgType type) {
if (type.isPrimitive()) {
return makeNameForPrimitive(type);
} else if (type.isArray()) {
@@ -133,13 +152,13 @@ public class NameGen {
return type.getPrimitiveType().getShortName().toLowerCase();
}
private static String makeNameForObject(ArgType type) {
private String makeNameForObject(ArgType type) {
if (type.isObject()) {
String alias = getAliasForObject(type.getObject());
if (alias != null) {
return alias;
}
ClassInfo clsInfo = ClassInfo.fromType(type);
ClassInfo clsInfo = ClassInfo.fromType(mth.dex(), type);
String shortName = clsInfo.getShortName();
String vName = fromName(shortName);
if (vName != null) {
@@ -167,24 +186,11 @@ public class NameGen {
return null;
}
public static void guessName(RegisterArg arg) {
SSAVar sVar = arg.getSVar();
if (sVar == null || sVar.getName() != null) {
return;
}
RegisterArg assignArg = sVar.getAssign();
InsnNode assignInsn = assignArg.getParentInsn();
String name = makeNameFromInsn(assignInsn);
if (name != null && !NameMapper.isReserved(name)) {
assignArg.setName(name);
}
}
private static String getAliasForObject(String name) {
return OBJ_ALIAS.get(name);
}
private static String makeNameFromInsn(InsnNode insn) {
private String makeNameFromInsn(InsnNode insn) {
switch (insn.getType()) {
case INVOKE:
InvokeNode inv = (InvokeNode) insn;
@@ -4,15 +4,12 @@ import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.DexNode;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.io.File;
import java.util.Map;
import java.util.WeakHashMap;
public final class ClassInfo {
private static final Map<ArgType, ClassInfo> CLASSINFO_CACHE = new WeakHashMap<ArgType, ClassInfo>();
private final ArgType type;
private String pkg;
private String name;
@@ -20,11 +17,22 @@ public final class ClassInfo {
// for inner class not equals null
private ClassInfo parentClass;
private ClassInfo(ArgType type) {
assert type.isObject() : "Not class type: " + type;
private ClassInfo(DexNode dex, ArgType type) {
if (!type.isObject()) {
throw new JadxRuntimeException("Not class type: " + type);
}
this.type = type;
splitNames(true);
splitNames(dex, true);
}
public static ClassInfo fromType(DexNode dex, ArgType type) {
ClassInfo cls = dex.getInfoStorage().getCls(type);
if (cls != null) {
return cls;
}
cls = new ClassInfo(dex, type);
return dex.getInfoStorage().putCls(cls);
}
public static ClassInfo fromDex(DexNode dex, int clsIndex) {
@@ -35,27 +43,14 @@ public final class ClassInfo {
if (type.isArray()) {
type = ArgType.OBJECT;
}
return fromType(type);
return fromType(dex, type);
}
public static ClassInfo fromName(String clsName) {
return fromType(ArgType.object(clsName));
public static ClassInfo fromName(DexNode dex, String clsName) {
return fromType(dex, ArgType.object(clsName));
}
public static ClassInfo fromType(ArgType type) {
ClassInfo cls = CLASSINFO_CACHE.get(type);
if (cls == null) {
cls = new ClassInfo(type);
CLASSINFO_CACHE.put(type, cls);
}
return cls;
}
public static void clearCache() {
CLASSINFO_CACHE.clear();
}
private void splitNames(boolean canBeInner) {
private void splitNames(DexNode dex, boolean canBeInner) {
String fullObjectName = type.getObject();
assert fullObjectName.indexOf('/') == -1 : "Raw type: " + type;
@@ -73,7 +68,7 @@ public final class ClassInfo {
int sep = clsName.lastIndexOf('$');
if (canBeInner && sep > 0 && sep != clsName.length() - 1) {
String parClsName = pkg + "." + clsName.substring(0, sep);
parentClass = fromName(parClsName);
parentClass = fromName(dex, parClsName);
clsName = clsName.substring(sep + 1);
} else {
parentClass = null;
@@ -134,8 +129,8 @@ public final class ClassInfo {
return parentClass != null;
}
public void notInner() {
splitNames(false);
public void notInner(DexNode dex) {
splitNames(dex, false);
}
public ArgType getType() {
@@ -11,15 +11,20 @@ public class FieldInfo {
private final String name;
private final ArgType type;
public FieldInfo(ClassInfo declClass, String name, ArgType type) {
private FieldInfo(ClassInfo declClass, String name, ArgType type) {
this.declClass = declClass;
this.name = name;
this.type = type;
}
public static FieldInfo from(DexNode dex, ClassInfo declClass, String name, ArgType type) {
FieldInfo field = new FieldInfo(declClass, name, type);
return dex.getInfoStorage().getField(field);
}
public static FieldInfo fromDex(DexNode dex, int index) {
FieldId field = dex.getFieldId(index);
return new FieldInfo(
return from(dex,
ClassInfo.fromDex(dex, field.getDeclaringClassIndex()),
dex.getString(field.getNameIndex()),
dex.getType(field.getTypeIndex()));
@@ -0,0 +1,46 @@
package jadx.core.dex.info;
import jadx.core.dex.instructions.args.ArgType;
import java.util.HashMap;
import java.util.Map;
public class InfoStorage {
private final Map<ArgType, ClassInfo> classes = new HashMap<ArgType, ClassInfo>();
private final Map<Integer, MethodInfo> methods = new HashMap<Integer, MethodInfo>();
private final Map<FieldInfo, FieldInfo> fields = new HashMap<FieldInfo, FieldInfo>();
public ClassInfo getCls(ArgType type) {
return classes.get(type);
}
public ClassInfo putCls(ClassInfo cls) {
synchronized (classes) {
ClassInfo prev = classes.put(cls.getType(), cls);
return prev == null ? cls : prev;
}
}
public MethodInfo getMethod(int mtdId) {
return methods.get(mtdId);
}
public MethodInfo putMethod(int mthId, MethodInfo mth) {
synchronized (methods) {
MethodInfo prev = methods.put(mthId, mth);
return prev == null ? mth : prev;
}
}
public FieldInfo getField(FieldInfo field) {
synchronized (fields) {
FieldInfo f = fields.get(field);
if (f != null) {
return f;
}
fields.put(field, field);
return field;
}
}
}
@@ -40,7 +40,12 @@ public final class MethodInfo {
}
public static MethodInfo fromDex(DexNode dex, int mthIndex) {
return new MethodInfo(dex, mthIndex);
MethodInfo mth = dex.getInfoStorage().getMethod(mthIndex);
if (mth != null) {
return mth;
}
mth = new MethodInfo(dex, mthIndex);
return dex.getInfoStorage().putMethod(mthIndex, mth);
}
public String getName() {
@@ -191,12 +191,12 @@ public class ClassNode extends LineAttrNode implements ILoadable {
// parse class generic map
genericMap = sp.consumeGenericMap();
// parse super class signature
superClass = ClassInfo.fromType(sp.consumeType());
superClass = ClassInfo.fromType(dex, sp.consumeType());
// parse interfaces signatures
for (int i = 0; i < interfaces.size(); i++) {
ArgType type = sp.consumeType();
if (type != null) {
interfaces.set(i, ClassInfo.fromType(type));
interfaces.set(i, ClassInfo.fromType(dex, type));
} else {
break;
}
@@ -228,7 +228,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
try {
mth.load();
} catch (Exception e) {
LOG.error("Method load error:", e);
LOG.error("Method load error: {}", mth, e);
mth.addAttr(new JadxErrorAttr(e));
}
}
@@ -2,6 +2,7 @@ package jadx.core.dex.nodes;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.InfoStorage;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.utils.exceptions.DecodeException;
@@ -36,6 +37,8 @@ public class DexNode {
private final Map<Object, FieldNode> constFields = new HashMap<Object, FieldNode>();
private final InfoStorage infoStorage = new InfoStorage();
public DexNode(RootNode root, InputFile input) {
this.root = root;
this.dexBuf = input.getDexBuffer();
@@ -78,6 +81,10 @@ public class DexNode {
return constFields;
}
public InfoStorage getInfoStorage() {
return infoStorage;
}
// DexBuffer wrappers
public String getString(int index) {
@@ -9,7 +9,7 @@ public class ResRefField extends FieldNode {
public ResRefField(DexNode dex, String str) {
super(dex.root().getAppResClass(),
new FieldInfo(dex.root().getAppResClass().getClassInfo(), str, ArgType.INT),
FieldInfo.from(dex, dex.root().getAppResClass().getClassInfo(), str, ArgType.INT),
AccessFlags.ACC_PUBLIC);
}
}
@@ -117,7 +117,8 @@ public class RootNode {
appResClass = resCls;
return;
}
appResClass = new ClassNode(dexNodes.get(0), ClassInfo.fromName("R"));
DexNode firstDex = dexNodes.get(0);
appResClass = new ClassNode(firstDex, ClassInfo.fromName(firstDex, "R"));
}
private static void initClassPath(List<ClassNode> classes) throws IOException, DecodeException {
@@ -142,7 +143,7 @@ public class RootNode {
ClassNode parent = resolveClass(cls.getClassInfo().getParentClass());
if (parent == null) {
names.remove(cls.getFullName());
cls.getClassInfo().notInner();
cls.getClassInfo().notInner(cls.dex());
names.put(cls.getFullName(), cls);
} else {
parent.addInnerClass(cls);
@@ -50,7 +50,8 @@ public class ClassModifier extends AbstractVisitor {
// remove fields if it is synthetic and type is a outer class
for (FieldNode field : cls.getFields()) {
if (field.getAccessFlags().isSynthetic() && field.getType().isObject()) {
ClassNode fieldsCls = cls.dex().resolveClass(ClassInfo.fromType(field.getType()));
ClassInfo clsInfo = ClassInfo.fromType(cls.dex(), field.getType());
ClassNode fieldsCls = cls.dex().resolveClass(clsInfo);
ClassInfo parentClass = cls.getClassInfo().getParentClass();
if (fieldsCls != null
&& parentClass.equals(fieldsCls.getClassInfo())
@@ -62,7 +63,7 @@ public class ClassModifier extends AbstractVisitor {
}
}
if (found != 0) {
FieldInfo replace = new FieldInfo(parentClass, "this", parentClass.getType());
FieldInfo replace = FieldInfo.from(cls.dex(), parentClass, "this", parentClass.getType());
field.addAttr(new FieldReplaceAttr(replace, true));
field.add(AFlag.DONT_GENERATE);
}
@@ -1,6 +1,5 @@
package jadx.core.dex.visitors.regions;
import jadx.core.codegen.NameGen;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.DeclareVariablesAttr;
@@ -301,7 +300,6 @@ public class ProcessVariables extends AbstractVisitor {
return false;
}
parentInsn.add(AFlag.DECLARE_VAR);
processVar(arg);
return true;
}
@@ -312,11 +310,6 @@ public class ProcessVariables extends AbstractVisitor {
region.addAttr(dv);
}
dv.addVar(arg);
processVar(arg);
}
private static void processVar(RegisterArg arg) {
NameGen.guessName(arg);
}
private static int calculateOrder(IContainer container, Map<IContainer, Integer> regionsOrder,