Skip to content

Commit

Permalink
refactor: allow store unresolved fields in ConstStorage (#2119)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Mar 30, 2024
1 parent 6b4976c commit b865c9c
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 66 deletions.
60 changes: 30 additions & 30 deletions jadx-core/src/main/java/jadx/core/dex/info/ConstStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -18,31 +16,32 @@
import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.RootNode;

public class ConstStorage {

private static final class ValueStorage {
private final Map<Object, FieldNode> values = new ConcurrentHashMap<>();
private final Map<Object, IFieldInfoRef> values = new ConcurrentHashMap<>();
private final Set<Object> duplicates = new HashSet<>();

public Map<Object, FieldNode> getValues() {
public Map<Object, IFieldInfoRef> getValues() {
return values;
}

public FieldNode get(Object key) {
public IFieldInfoRef get(Object key) {
return values.get(key);
}

/**
* @return true if this value is duplicated
*/
public boolean put(Object value, FieldNode fld) {
public boolean put(Object value, IFieldInfoRef fld) {
if (duplicates.contains(value)) {
values.remove(value);
return true;
}
FieldNode prev = values.put(value, fld);
IFieldInfoRef prev = values.put(value, fld);
if (prev != null) {
values.remove(value);
duplicates.add(value);
Expand All @@ -56,14 +55,13 @@ public boolean contains(Object value) {
}

void removeForCls(ClassNode cls) {
Iterator<Entry<Object, FieldNode>> it = values.entrySet().iterator();
while (it.hasNext()) {
Entry<Object, FieldNode> entry = it.next();
FieldNode field = entry.getValue();
if (field.getParentClass().equals(cls)) {
it.remove();
values.entrySet().removeIf(entry -> {
IFieldInfoRef field = entry.getValue();
if (field instanceof FieldNode) {
return ((FieldNode) field).getParentClass().equals(cls);
}
}
return false;
});
}
}

Expand All @@ -77,18 +75,30 @@ public ConstStorage(JadxArgs args) {
this.replaceEnabled = args.isReplaceConsts();
}

public void processConstFields(ClassNode cls, List<FieldNode> staticFields) {
public void processConstFields(List<FieldNode> staticFields) {
if (!replaceEnabled || staticFields.isEmpty()) {
return;
}
for (FieldNode f : staticFields) {
Object value = getFieldConstValue(f);
if (value != null) {
addConstField(cls, f, value, f.getAccessFlags().isPublic());
addConstField(f, value, f.getAccessFlags().isPublic());
}
}
}

public void addConstField(FieldNode fld, Object value, boolean isPublic) {
if (isPublic) {
addGlobalConstField(fld, value);
} else {
getClsValues(fld.getParentClass()).put(value, fld);
}
}

public void addGlobalConstField(IFieldInfoRef fld, Object value) {
globalValues.put(value, fld);
}

public static @Nullable Object getFieldConstValue(FieldNode fld) {
AccessInfo accFlags = fld.getAccessFlags();
if (accFlags.isStatic() && accFlags.isFinal()) {
Expand All @@ -105,20 +115,11 @@ public void removeForClass(ClassNode cls) {
globalValues.removeForCls(cls);
}

private void addConstField(ClassNode cls, FieldNode fld, Object value, boolean isPublic) {
if (isPublic) {
globalValues.put(value, fld);
} else {
getClsValues(cls).put(value, fld);
}
}

private ValueStorage getClsValues(ClassNode cls) {
return classes.computeIfAbsent(cls, c -> new ValueStorage());
}

@Nullable
public FieldNode getConstField(ClassNode cls, Object value, boolean searchGlobal) {
public @Nullable IFieldInfoRef getConstField(ClassNode cls, Object value, boolean searchGlobal) {
if (!replaceEnabled) {
return null;
}
Expand All @@ -137,7 +138,7 @@ public FieldNode getConstField(ClassNode cls, Object value, boolean searchGlobal
while (current != null) {
ValueStorage classValues = classes.get(current);
if (classValues != null) {
FieldNode field = classValues.get(value);
IFieldInfoRef field = classValues.get(value);
if (field != null) {
if (foundInGlobal) {
return null;
Expand Down Expand Up @@ -182,8 +183,7 @@ private FieldNode getResourceField(Integer value, RootNode root) {
return null;
}

@Nullable
public FieldNode getConstFieldByLiteralArg(ClassNode cls, LiteralArg arg) {
public @Nullable IFieldInfoRef getConstFieldByLiteralArg(ClassNode cls, LiteralArg arg) {
if (!replaceEnabled) {
return null;
}
Expand Down Expand Up @@ -225,7 +225,7 @@ public Map<Integer, String> getResourcesNames() {
return resourcesNames;
}

public Map<Object, FieldNode> getGlobalConstFields() {
public Map<Object, IFieldInfoRef> getGlobalConstFields() {
return globalValues.getValues();
}

Expand Down
8 changes: 7 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import jadx.api.plugins.input.data.IFieldRef;
import jadx.core.codegen.TypeGen;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.RootNode;

public final class FieldInfo {
public final class FieldInfo implements IFieldInfoRef {

private final ClassInfo declClass;
private final String name;
Expand Down Expand Up @@ -76,6 +77,11 @@ public boolean equalsNameAndType(FieldInfo other) {
return name.equals(other.name) && type.equals(other.type);
}

@Override
public FieldInfo getFieldInfo() {
return this;
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
10 changes: 4 additions & 6 deletions jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ private void initStaticValues(List<FieldNode> fields) {
}
try {
// process const fields
root().getConstValues().processConstFields(this, staticFields);
root().getConstValues().processConstFields(staticFields);
} catch (Exception e) {
this.addWarnComment("Failed to load initial values for static fields", e);
}
Expand Down Expand Up @@ -513,17 +513,15 @@ public void addField(FieldNode fld) {
fields.add(fld);
}

public FieldNode getConstField(Object obj) {
public @Nullable IFieldInfoRef getConstField(Object obj) {
return getConstField(obj, true);
}

@Nullable
public FieldNode getConstField(Object obj, boolean searchGlobal) {
public @Nullable IFieldInfoRef getConstField(Object obj, boolean searchGlobal) {
return root().getConstValues().getConstField(this, obj, searchGlobal);
}

@Nullable
public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
public @Nullable IFieldInfoRef getConstFieldByLiteralArg(LiteralArg arg) {
return root().getConstValues().getConstFieldByLiteralArg(this, arg);
}

Expand Down
3 changes: 2 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/nodes/FieldNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.utils.ListUtils;

public class FieldNode extends NotificationAttrNode implements ICodeNode {
public class FieldNode extends NotificationAttrNode implements ICodeNode, IFieldInfoRef {

private final ClassNode parentClass;
private final FieldInfo fieldInfo;
Expand Down Expand Up @@ -46,6 +46,7 @@ public void updateType(ArgType type) {
this.type = type;
}

@Override
public FieldInfo getFieldInfo() {
return fieldInfo;
}
Expand Down
10 changes: 10 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/IFieldInfoRef.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package jadx.core.dex.nodes;

import jadx.core.dex.info.FieldInfo;

/**
* Common interface for FieldInfo and FieldNode
*/
public interface IFieldInfoRef {
FieldInfo getFieldInfo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import jadx.core.dex.instructions.args.SSAVar;
import jadx.core.dex.instructions.mods.ConstructorInsn;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.finaly.MarkFinallyVisitor;
Expand Down Expand Up @@ -82,15 +82,15 @@ private static void checkInsn(MethodNode mth, InsnNode insn, List<InsnNode> toRe
}
case CONST_STR: {
String s = ((ConstStringNode) insn).getString();
FieldNode f = mth.getParentClass().getConstField(s);
IFieldInfoRef f = mth.getParentClass().getConstField(s);
if (f == null) {
InsnNode copy = insn.copyWithoutResult();
constArg = InsnArg.wrapArg(copy);
} else {
InsnNode constGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
constArg = InsnArg.wrapArg(constGet);
constArg.setType(ArgType.STRING);
onSuccess = () -> f.addUseIn(mth);
onSuccess = () -> ModVisitor.addFieldUsage(f, mth);
}
break;
}
Expand Down Expand Up @@ -251,7 +251,7 @@ private static boolean replaceArg(MethodNode mth, RegisterArg arg, InsnArg const
return false;
}
// arg replaced, made some optimizations
FieldNode fieldNode = null;
IFieldInfoRef fieldNode = null;
ArgType litArgType = litArg.getType();
if (litArgType.isTypeKnown()) {
fieldNode = mth.getParentClass().getConstFieldByLiteralArg(litArg);
Expand All @@ -261,7 +261,7 @@ private static boolean replaceArg(MethodNode mth, RegisterArg arg, InsnArg const
if (fieldNode != null) {
IndexInsnNode sgetInsn = new IndexInsnNode(InsnType.SGET, fieldNode.getFieldInfo(), 0);
if (litArg.wrapInstruction(mth, sgetInsn) != null) {
fieldNode.addUseIn(mth);
ModVisitor.addFieldUsage(fieldNode, mth);
}
} else {
addExplicitCast(useInsn, litArg);
Expand Down
25 changes: 16 additions & 9 deletions jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.IMethodDetails;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
Expand Down Expand Up @@ -239,10 +240,10 @@ private static void replaceConstKeys(MethodNode mth, ClassNode parentClass, Swit
int[] keys = insn.getKeys();
int len = keys.length;
for (int k = 0; k < len; k++) {
FieldNode f = parentClass.getConstField(keys[k]);
IFieldInfoRef f = parentClass.getConstField(keys[k]);
if (f != null) {
insn.modifyKey(k, f);
f.addUseIn(mth);
addFieldUsage(f, mth);
}
}
}
Expand Down Expand Up @@ -313,15 +314,15 @@ private EncodedValue replaceConstValue(ClassNode parentCls, EncodedValue encoded
}
return new EncodedValue(EncodedType.ENCODED_ARRAY, listVal);
}
FieldNode constField = parentCls.getConstField(encodedValue.getValue());
IFieldInfoRef constField = parentCls.getConstField(encodedValue.getValue());
if (constField != null) {
return new EncodedValue(EncodedType.ENCODED_FIELD, constField.getFieldInfo());
}
return encodedValue;
}

private static void replaceConst(MethodNode mth, ClassNode parentClass, BlockNode block, int i, InsnNode insn) {
FieldNode f;
IFieldInfoRef f;
if (insn.getType() == InsnType.CONST_STR) {
String s = ((ConstStringNode) insn).getString();
f = parentClass.getConstField(s);
Expand All @@ -335,7 +336,7 @@ private static void replaceConst(MethodNode mth, ClassNode parentClass, BlockNod
InsnNode inode = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
inode.setResult(insn.getResult());
replaceInsn(mth, block, i, inode);
f.addUseIn(mth);
addFieldUsage(f, mth);
}
}

Expand All @@ -345,11 +346,11 @@ private static void processArith(MethodNode mth, ClassNode parentClass, ArithNod
}
InsnArg litArg = arithNode.getArg(1);
if (litArg.isLiteral()) {
FieldNode f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg);
IFieldInfoRef f = parentClass.getConstFieldByLiteralArg((LiteralArg) litArg);
if (f != null) {
InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
if (arithNode.replaceArg(litArg, InsnArg.wrapArg(fGet))) {
f.addUseIn(mth);
addFieldUsage(f, mth);
}
}
}
Expand Down Expand Up @@ -566,11 +567,11 @@ private static InsnNode makeFilledArrayInsn(MethodNode mth, NewArrayNode newArra
InsnNode filledArr = new FilledNewArrayNode(elType, list.size());
filledArr.setResult(newArrayNode.getResult().duplicate());
for (LiteralArg arg : list) {
FieldNode f = mth.getParentClass().getConstFieldByLiteralArg(arg);
IFieldInfoRef f = mth.getParentClass().getConstFieldByLiteralArg(arg);
if (f != null) {
InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
filledArr.addArg(InsnArg.wrapArg(fGet));
f.addUseIn(mth);
addFieldUsage(f, mth);
} else {
filledArr.addArg(arg.duplicate());
}
Expand Down Expand Up @@ -607,4 +608,10 @@ private static void processMoveException(MethodNode mth, BlockNode block, InsnNo
}
block.copyAttributeFrom(insn, AType.CODE_COMMENTS); // save comment
}

public static void addFieldUsage(IFieldInfoRef fieldData, MethodNode mth) {
if (fieldData instanceof FieldNode) {
((FieldNode) fieldData).addUseIn(mth);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
Expand Down Expand Up @@ -167,11 +167,11 @@ private static boolean processNewArray(MethodNode mth,

private static InsnArg replaceConstInArg(MethodNode mth, InsnArg valueArg) {
if (valueArg.isLiteral()) {
FieldNode f = mth.getParentClass().getConstFieldByLiteralArg((LiteralArg) valueArg);
IFieldInfoRef f = mth.getParentClass().getConstFieldByLiteralArg((LiteralArg) valueArg);
if (f != null) {
InsnNode fGet = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
InsnArg arg = InsnArg.wrapArg(fGet);
f.addUseIn(mth);
ModVisitor.addFieldUsage(f, mth);
return arg;
}
}
Expand Down

0 comments on commit b865c9c

Please sign in to comment.