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;
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(", ");
}
......
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) {"));
......
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