Search in sources :

Example 6 with FilledNewArrayNode

use of jadx.core.dex.instructions.FilledNewArrayNode in project jadx by skylot.

the class ReSugarCode method processNewArray.

/**
 * Replace new-array and sequence of array-put to new filled-array instruction.
 */
private static boolean processNewArray(MethodNode mth, NewArrayNode newArrayInsn, List<InsnNode> instructions, InsnRemover remover) {
    Object arrayLenConst = InsnUtils.getConstValueByArg(mth.root(), newArrayInsn.getArg(0));
    if (!(arrayLenConst instanceof LiteralArg)) {
        return false;
    }
    int len = (int) ((LiteralArg) arrayLenConst).getLiteral();
    if (len == 0) {
        return false;
    }
    ArgType arrType = newArrayInsn.getArrayType();
    ArgType elemType = arrType.getArrayElement();
    boolean allowMissingKeys = arrType.getArrayDimension() == 1 && elemType.isPrimitive();
    int minLen = allowMissingKeys ? len / 2 : len;
    RegisterArg arrArg = newArrayInsn.getResult();
    List<RegisterArg> useList = arrArg.getSVar().getUseList();
    if (useList.size() < minLen) {
        return false;
    }
    // quick check if APUT is used
    boolean foundPut = false;
    for (RegisterArg registerArg : useList) {
        InsnNode parentInsn = registerArg.getParentInsn();
        if (parentInsn != null && parentInsn.getType() == InsnType.APUT) {
            foundPut = true;
            break;
        }
    }
    if (!foundPut) {
        return false;
    }
    // collect put instructions sorted by array index
    SortedMap<Long, InsnNode> arrPuts = new TreeMap<>();
    for (RegisterArg registerArg : useList) {
        InsnNode parentInsn = registerArg.getParentInsn();
        if (parentInsn == null || parentInsn.getType() != InsnType.APUT) {
            continue;
        }
        if (!arrArg.sameRegAndSVar(parentInsn.getArg(0))) {
            return false;
        }
        Object constVal = InsnUtils.getConstValueByArg(mth.root(), parentInsn.getArg(1));
        if (!(constVal instanceof LiteralArg)) {
            return false;
        }
        long index = ((LiteralArg) constVal).getLiteral();
        if (index >= len) {
            return false;
        }
        if (arrPuts.containsKey(index)) {
            // stop on index rewrite
            break;
        }
        arrPuts.put(index, parentInsn);
    }
    if (arrPuts.size() < minLen) {
        return false;
    }
    // expect all puts to be in same block
    if (!new HashSet<>(instructions).containsAll(arrPuts.values())) {
        return false;
    }
    // checks complete, apply
    InsnNode filledArr = new FilledNewArrayNode(elemType, len);
    filledArr.setResult(arrArg.duplicate());
    long prevIndex = -1;
    for (Map.Entry<Long, InsnNode> entry : arrPuts.entrySet()) {
        long index = entry.getKey();
        if (index != prevIndex) {
            // use zero for missing keys
            for (long i = prevIndex + 1; i < index; i++) {
                filledArr.addArg(InsnArg.lit(0, elemType));
            }
        }
        InsnNode put = entry.getValue();
        filledArr.addArg(replaceConstInArg(mth, put.getArg(2)));
        remover.addAndUnbind(put);
        prevIndex = index;
    }
    remover.addAndUnbind(newArrayInsn);
    InsnNode lastPut = arrPuts.get(arrPuts.lastKey());
    int replaceIndex = InsnList.getIndex(instructions, lastPut);
    instructions.set(replaceIndex, filledArr);
    return true;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) FilledNewArrayNode(jadx.core.dex.instructions.FilledNewArrayNode) LiteralArg(jadx.core.dex.instructions.args.LiteralArg) TreeMap(java.util.TreeMap) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Map(java.util.Map) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap) HashSet(java.util.HashSet)

Aggregations

FilledNewArrayNode (jadx.core.dex.instructions.FilledNewArrayNode)6 ArgType (jadx.core.dex.instructions.args.ArgType)6 InsnNode (jadx.core.dex.nodes.InsnNode)6 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)5 LiteralArg (jadx.core.dex.instructions.args.LiteralArg)4 JadxRuntimeException (jadx.core.utils.exceptions.JadxRuntimeException)3 InsnArg (jadx.core.dex.instructions.args.InsnArg)2 FieldNode (jadx.core.dex.nodes.FieldNode)2 ConstStringNode (jadx.core.dex.instructions.ConstStringNode)1 FillArrayInsn (jadx.core.dex.instructions.FillArrayInsn)1 InvokeNode (jadx.core.dex.instructions.InvokeNode)1 NewArrayNode (jadx.core.dex.instructions.NewArrayNode)1 SwitchInsn (jadx.core.dex.instructions.SwitchInsn)1 InsnWrapArg (jadx.core.dex.instructions.args.InsnWrapArg)1 RegisterArg (jadx.core.dex.instructions.args.RegisterArg)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 SortedMap (java.util.SortedMap)1 TreeMap (java.util.TreeMap)1