core: inline filled array creation
This commit is contained in:
@@ -14,6 +14,7 @@ import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
import jadx.core.dex.visitors.MethodInlineVisitor;
|
||||
import jadx.core.dex.visitors.ModVisitor;
|
||||
import jadx.core.dex.visitors.PrepareForCodeGen;
|
||||
import jadx.core.dex.visitors.ReSugarCode;
|
||||
import jadx.core.dex.visitors.SimplifyVisitor;
|
||||
import jadx.core.dex.visitors.regions.CheckRegions;
|
||||
import jadx.core.dex.visitors.regions.IfRegionVisitor;
|
||||
@@ -69,6 +70,7 @@ public class Jadx {
|
||||
passes.add(new EnumVisitor());
|
||||
|
||||
passes.add(new CodeShrinker());
|
||||
passes.add(new ReSugarCode());
|
||||
if (args.isCFGOutput()) {
|
||||
passes.add(new DotGraphVisitor(outDir, false));
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ public class InsnGen {
|
||||
useType(code, insn.getResult().getType());
|
||||
code.add('{');
|
||||
for (int i = 0; i < c; i++) {
|
||||
addArg(code, insn.getArg(i));
|
||||
addArg(code, insn.getArg(i), false);
|
||||
if (i + 1 < c) {
|
||||
code.add(", ");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
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 {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InstructionRemover.class);
|
||||
|
||||
private final MethodNode mth;
|
||||
private final List<InsnNode> insns;
|
||||
private final List<InsnNode> toRemove;
|
||||
private List<InsnNode> instrList;
|
||||
|
||||
public InstructionRemover(MethodNode mth, BlockNode block) {
|
||||
this(mth, block.getInstructions());
|
||||
public InstructionRemover(MethodNode mth) {
|
||||
this(mth, null);
|
||||
}
|
||||
|
||||
public InstructionRemover(MethodNode mth, List<InsnNode> instructions) {
|
||||
public InstructionRemover(MethodNode mth, BlockNode block) {
|
||||
this.mth = mth;
|
||||
this.insns = instructions;
|
||||
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) {
|
||||
@@ -47,7 +53,7 @@ public class InstructionRemover {
|
||||
if (toRemove.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
removeAll(mth, insns, toRemove);
|
||||
removeAll(mth, instrList, toRemove);
|
||||
toRemove.clear();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
private static void removeAll(MethodNode mth, List<InsnNode> insns, List<InsnNode> toRemove) {
|
||||
for (InsnNode rem : toRemove) {
|
||||
|
||||
@@ -25,7 +25,7 @@ public class TestFloatValue extends InternalJadxTest {
|
||||
String code = cls.getCode().toString();
|
||||
|
||||
assertThat(code, not(containsString("1073741824")));
|
||||
assertThat(code, containsString("0.55f;"));
|
||||
assertThat(code, containsString("0.55f"));
|
||||
assertThat(code, containsString("fa[0] = fa[0] / 2.0f;"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TestVarArgAnnotation extends InternalJadxTest {
|
||||
|
||||
// TODO:
|
||||
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
|
||||
assertThat(code, containsString("void test3(int[] a) {"));
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
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\"};"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
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};"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user