core: refactor info classes for store only one instance
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user