Commit 066b5a89 authored by Skylot's avatar Skylot

core: refactor 'if' regions processing

parent 4c4af792
...@@ -11,9 +11,9 @@ import jadx.core.dex.nodes.BlockNode; ...@@ -11,9 +11,9 @@ import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.utils.BlockUtils; import jadx.core.utils.BlockUtils;
import jadx.core.utils.InstructionRemover;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
...@@ -25,12 +25,13 @@ public class ConstInlinerVisitor extends AbstractVisitor { ...@@ -25,12 +25,13 @@ public class ConstInlinerVisitor extends AbstractVisitor {
return; return;
} }
for (BlockNode block : mth.getBasicBlocks()) { for (BlockNode block : mth.getBasicBlocks()) {
for (Iterator<InsnNode> it = block.getInstructions().iterator(); it.hasNext(); ) { InstructionRemover remover = new InstructionRemover(block.getInstructions());
InsnNode insn = it.next(); for (InsnNode insn : block.getInstructions()) {
if (checkInsn(mth, block, insn)) { if (checkInsn(mth, block, insn)) {
it.remove(); remover.add(insn);
} }
} }
remover.perform();
} }
} }
...@@ -53,9 +54,11 @@ public class ConstInlinerVisitor extends AbstractVisitor { ...@@ -53,9 +54,11 @@ public class ConstInlinerVisitor extends AbstractVisitor {
private static boolean replaceConst(MethodNode mth, BlockNode block, InsnNode insn, long literal) { private static boolean replaceConst(MethodNode mth, BlockNode block, InsnNode insn, long literal) {
List<InsnArg> use = insn.getResult().getTypedVar().getUseList(); List<InsnArg> use = insn.getResult().getTypedVar().getUseList();
int replaceCount = 0; int replaceCount = 0;
int assignCount = 0;
for (InsnArg arg : use) { for (InsnArg arg : use) {
InsnNode useInsn = arg.getParentInsn(); InsnNode useInsn = arg.getParentInsn();
if (arg == insn.getResult() || useInsn == null) { if (arg == insn.getResult() || useInsn == null) {
assignCount++;
continue; continue;
} }
BlockNode useBlock = BlockUtils.getBlockByInsn(mth, useInsn); BlockNode useBlock = BlockUtils.getBlockByInsn(mth, useInsn);
...@@ -76,7 +79,7 @@ public class ConstInlinerVisitor extends AbstractVisitor { ...@@ -76,7 +79,7 @@ public class ConstInlinerVisitor extends AbstractVisitor {
} }
} }
} }
return replaceCount == use.size() - 1; return replaceCount == use.size() - assignCount;
} }
private static boolean registerReassignOnPath(BlockNode block, BlockNode useBlock, InsnNode assignInsn) { private static boolean registerReassignOnPath(BlockNode block, BlockNode useBlock, InsnNode assignInsn) {
......
...@@ -7,7 +7,9 @@ import jadx.core.dex.nodes.IContainer; ...@@ -7,7 +7,9 @@ import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.IfRegion;
import jadx.core.dex.regions.LoopRegion; import jadx.core.dex.regions.LoopRegion;
import jadx.core.dex.regions.SwitchRegion;
import jadx.core.utils.RegionUtils; import jadx.core.utils.RegionUtils;
import java.util.List; import java.util.List;
...@@ -52,6 +54,12 @@ public class ProcessReturnInsns extends TracedRegionVisitor { ...@@ -52,6 +54,12 @@ public class ProcessReturnInsns extends TracedRegionVisitor {
private boolean noTrailInstructions(BlockNode block) { private boolean noTrailInstructions(BlockNode block) {
IContainer curContainer = block; IContainer curContainer = block;
for (IRegion region : regionStack) { for (IRegion region : regionStack) {
// ignore paths on other branches
if (region instanceof IfRegion
|| region instanceof SwitchRegion) {
curContainer = region;
continue;
}
List<IContainer> subBlocks = region.getSubBlocks(); List<IContainer> subBlocks = region.getSubBlocks();
if (!subBlocks.isEmpty()) { if (!subBlocks.isEmpty()) {
ListIterator<IContainer> itSubBlock = subBlocks.listIterator(subBlocks.size()); ListIterator<IContainer> itSubBlock = subBlocks.listIterator(subBlocks.size());
......
...@@ -461,13 +461,8 @@ public class RegionMaker { ...@@ -461,13 +461,8 @@ public class RegionMaker {
} }
} }
if (elseBlock != null) { if (elseBlock != null && stack.containsExit(elseBlock)) {
if (stack.containsExit(elseBlock)) { elseBlock = null;
elseBlock = null;
} else if (elseBlock.getAttributes().contains(AttributeFlag.RETURN)) {
out = elseBlock;
elseBlock = null;
}
} }
stack.push(ifRegion); stack.push(ifRegion);
...@@ -481,73 +476,88 @@ public class RegionMaker { ...@@ -481,73 +476,88 @@ public class RegionMaker {
} }
private IfInfo mergeNestedIfNodes(BlockNode block, BlockNode bThen, BlockNode bElse, List<BlockNode> merged) { private IfInfo mergeNestedIfNodes(BlockNode block, BlockNode bThen, BlockNode bElse, List<BlockNode> merged) {
IfInfo info = new IfInfo();
info.setIfnode(block);
info.setCondition(IfCondition.fromIfBlock(block));
info.setThenBlock(bThen);
info.setElseBlock(bElse);
return mergeNestedIfNodes(info, merged);
}
private IfInfo mergeNestedIfNodes(IfInfo info, List<BlockNode> merged) {
BlockNode bThen = info.getThenBlock();
BlockNode bElse = info.getElseBlock();
if (bThen == bElse) { if (bThen == bElse) {
return null; return null;
} }
boolean found; BlockNode ifBlock = info.getIfnode();
IfCondition condition = IfCondition.fromIfBlock(block); BlockNode nestedIfBlock = getNextIfBlock(ifBlock);
IfInfo result = null; if (nestedIfBlock == null) {
do { return null;
found = false; }
for (BlockNode succ : block.getSuccessors()) {
BlockNode nestedIfBlock = getIfNode(succ);
if (nestedIfBlock != null && nestedIfBlock != block) {
IfNode nestedIfInsn = (IfNode) nestedIfBlock.getInstructions().get(0);
BlockNode nbThen = nestedIfInsn.getThenBlock();
BlockNode nbElse = nestedIfInsn.getElseBlock();
boolean inverted = false;
IfCondition nestedCondition = IfCondition.fromIfNode(nestedIfInsn);
if (isPathExists(bElse, nestedIfBlock)) {
// else branch
if (!isEqualPaths(bThen, nbThen)) {
if (!isEqualPaths(bThen, nbElse)) {
// not connected conditions
break;
}
nestedIfInsn.invertCondition();
inverted = true;
}
condition = IfCondition.merge(Mode.OR, condition, nestedCondition);
} else {
// then branch
if (!isEqualPaths(bElse, nbElse)) {
if (!isEqualPaths(bElse, nbThen)) {
// not connected conditions
break;
}
nestedIfInsn.invertCondition();
inverted = true;
}
condition = IfCondition.merge(Mode.AND, condition, nestedCondition);
}
result = new IfInfo();
result.setCondition(condition);
nestedIfBlock.getAttributes().add(AttributeFlag.SKIP);
skipSimplePath(bThen);
if (merged != null) {
merged.add(nestedIfBlock);
}
// set new blocks IfNode nestedIfInsn = (IfNode) nestedIfBlock.getInstructions().get(0);
result.setIfnode(nestedIfBlock); IfCondition nestedCondition = IfCondition.fromIfNode(nestedIfInsn);
result.setThenBlock(inverted ? nbElse : nbThen); BlockNode nbThen = nestedIfInsn.getThenBlock();
result.setElseBlock(inverted ? nbThen : nbElse); BlockNode nbElse = nestedIfInsn.getElseBlock();
found = true; IfCondition condition = info.getCondition();
block = nestedIfBlock; boolean inverted = false;
bThen = result.getThenBlock(); if (isPathExists(bElse, nestedIfBlock)) {
bElse = result.getElseBlock(); // else branch
break; if (!isEqualPaths(bThen, nbThen)) {
if (!isEqualPaths(bThen, nbElse)) {
// not connected conditions
return null;
}
nestedIfInsn.invertCondition();
inverted = true;
}
condition = IfCondition.merge(Mode.OR, condition, nestedCondition);
} else {
// then branch
if (!isEqualPaths(bElse, nbElse)) {
if (!isEqualPaths(bElse, nbThen)) {
// not connected conditions
return null;
} }
nestedIfInsn.invertCondition();
inverted = true;
} }
} while (found); condition = IfCondition.merge(Mode.AND, condition, nestedCondition);
}
if (merged != null) {
merged.add(nestedIfBlock);
}
nestedIfBlock.getAttributes().add(AttributeFlag.SKIP);
BlockNode blockToNestedIfBlock = BlockUtils.getNextBlockToPath(ifBlock, nestedIfBlock);
skipSimplePath(BlockUtils.selectOther(blockToNestedIfBlock, ifBlock.getCleanSuccessors()));
IfInfo result = new IfInfo();
result.setIfnode(nestedIfBlock);
result.setCondition(condition);
result.setThenBlock(inverted ? nbElse : nbThen);
result.setElseBlock(inverted ? nbThen : nbElse);
// search next nested if block
IfInfo next = mergeNestedIfNodes(result, merged);
if (next != null) {
return next;
}
return result; return result;
} }
private BlockNode getNextIfBlock(BlockNode block) {
for (BlockNode succ : block.getSuccessors()) {
BlockNode nestedIfBlock = getIfNode(succ);
if (nestedIfBlock != null && nestedIfBlock != block) {
return nestedIfBlock;
}
}
return null;
}
private static BlockNode getIfNode(BlockNode block) { private static BlockNode getIfNode(BlockNode block) {
if (block != null && !block.getAttributes().contains(AttributeType.LOOP)) { if (block != null && !block.getAttributes().contains(AttributeType.LOOP)) {
List<InsnNode> insns = block.getInstructions(); List<InsnNode> insns = block.getInstructions();
......
...@@ -132,6 +132,23 @@ public class BlockUtils { ...@@ -132,6 +132,23 @@ public class BlockUtils {
} }
/** /**
* Return successor on path to 'pathEnd' block
*/
public static BlockNode getNextBlockToPath(BlockNode block, BlockNode pathEnd) {
List<BlockNode> successors = block.getCleanSuccessors();
if (successors.contains(pathEnd)) {
return pathEnd;
}
Set<BlockNode> path = getAllPathsBlocks(block, pathEnd);
for (BlockNode s : successors) {
if (path.contains(s)) {
return s;
}
}
return null;
}
/**
* Collect blocks from all possible execution paths from 'start' to 'end' * Collect blocks from all possible execution paths from 'start' to 'end'
*/ */
public static Set<BlockNode> getAllPathsBlocks(BlockNode start, BlockNode end) { public static Set<BlockNode> getAllPathsBlocks(BlockNode start, BlockNode end) {
......
...@@ -35,18 +35,18 @@ public class Utils { ...@@ -35,18 +35,18 @@ public class Utils {
case '/': case '/':
case ';': case ';':
case '$': case '$':
case ' ':
case ',':
case '<': case '<':
case '[':
sb.append('_'); sb.append('_');
break; break;
case ']': case '[':
sb.append('A'); sb.append('A');
break; break;
case ']':
case '>': case '>':
case ',':
case ' ':
case '?': case '?':
case '*': case '*':
break; break;
......
package jadx.api; package jadx.api;
import jadx.core.Jadx; import jadx.core.Jadx;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.DepthTraverser; import jadx.core.dex.visitors.DepthTraverser;
...@@ -20,9 +19,11 @@ import java.util.jar.JarEntry; ...@@ -20,9 +19,11 @@ import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream; import java.util.jar.JarOutputStream;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.fail; import static junit.framework.Assert.fail;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public abstract class InternalJadxTest extends TestUtils { public abstract class InternalJadxTest extends TestUtils {
...@@ -67,7 +68,7 @@ public abstract class InternalJadxTest extends TestUtils { ...@@ -67,7 +68,7 @@ public abstract class InternalJadxTest extends TestUtils {
for (IDexTreeVisitor visitor : passes) { for (IDexTreeVisitor visitor : passes) {
DepthTraverser.visit(visitor, cls); DepthTraverser.visit(visitor, cls);
} }
assertFalse(cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)); assertThat(cls.getCode().toString(), not(containsString("inconsistent")));
return cls; return cls;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
......
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