refactor: add method info caching to speed up initial loading
This commit is contained in:
@@ -11,6 +11,8 @@ public class InfoStorage {
|
||||
private final Map<FieldInfo, FieldInfo> fields = new HashMap<>();
|
||||
// use only one MethodInfo instance
|
||||
private final Map<MethodInfo, MethodInfo> uniqueMethods = new HashMap<>();
|
||||
// can contain same method with different ids (from different dex files)
|
||||
private final Map<Integer, MethodInfo> methods = new HashMap<>();
|
||||
|
||||
public ClassInfo getCls(ArgType type) {
|
||||
return classes.get(type);
|
||||
@@ -23,6 +25,18 @@ public class InfoStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public MethodInfo getByUniqId(int id) {
|
||||
synchronized (methods) {
|
||||
return methods.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void putByUniqId(int id, MethodInfo mth) {
|
||||
synchronized (methods) {
|
||||
methods.put(id, mth);
|
||||
}
|
||||
}
|
||||
|
||||
public MethodInfo putMethod(MethodInfo newMth) {
|
||||
synchronized (uniqueMethods) {
|
||||
MethodInfo prev = uniqueMethods.get(newMth);
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.IMethodData;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.core.codegen.TypeGen;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
@@ -31,18 +31,27 @@ public final class MethodInfo implements Comparable<MethodInfo> {
|
||||
this.shortId = makeShortId(name, argTypes, retType);
|
||||
}
|
||||
|
||||
public static MethodInfo fromData(RootNode root, IMethodData methodData) {
|
||||
ArgType parentClsType = ArgType.parse(methodData.getParentClassType());
|
||||
public static MethodInfo fromRef(RootNode root, IMethodRef methodRef) {
|
||||
InfoStorage infoStorage = root.getInfoStorage();
|
||||
int uniqId = methodRef.getUniqId();
|
||||
MethodInfo prevMth = infoStorage.getByUniqId(uniqId);
|
||||
if (prevMth != null) {
|
||||
return prevMth;
|
||||
}
|
||||
methodRef.load();
|
||||
ArgType parentClsType = ArgType.parse(methodRef.getParentClassType());
|
||||
ClassInfo parentClass = ClassInfo.fromType(root, parentClsType);
|
||||
ArgType returnType = ArgType.parse(methodData.getReturnType());
|
||||
List<ArgType> args = Utils.collectionMap(methodData.getArgTypes(), ArgType::parse);
|
||||
MethodInfo newMth = new MethodInfo(parentClass, methodData.getName(), args, returnType);
|
||||
return root.getInfoStorage().putMethod(newMth);
|
||||
ArgType returnType = ArgType.parse(methodRef.getReturnType());
|
||||
List<ArgType> args = Utils.collectionMap(methodRef.getArgTypes(), ArgType::parse);
|
||||
MethodInfo newMth = new MethodInfo(parentClass, methodRef.getName(), args, returnType);
|
||||
MethodInfo uniqMth = infoStorage.putMethod(newMth);
|
||||
infoStorage.putByUniqId(uniqId, uniqMth);
|
||||
return uniqMth;
|
||||
}
|
||||
|
||||
public static MethodInfo fromDetails(RootNode rootNode, ClassInfo declClass, String name, List<ArgType> args, ArgType retType) {
|
||||
public static MethodInfo fromDetails(RootNode root, ClassInfo declClass, String name, List<ArgType> args, ArgType retType) {
|
||||
MethodInfo newMth = new MethodInfo(declClass, name, args, retType);
|
||||
return rootNode.getInfoStorage().putMethod(newMth);
|
||||
return root.getInfoStorage().putMethod(newMth);
|
||||
}
|
||||
|
||||
public String makeSignature(boolean includeRetType) {
|
||||
|
||||
@@ -521,8 +521,8 @@ public class InsnDecoder {
|
||||
}
|
||||
|
||||
private InsnNode invoke(InsnData insn, InvokeType type, boolean isRange) {
|
||||
MethodInfo mth = MethodInfo.fromData(root, insn.getIndexAsMethod());
|
||||
return new InvokeNode(mth, insn, type, isRange);
|
||||
MethodInfo mthInfo = MethodInfo.fromRef(root, insn.getIndexAsMethod());
|
||||
return new InvokeNode(mthInfo, insn, type, isRange);
|
||||
}
|
||||
|
||||
private InsnNode arrayGet(InsnData insn, ArgType argType) {
|
||||
|
||||
@@ -81,8 +81,8 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
public ClassNode(RootNode root, IClassData cls) {
|
||||
this.root = root;
|
||||
this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType()));
|
||||
initialLoad(cls);
|
||||
this.clsData = cls.copy();
|
||||
initialLoad(clsData);
|
||||
}
|
||||
|
||||
private void initialLoad(IClassData cls) {
|
||||
|
||||
@@ -82,8 +82,8 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
return methodNode;
|
||||
}
|
||||
|
||||
public MethodNode(ClassNode classNode, IMethodData mthData) {
|
||||
this.mthInfo = MethodInfo.fromData(classNode.root(), mthData);
|
||||
private MethodNode(ClassNode classNode, IMethodData mthData) {
|
||||
this.mthInfo = MethodInfo.fromRef(classNode.root(), mthData.getMethodRef());
|
||||
this.parentClass = classNode;
|
||||
this.accFlags = new AccessInfo(mthData.getAccessFlags(), AFType.METHOD);
|
||||
this.methodIsVirtual = !mthData.isDirect();
|
||||
|
||||
@@ -104,7 +104,7 @@ public class UsageInfoVisitor extends AbstractVisitor {
|
||||
|
||||
case METHOD_REF:
|
||||
insnData.decode();
|
||||
MethodNode methodNode = root.resolveMethod(MethodInfo.fromData(root, insnData.getIndexAsMethod()));
|
||||
MethodNode methodNode = root.resolveMethod(MethodInfo.fromRef(root, insnData.getIndexAsMethod()));
|
||||
if (methodNode != null) {
|
||||
usageInfo.methodUse(mth, methodNode);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user