core: remove not needed casts

This commit is contained in:
Skylot
2013-09-14 17:38:38 +04:00
parent cde8d72510
commit 4edfffae27
8 changed files with 181 additions and 20 deletions
@@ -215,11 +215,15 @@ public class InsnGen {
case CHECK_CAST:
case CAST:
code.add("((");
boolean wrap = state.contains(IGState.BODY_ONLY);
if (wrap)
code.add("(");
code.add("(");
code.add(useType(((ArgType) ((IndexInsnNode) insn).getIndex())));
code.add(") (");
code.add(arg(insn.getArg(0), false));
code.add("))");
code.add(") ");
code.add(arg(insn.getArg(0)));
if (wrap)
code.add(")");
break;
case ARITH:
@@ -564,6 +568,19 @@ public class InsnGen {
}
}
private void addArgs(CodeWriter code, InsnNode insn, int k) throws CodegenException {
int argsCount = insn.getArgsCount();
code.add('(');
if (k < argsCount) {
code.add(arg(insn.getArg(k), false));
for (int i = k + 1; i < argsCount; i++) {
code.add(", ");
code.add(arg(insn.getArg(i), false));
}
}
code.add(')');
}
private void inlineMethod(MethodNode callMthNode, InvokeNode insn, CodeWriter code) throws CodegenException {
IAttribute mia = callMthNode.getAttributes().get(AttributeType.METHOD_INLINE);
InsnNode inl = ((MethodInlineAttr) mia).getInsn();
@@ -603,19 +620,6 @@ public class InsnGen {
}
}
private void addArgs(CodeWriter code, InsnNode insn, int k) throws CodegenException {
int argsCount = insn.getArgsCount();
code.add('(');
if (k < argsCount) {
code.add(arg(insn.getArg(k), false));
for (int i = k + 1; i < argsCount; i++) {
code.add(", ");
code.add(arg(insn.getArg(i), false));
}
}
code.add(')');
}
private void makeArith(ArithNode insn, CodeWriter code, EnumSet<IGState> state) throws CodegenException {
ArithOp op = insn.getOp();
String v1 = arg(insn.getArg(0));
@@ -384,6 +384,17 @@ public abstract class ArgType {
return null;
}
public static boolean isCastNeeded(ArgType from, ArgType to) {
if (from.equals(to)) {
return false;
}
if (from.isObject() && to.isObject()
&& clsp.isImplements(from.getObject(), to.getObject())) {
return false;
}
return true;
}
public static ArgType parse(String type) {
char f = type.charAt(0);
switch (f) {
@@ -64,9 +64,7 @@ public class ClassNode extends LineAttrNode implements ILoadable {
this.interfaces.add(ClassInfo.fromDex(dex, interfaceIdx));
}
if (cls.getClassDataOffset() == 0) {
// nothing to loadFile
} else {
if (cls.getClassDataOffset() != 0) {
ClassData clsData = dex.readClassData(cls);
for (Method mth : clsData.getDirectMethods())
@@ -10,6 +10,7 @@ import jadx.core.dex.instructions.IfNode;
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.FieldArg;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.InsnWrapArg;
@@ -234,6 +235,17 @@ public class CodeShrinker extends AbstractVisitor {
}
break;
case CHECK_CAST:
InsnArg castArg = insn.getArg(0);
ArgType castType = (ArgType) ((IndexInsnNode)insn).getIndex();
if (!ArgType.isCastNeeded(castArg.getType(), castType)) {
InsnNode insnNode = new InsnNode(InsnType.MOVE, 1);
insnNode.setResult(insn.getResult());
insnNode.addArg(castArg);
return insnNode;
}
break;
default:
break;
}
@@ -1,6 +1,8 @@
package jadx.core.dex.visitors.typeresolver;
import jadx.core.dex.attributes.BlockRegState;
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.BlockNode;
@@ -17,6 +19,8 @@ public class TypeResolver extends AbstractVisitor {
if (mth.isNoCode())
return;
prepare(mth);
visitBlocks(mth);
visitEdges(mth);
@@ -27,6 +31,22 @@ public class TypeResolver extends AbstractVisitor {
}
}
/**
* Check argument types (can be broken after merging debug info)
*/
private void prepare(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions()) {
switch (insn.getType()) {
case CHECK_CAST:
ArgType castType = (ArgType) ((IndexInsnNode) insn).getIndex();
insn.getResult().getTypedVar().forceSetType(castType);
break;
}
}
}
}
private void visitBlocks(MethodNode mth) {
for (BlockNode block : mth.getBasicBlocks()) {
BlockRegState state = new BlockRegState(mth);
@@ -0,0 +1,44 @@
package jadx.api;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.InsnWrapArg;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import java.util.List;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class TestDuplicateCast extends InternalJadxTest {
public static class TestCls {
public int[] method(Object o) {
return (int[]) o;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
MethodNode mth = getMethod(cls, "method");
List<InsnNode> insns = mth.getBasicBlocks().get(1).getInstructions();
assertEquals(insns.size(), 1);
InsnNode insnNode = insns.get(0);
assertEquals(InsnType.RETURN, insnNode.getType());
assertTrue(insnNode.getArg(0).isInsnWrap());
InsnNode wrapInsn = ((InsnWrapArg) insnNode.getArg(0)).getWrapInsn();
assertEquals(InsnType.CHECK_CAST, wrapInsn.getType());
assertFalse(wrapInsn.getArg(0).isInsnWrap());
String code = cls.getCode().toString();
assertThat(code, containsString("return (int[]) o;"));
}
}
@@ -0,0 +1,31 @@
package jadx.api;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestStringBuilderElimination extends InternalJadxTest {
public static class MyException extends Exception {
public MyException(String str, Exception e) {
// super("msg:" + str, e);
}
public void method(int k) {
System.out.println("k=" + k);
}
}
@Test
public void test() {
ClassNode cls = getClassNode(MyException.class);
String code = cls.getCode().toString();
assertThat(code, not(containsString("new StringBuilder")));
assertThat(code, containsString("System.out.println(\"k=\" + k);"));
}
}
@@ -0,0 +1,41 @@
package jadx.tests;
import jadx.core.clsp.ClspGraph;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.utils.exceptions.DecodeException;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import static jadx.core.dex.instructions.args.ArgType.object;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class JadxClasspathTest {
private static final String JAVA_LANG_EXCEPTION = "java.lang.Exception";
private static final String JAVA_LANG_THROWABLE = "java.lang.Throwable";
ClspGraph clsp;
@Before
public void initClsp() throws IOException, DecodeException {
clsp = new ClspGraph();
clsp.load();
ArgType.setClsp(clsp);
}
@Test
public void test() {
ArgType objExc = object(JAVA_LANG_EXCEPTION);
ArgType objThr = object(JAVA_LANG_THROWABLE);
assertTrue(clsp.isImplements(JAVA_LANG_EXCEPTION, JAVA_LANG_THROWABLE));
assertFalse(clsp.isImplements(JAVA_LANG_THROWABLE, JAVA_LANG_EXCEPTION));
assertFalse(ArgType.isCastNeeded(objExc, objThr));
assertTrue(ArgType.isCastNeeded(objThr, objExc));
}
}