core: remove not needed casts
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user