Commit 3bdda551 authored by Skylot's avatar Skylot

core: inline filled array creation

parent b657b0fb
...@@ -14,6 +14,7 @@ import jadx.core.dex.visitors.IDexTreeVisitor; ...@@ -14,6 +14,7 @@ import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.dex.visitors.MethodInlineVisitor; import jadx.core.dex.visitors.MethodInlineVisitor;
import jadx.core.dex.visitors.ModVisitor; import jadx.core.dex.visitors.ModVisitor;
import jadx.core.dex.visitors.PrepareForCodeGen; import jadx.core.dex.visitors.PrepareForCodeGen;
import jadx.core.dex.visitors.ReSugarCode;
import jadx.core.dex.visitors.SimplifyVisitor; import jadx.core.dex.visitors.SimplifyVisitor;
import jadx.core.dex.visitors.regions.CheckRegions; import jadx.core.dex.visitors.regions.CheckRegions;
import jadx.core.dex.visitors.regions.IfRegionVisitor; import jadx.core.dex.visitors.regions.IfRegionVisitor;
...@@ -69,6 +70,7 @@ public class Jadx { ...@@ -69,6 +70,7 @@ public class Jadx {
passes.add(new EnumVisitor()); passes.add(new EnumVisitor());
passes.add(new CodeShrinker()); passes.add(new CodeShrinker());
passes.add(new ReSugarCode());
if (args.isCFGOutput()) { if (args.isCFGOutput()) {
passes.add(new DotGraphVisitor(outDir, false)); passes.add(new DotGraphVisitor(outDir, false));
} }
......
...@@ -496,7 +496,7 @@ public class InsnGen { ...@@ -496,7 +496,7 @@ public class InsnGen {
useType(code, insn.getResult().getType()); useType(code, insn.getResult().getType());
code.add('{'); code.add('{');
for (int i = 0; i < c; i++) { for (int i = 0; i < c; i++) {
addArg(code, insn.getArg(i)); addArg(code, insn.getArg(i), false);
if (i + 1 < c) { if (i + 1 < c) {
code.add(", "); code.add(", ");
} }
......
package jadx.core.dex.visitors;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.InstructionRemover;
import jadx.core.utils.exceptions.JadxException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReSugarCode extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(ReSugarCode.class);
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode()) {
return;
}
InstructionRemover remover = new InstructionRemover(mth);
for (BlockNode block : mth.getBasicBlocks()) {
remover.setBlock(block);
List<InsnNode> instructions = block.getInstructions();
int size = instructions.size();
for (int i = 0; i < size; i++) {
InsnNode replacedInsn = process(mth, instructions, i, remover);
if (replacedInsn != null) {
instructions.set(i, replacedInsn);
}
}
remover.perform();
}
}
private static InsnNode process(MethodNode mth, List<InsnNode> instructions, int i, InstructionRemover remover) {
InsnNode insn = instructions.get(i);
switch (insn.getType()) {
case NEW_ARRAY:
return processNewArray(mth, instructions, i, remover);
default:
return null;
}
}
/**
* Replace new array and sequence of array-put to new filled-array instruction.
*/
private static InsnNode processNewArray(MethodNode mth, List<InsnNode> instructions, int i, InstructionRemover remover) {
InsnNode insn = instructions.get(i);
InsnArg arg = insn.getArg(0);
if (!arg.isLiteral()) {
return null;
}
int len = (int) ((LiteralArg) arg).getLiteral();
int size = instructions.size();
if (len <= 0 || i + len >= size || instructions.get(i + len).getType() != InsnType.APUT) {
return null;
}
InsnNode filledArr = new InsnNode(InsnType.FILLED_NEW_ARRAY, len);
filledArr.setResult(insn.getResult());
for (int j = 0; j < len; j++) {
InsnNode put = instructions.get(i + 1 + j);
if (put.getType() != InsnType.APUT) {
LOG.debug("Not a APUT in expected new filled array: {}, method: {}", put, mth);
return null;
}
filledArr.addArg(put.getArg(2));
remover.add(put);
}
return filledArr;
}
}
...@@ -26,17 +26,23 @@ public class InstructionRemover { ...@@ -26,17 +26,23 @@ public class InstructionRemover {
private static final Logger LOG = LoggerFactory.getLogger(InstructionRemover.class); private static final Logger LOG = LoggerFactory.getLogger(InstructionRemover.class);
private final MethodNode mth; private final MethodNode mth;
private final List<InsnNode> insns;
private final List<InsnNode> toRemove; private final List<InsnNode> toRemove;
private List<InsnNode> instrList;
public InstructionRemover(MethodNode mth, BlockNode block) { public InstructionRemover(MethodNode mth) {
this(mth, block.getInstructions()); this(mth, null);
} }
public InstructionRemover(MethodNode mth, List<InsnNode> instructions) { public InstructionRemover(MethodNode mth, BlockNode block) {
this.mth = mth; this.mth = mth;
this.insns = instructions;
this.toRemove = new ArrayList<InsnNode>(); this.toRemove = new ArrayList<InsnNode>();
if (block != null) {
this.instrList = block.getInstructions();
}
}
public void setBlock(BlockNode block) {
this.instrList = block.getInstructions();
} }
public void add(InsnNode insn) { public void add(InsnNode insn) {
...@@ -47,7 +53,7 @@ public class InstructionRemover { ...@@ -47,7 +53,7 @@ public class InstructionRemover {
if (toRemove.isEmpty()) { if (toRemove.isEmpty()) {
return; return;
} }
removeAll(mth, insns, toRemove); removeAll(mth, instrList, toRemove);
toRemove.clear(); toRemove.clear();
} }
...@@ -84,7 +90,7 @@ public class InstructionRemover { ...@@ -84,7 +90,7 @@ public class InstructionRemover {
} }
} }
// Don't use 'insns.removeAll(toRemove)' because it will remove instructions by content // Don't use 'instrList.removeAll(toRemove)' because it will remove instructions by content
// and here can be several instructions with same content // and here can be several instructions with same content
private static void removeAll(MethodNode mth, List<InsnNode> insns, List<InsnNode> toRemove) { private static void removeAll(MethodNode mth, List<InsnNode> insns, List<InsnNode> toRemove) {
for (InsnNode rem : toRemove) { for (InsnNode rem : toRemove) {
......
...@@ -25,7 +25,7 @@ public class TestFloatValue extends InternalJadxTest { ...@@ -25,7 +25,7 @@ public class TestFloatValue extends InternalJadxTest {
String code = cls.getCode().toString(); String code = cls.getCode().toString();
assertThat(code, not(containsString("1073741824"))); assertThat(code, not(containsString("1073741824")));
assertThat(code, containsString("0.55f;")); assertThat(code, containsString("0.55f"));
assertThat(code, containsString("fa[0] = fa[0] / 2.0f;")); assertThat(code, containsString("fa[0] = fa[0] / 2.0f;"));
} }
} }
...@@ -39,7 +39,7 @@ public class TestVarArgAnnotation extends InternalJadxTest { ...@@ -39,7 +39,7 @@ public class TestVarArgAnnotation extends InternalJadxTest {
// TODO: // TODO:
assertThat(code, containsString("test1(new int[]{1, 2});")); assertThat(code, containsString("test1(new int[]{1, 2});"));
assertThat(code, containsString("test2(3, objArr);")); assertThat(code, containsString("test2(3, new Object[]{\"1\", Integer.valueOf(7)});"));
// negative case // negative case
assertThat(code, containsString("void test3(int[] a) {")); assertThat(code, containsString("void test3(int[] a) {"));
......
package jadx.tests.internal.arrays;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
public class TestArrayFill extends InternalJadxTest {
public static class TestCls {
public String[] method() {
return new String[]{"1", "2", "3"};
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsString("return new String[]{\"1\", \"2\", \"3\"};"));
}
}
package jadx.tests.internal.arrays;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
public class TestArrayFill2 extends InternalJadxTest {
public static class TestCls {
public int[] test(int a) {
return new int[]{1, a + 1, 2};
}
public int[] test2(int a) {
return new int[]{1, a++, a * 2};
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsString("return new int[]{1, a + 1, 2};"));
// TODO
// assertThat(code, containsString("return new int[]{1, a++, a * 2};"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment