提交 e2018535 编写于 作者: S Skylot

core: add ternary conditions processing

上级 ee56610f
...@@ -33,6 +33,10 @@ public class ConditionGen extends InsnGen { ...@@ -33,6 +33,10 @@ public class ConditionGen extends InsnGen {
addCompare(code, condition.getCompare()); addCompare(code, condition.getCompare());
break; break;
case TERNARY:
addTernary(code, condition);
break;
case NOT: case NOT:
addNot(code, condition); addNot(code, condition);
break; break;
...@@ -43,7 +47,7 @@ public class ConditionGen extends InsnGen { ...@@ -43,7 +47,7 @@ public class ConditionGen extends InsnGen {
break; break;
default: default:
throw new JadxRuntimeException("Unknown condition mode: " + condition); throw new JadxRuntimeException("Unknown condition mode: " + condition.getMode());
} }
} }
...@@ -94,6 +98,14 @@ public class ConditionGen extends InsnGen { ...@@ -94,6 +98,14 @@ public class ConditionGen extends InsnGen {
addArg(code, secondArg, isArgWrapNeeded(secondArg)); addArg(code, secondArg, isArgWrapNeeded(secondArg));
} }
private void addTernary(CodeWriter code, IfCondition condition) throws CodegenException {
add(code, condition.first());
code.add(" ? ");
add(code, condition.second());
code.add(" : ");
add(code, condition.third());
}
private void addNot(CodeWriter code, IfCondition condition) throws CodegenException { private void addNot(CodeWriter code, IfCondition condition) throws CodegenException {
code.add('!'); code.add('!');
wrap(code, condition.getArgs().get(0)); wrap(code, condition.getArgs().get(0));
......
...@@ -11,7 +11,11 @@ import jadx.core.utils.Utils; ...@@ -11,7 +11,11 @@ import jadx.core.utils.Utils;
public class TernaryInsn extends InsnNode { public class TernaryInsn extends InsnNode {
private final IfCondition condition; private IfCondition condition;
public TernaryInsn(IfCondition condition, RegisterArg result) {
this(condition, result, LiteralArg.TRUE, LiteralArg.FALSE);
}
public TernaryInsn(IfCondition condition, RegisterArg result, InsnArg th, InsnArg els) { public TernaryInsn(IfCondition condition, RegisterArg result, InsnArg th, InsnArg els) {
super(InsnType.TERNARY, 2); super(InsnType.TERNARY, 2);
...@@ -33,6 +37,20 @@ public class TernaryInsn extends InsnNode { ...@@ -33,6 +37,20 @@ public class TernaryInsn extends InsnNode {
return condition; return condition;
} }
public void simplifyCondition() {
condition = IfCondition.simplify(condition);
if (condition.getMode() == IfCondition.Mode.NOT) {
invert();
}
}
private void invert() {
condition = IfCondition.invert(condition);
InsnArg tmp = getArg(0);
setArg(0, getArg(1));
setArg(1, tmp);
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
......
...@@ -22,6 +22,7 @@ public final class IfCondition { ...@@ -22,6 +22,7 @@ public final class IfCondition {
public enum Mode { public enum Mode {
COMPARE, COMPARE,
TERNARY,
NOT, NOT,
AND, AND,
OR OR
...@@ -64,6 +65,10 @@ public final class IfCondition { ...@@ -64,6 +65,10 @@ public final class IfCondition {
return new IfCondition(new Compare(insn)); return new IfCondition(new Compare(insn));
} }
public static IfCondition ternary(IfCondition a, IfCondition b, IfCondition c) {
return new IfCondition(Mode.TERNARY, Arrays.asList(a, b, c));
}
public static IfCondition merge(Mode mode, IfCondition a, IfCondition b) { public static IfCondition merge(Mode mode, IfCondition a, IfCondition b) {
if (a.getMode() == mode) { if (a.getMode() == mode) {
IfCondition n = new IfCondition(a); IfCondition n = new IfCondition(a);
...@@ -89,6 +94,10 @@ public final class IfCondition { ...@@ -89,6 +94,10 @@ public final class IfCondition {
return args.get(1); return args.get(1);
} }
public IfCondition third() {
return args.get(2);
}
public void addArg(IfCondition c) { public void addArg(IfCondition c) {
args.add(c); args.add(c);
} }
...@@ -106,6 +115,8 @@ public final class IfCondition { ...@@ -106,6 +115,8 @@ public final class IfCondition {
switch (mode) { switch (mode) {
case COMPARE: case COMPARE:
return new IfCondition(cond.getCompare().invert()); return new IfCondition(cond.getCompare().invert());
case TERNARY:
return ternary(not(cond.first()), cond.third(), cond.second());
case NOT: case NOT:
return cond.first(); return cond.first();
case AND: case AND:
...@@ -154,7 +165,10 @@ public final class IfCondition { ...@@ -154,7 +165,10 @@ public final class IfCondition {
cond = new IfCondition(cond.getMode(), args); cond = new IfCondition(cond.getMode(), args);
} }
if (cond.getMode() == Mode.NOT && cond.first().getMode() == Mode.NOT) { if (cond.getMode() == Mode.NOT && cond.first().getMode() == Mode.NOT) {
cond = cond.first().first(); cond = invert(cond.first());
}
if (cond.getMode() == Mode.TERNARY && cond.first().getMode() == Mode.NOT) {
cond = invert(cond);
} }
// for condition with a lot of negations => make invert // for condition with a lot of negations => make invert
...@@ -216,6 +230,8 @@ public final class IfCondition { ...@@ -216,6 +230,8 @@ public final class IfCondition {
switch (mode) { switch (mode) {
case COMPARE: case COMPARE:
return compare.toString(); return compare.toString();
case TERNARY:
return first() + " ? " + second() + " : " + third();
case NOT: case NOT:
return "!" + first(); return "!" + first();
case AND: case AND:
......
...@@ -65,7 +65,7 @@ public class SimplifyVisitor extends AbstractVisitor { ...@@ -65,7 +65,7 @@ public class SimplifyVisitor extends AbstractVisitor {
simplifyIf((IfNode) insn); simplifyIf((IfNode) insn);
break; break;
case TERNARY: case TERNARY:
simplifyTernary((TernaryInsn)insn); simplifyTernary((TernaryInsn) insn);
break; break;
case INVOKE: case INVOKE:
...@@ -117,6 +117,8 @@ public class SimplifyVisitor extends AbstractVisitor { ...@@ -117,6 +117,8 @@ public class SimplifyVisitor extends AbstractVisitor {
IfCondition condition = insn.getCondition(); IfCondition condition = insn.getCondition();
if (condition.isCompare()) { if (condition.isCompare()) {
simplifyIf(condition.getCompare().getInsn()); simplifyIf(condition.getCompare().getInsn());
} else {
insn.simplifyCondition();
} }
} }
......
...@@ -101,6 +101,11 @@ public class IfMakerHelper { ...@@ -101,6 +101,11 @@ public class IfMakerHelper {
return c1.size() == c2.size() && c1.containsAll(c2); return c1.size() == c2.size() && c1.containsAll(c2);
} }
static IfInfo searchNestedIf(IfInfo info) {
IfInfo tmp = mergeNestedIfNodes(info);
return tmp != null ? tmp : info;
}
static IfInfo mergeNestedIfNodes(IfInfo currentIf) { static IfInfo mergeNestedIfNodes(IfInfo currentIf) {
BlockNode curThen = currentIf.getThenBlock(); BlockNode curThen = currentIf.getThenBlock();
BlockNode curElse = currentIf.getElseBlock(); BlockNode curElse = currentIf.getElseBlock();
...@@ -126,12 +131,13 @@ public class IfMakerHelper { ...@@ -126,12 +131,13 @@ public class IfMakerHelper {
if (!RegionMaker.isEqualPaths(curElse, nextIf.getElseBlock()) if (!RegionMaker.isEqualPaths(curElse, nextIf.getElseBlock())
&& !RegionMaker.isEqualPaths(curThen, nextIf.getThenBlock())) { && !RegionMaker.isEqualPaths(curThen, nextIf.getThenBlock())) {
// complex condition, run additional checks // complex condition, run additional checks
if (checkConditionBranches(curThen, curElse) || checkConditionBranches(curElse, curThen)) { if (checkConditionBranches(curThen, curElse)
|| checkConditionBranches(curElse, curThen)) {
return null; return null;
} }
BlockNode otherBranchBlock = followThenBranch ? curElse : curThen; BlockNode otherBranchBlock = followThenBranch ? curElse : curThen;
if (!isPathExists(nextIf.getIfBlock(), otherBranchBlock)) { if (!isPathExists(nextIf.getIfBlock(), otherBranchBlock)) {
return null; return checkForTernaryInCondition(currentIf);
} }
if (isPathExists(nextIf.getThenBlock(), otherBranchBlock) if (isPathExists(nextIf.getThenBlock(), otherBranchBlock)
&& isPathExists(nextIf.getElseBlock(), otherBranchBlock)) { && isPathExists(nextIf.getElseBlock(), otherBranchBlock)) {
...@@ -152,9 +158,43 @@ public class IfMakerHelper { ...@@ -152,9 +158,43 @@ public class IfMakerHelper {
IfInfo result = mergeIfInfo(currentIf, nextIf, followThenBranch); IfInfo result = mergeIfInfo(currentIf, nextIf, followThenBranch);
// search next nested if block // search next nested if block
IfInfo next = mergeNestedIfNodes(result); return searchNestedIf(result);
if (next != null) { }
return next;
private static IfInfo checkForTernaryInCondition(IfInfo currentIf) {
IfInfo nextThen = getNextIf(currentIf, currentIf.getThenBlock());
IfInfo nextElse = getNextIf(currentIf, currentIf.getElseBlock());
if (nextThen == null || nextElse == null) {
return null;
}
if (!nextThen.getIfBlock().getDomFrontier().equals(nextElse.getIfBlock().getDomFrontier())) {
return null;
}
nextThen = searchNestedIf(nextThen);
nextElse = searchNestedIf(nextElse);
if (nextThen.getThenBlock() == nextElse.getThenBlock()
&& nextThen.getElseBlock() == nextElse.getElseBlock()) {
return mergeTernaryConditions(currentIf, nextThen, nextElse);
}
if (nextThen.getThenBlock() == nextElse.getElseBlock()
&& nextThen.getElseBlock() == nextElse.getThenBlock()) {
nextElse = IfInfo.invert(nextElse);
return mergeTernaryConditions(currentIf, nextThen, nextElse);
}
return null;
}
private static IfInfo mergeTernaryConditions(IfInfo currentIf, IfInfo nextThen, IfInfo nextElse) {
IfCondition newCondition = IfCondition.ternary(currentIf.getCondition(),
nextThen.getCondition(), nextElse.getCondition());
IfInfo result = new IfInfo(newCondition, nextThen.getThenBlock(), nextThen.getElseBlock());
result.setIfBlock(currentIf.getIfBlock());
result.getMergedBlocks().addAll(currentIf.getMergedBlocks());
result.getMergedBlocks().addAll(nextThen.getMergedBlocks());
result.getMergedBlocks().addAll(nextElse.getMergedBlocks());
for (BlockNode blockNode : result.getMergedBlocks()) {
blockNode.add(AFlag.SKIP);
} }
return result; return result;
} }
......
...@@ -20,15 +20,6 @@ public class TestConditions14 extends InternalJadxTest { ...@@ -20,15 +20,6 @@ public class TestConditions14 extends InternalJadxTest {
System.out.println("1"); System.out.println("1");
return true; return true;
} }
// public static boolean test2(Object a, Object b) {
// if (a == null ? b != null : !a.equals(b)) {
// return false;
// }
// System.out.println("2");
// return true;
// }
} }
@Test @Test
......
package jadx.tests.internal.conditions;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static jadx.tests.utils.JadxMatchers.containsOne;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestTernaryInIf extends InternalJadxTest {
public static class TestCls {
public boolean test1(boolean a, boolean b, boolean c) {
return a ? b : c;
}
public int test2(boolean a, boolean b, boolean c) {
return (a ? b : c) ? 1 : 2;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsOne("return a ? b : c;"));
assertThat(code, containsOne("return (a ? b : c) ? 1 : 2;"));
assertThat(code, not(containsString("if")));
assertThat(code, not(containsString("else")));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册