diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 4ca555914..0d6e9be84 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -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; diff --git a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java index ecf5d2be8..663b29c0a 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java @@ -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()); diff --git a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java index 7849b447b..6771c7446 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java @@ -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() { diff --git a/jadx-core/src/main/java/jadx/core/codegen/NameGen.java b/jadx-core/src/main/java/jadx/core/codegen/NameGen.java index e90e188e3..7a4e7b7c9 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/NameGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/NameGen.java @@ -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 OBJ_ALIAS; private final Set varNames = new HashSet(); + 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; diff --git a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java index 65417f618..25bf74c47 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/ClassInfo.java @@ -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 CLASSINFO_CACHE = new WeakHashMap(); - 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() { diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java index 805a16e6a..b98d7a716 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java @@ -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())); diff --git a/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java b/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java new file mode 100644 index 000000000..e8c18e34b --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java @@ -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 classes = new HashMap(); + private final Map methods = new HashMap(); + private final Map fields = new HashMap(); + + 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; + } + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java index fec1b5623..6f93493e7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java @@ -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() { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index 464cbc30d..db0c1d6ae 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -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)); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java index 24db0a39f..41fe3a9a3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java @@ -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 constFields = new HashMap(); + 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) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java index e741a2879..d77ef0a89 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ResRefField.java @@ -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); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index 63d7fe6d9..5fba46600 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -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 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); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java index 291bcac9c..b1ac00e62 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java @@ -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); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java index 9ce2058be..eed93c967 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java @@ -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 regionsOrder,