use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method canInsertBreak.
private boolean canInsertBreak(BlockNode exit) {
if (BlockUtils.containsExitInsn(exit)) {
return false;
}
List<BlockNode> simplePath = BlockUtils.buildSimplePath(exit);
if (!simplePath.isEmpty()) {
BlockNode lastBlock = simplePath.get(simplePath.size() - 1);
if (lastBlock.contains(AFlag.RETURN) || lastBlock.getSuccessors().isEmpty()) {
return false;
}
}
// check if there no outer switch (TODO: very expensive check)
Set<BlockNode> paths = BlockUtils.getAllPathsBlocks(mth.getEnterBlock(), exit);
for (BlockNode block : paths) {
if (BlockUtils.checkLastInsnType(block, InsnType.SWITCH)) {
return false;
}
}
return true;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method processSwitch.
private BlockNode processSwitch(IRegion currentRegion, BlockNode block, SwitchInsn insn, RegionStack stack) {
// map case blocks to keys
int len = insn.getTargets().length;
Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<>(len);
BlockNode[] targetBlocksArr = insn.getTargetBlocks();
for (int i = 0; i < len; i++) {
List<Object> keys = blocksMap.computeIfAbsent(targetBlocksArr[i], k -> new ArrayList<>(2));
keys.add(insn.getKey(i));
}
BlockNode defCase = insn.getDefTargetBlock();
if (defCase != null) {
List<Object> keys = blocksMap.computeIfAbsent(defCase, k -> new ArrayList<>(1));
keys.add(SwitchRegion.DEFAULT_CASE_KEY);
}
// search 'out' block - 'next' block after whole switch statement
BlockNode out;
LoopInfo loop = mth.getLoopForBlock(block);
if (loop == null) {
out = calcPostDomOut(mth, block, mth.getPreExitBlocks());
} else {
BlockNode loopEnd = loop.getEnd();
stack.addExit(loop.getStart());
if (stack.containsExit(block) || block == loopEnd || loopEnd.getPredecessors().contains(block)) {
// in exits or last insn in loop => no 'out' block
out = null;
} else {
// treat 'continue' as exit
out = calcPostDomOut(mth, block, loopEnd.getPredecessors());
if (out != null) {
insertContinueInSwitch(block, out, loopEnd);
} else {
// no 'continue'
out = calcPostDomOut(mth, block, Collections.singletonList(loopEnd));
}
}
if (out == loop.getStart()) {
// no other outs instead back edge to loop start
out = null;
}
}
if (out != null && processedBlocks.get(out.getId())) {
// out block already processed, prevent endless loop
throw new JadxRuntimeException("Failed to find switch 'out' block");
}
SwitchRegion sw = new SwitchRegion(currentRegion, block);
currentRegion.getSubBlocks().add(sw);
stack.push(sw);
stack.addExit(out);
// detect fallthrough cases
Map<BlockNode, BlockNode> fallThroughCases = new LinkedHashMap<>();
if (out != null) {
BitSet caseBlocks = BlockUtils.blocksToBitSet(mth, blocksMap.keySet());
caseBlocks.clear(out.getId());
for (BlockNode successor : block.getCleanSuccessors()) {
BlockNode fallThroughBlock = searchFallThroughCase(successor, out, caseBlocks);
if (fallThroughBlock != null) {
fallThroughCases.put(successor, fallThroughBlock);
}
}
// check fallthrough cases order
if (!fallThroughCases.isEmpty() && isBadCasesOrder(blocksMap, fallThroughCases)) {
Map<BlockNode, List<Object>> newBlocksMap = reOrderSwitchCases(blocksMap, fallThroughCases);
if (isBadCasesOrder(newBlocksMap, fallThroughCases)) {
mth.addWarnComment("Can't fix incorrect switch cases order, some code will duplicate");
fallThroughCases.clear();
} else {
blocksMap = newBlocksMap;
}
}
}
for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
List<Object> keysList = entry.getValue();
BlockNode caseBlock = entry.getKey();
if (stack.containsExit(caseBlock)) {
sw.addCase(keysList, new Region(stack.peekRegion()));
} else {
BlockNode next = fallThroughCases.get(caseBlock);
stack.addExit(next);
Region caseRegion = makeRegion(caseBlock, stack);
stack.removeExit(next);
if (next != null) {
next.add(AFlag.FALL_THROUGH);
caseRegion.add(AFlag.FALL_THROUGH);
}
sw.addCase(keysList, caseRegion);
// 'break' instruction will be inserted in RegionMakerVisitor.PostRegionVisitor
}
}
removeEmptyCases(insn, sw, defCase);
stack.pop();
return out;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class CodeShrinkVisitor method canMoveBetweenBlocks.
private static boolean canMoveBetweenBlocks(MethodNode mth, InsnNode assignInsn, BlockNode assignBlock, BlockNode useBlock, InsnNode useInsn) {
if (!BlockUtils.isPathExists(assignBlock, useBlock)) {
return false;
}
List<RegisterArg> argsList = ArgsInfo.getArgs(assignInsn);
BitSet args = new BitSet();
for (RegisterArg arg : argsList) {
args.set(arg.getRegNum());
}
boolean startCheck = false;
for (InsnNode insn : assignBlock.getInstructions()) {
if (startCheck && (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args))) {
return false;
}
if (insn == assignInsn) {
startCheck = true;
}
}
Set<BlockNode> pathsBlocks = BlockUtils.getAllPathsBlocks(assignBlock, useBlock);
pathsBlocks.remove(assignBlock);
pathsBlocks.remove(useBlock);
for (BlockNode block : pathsBlocks) {
if (block.contains(AFlag.DONT_GENERATE)) {
if (BlockUtils.checkLastInsnType(block, InsnType.MONITOR_EXIT)) {
if (RegionUtils.isBlocksInSameRegion(mth, assignBlock, useBlock)) {
// allow move inside same synchronized region
} else {
// don't move from synchronized block
return false;
}
}
// skip checks for not generated blocks
continue;
}
for (InsnNode insn : block.getInstructions()) {
if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
return false;
}
}
}
for (InsnNode insn : useBlock.getInstructions()) {
if (insn == useInsn) {
return true;
}
if (!insn.canReorder() || ArgsInfo.usedArgAssign(insn, args)) {
return false;
}
}
throw new JadxRuntimeException("Can't process instruction move : " + assignBlock);
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class SSATransform method resetSSAVars.
private static void resetSSAVars(MethodNode mth) {
for (SSAVar ssaVar : mth.getSVars()) {
ssaVar.getAssign().resetSSAVar();
ssaVar.getUseList().forEach(RegisterArg::resetSSAVar);
}
for (BlockNode block : mth.getBasicBlocks()) {
block.remove(AType.PHI_LIST);
}
mth.getSVars().clear();
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class SSATransform method fixUselessPhi.
private static boolean fixUselessPhi(MethodNode mth) {
boolean changed = false;
List<PhiInsn> insnToRemove = new ArrayList<>();
for (SSAVar var : mth.getSVars()) {
// phi result not used
if (var.getUseCount() == 0) {
InsnNode assignInsn = var.getAssign().getParentInsn();
if (assignInsn != null && assignInsn.getType() == InsnType.PHI) {
insnToRemove.add((PhiInsn) assignInsn);
changed = true;
}
}
}
for (BlockNode block : mth.getBasicBlocks()) {
PhiListAttr phiList = block.get(AType.PHI_LIST);
if (phiList == null) {
continue;
}
Iterator<PhiInsn> it = phiList.getList().iterator();
while (it.hasNext()) {
PhiInsn phi = it.next();
if (fixPhiWithSameArgs(mth, block, phi)) {
it.remove();
changed = true;
}
}
}
removePhiList(mth, insnToRemove);
return changed;
}
Aggregations