use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method calcPostDomOut.
@Nullable
private static BlockNode calcPostDomOut(MethodNode mth, BlockNode block, List<BlockNode> exits) {
if (exits.size() == 1 && mth.getExitBlock().equals(exits.get(0))) {
// simple case: for only one exit which is equal to method exit block
return BlockUtils.calcImmediatePostDominator(mth, block);
}
// fast search: union of blocks dominance frontier
// work if no fallthrough cases and no returns inside switch
BitSet outs = BlockUtils.copyBlocksBitSet(mth, block.getDomFrontier());
for (BlockNode s : block.getCleanSuccessors()) {
outs.or(s.getDomFrontier());
}
outs.clear(block.getId());
if (outs.cardinality() != 1) {
// slow search: calculate partial post-dominance for every exit node
BitSet ipdoms = BlockUtils.newBlocksBitSet(mth);
for (BlockNode exitBlock : exits) {
if (BlockUtils.isAnyPathExists(block, exitBlock)) {
Set<BlockNode> pathBlocks = BlockUtils.getAllPathsBlocks(block, exitBlock);
BlockNode ipdom = BlockUtils.calcPartialImmediatePostDominator(mth, block, pathBlocks, exitBlock);
if (ipdom != null) {
ipdoms.set(ipdom.getId());
}
}
}
outs.and(ipdoms);
}
return BlockUtils.bitSetToOneBlock(mth, outs);
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method processTryCatchBlocks.
public IRegion processTryCatchBlocks(MethodNode mth) {
List<TryCatchBlockAttr> tcs = mth.getAll(AType.TRY_BLOCKS_LIST);
for (TryCatchBlockAttr tc : tcs) {
List<BlockNode> blocks = new ArrayList<>(tc.getHandlersCount());
Set<BlockNode> splitters = new HashSet<>();
for (ExceptionHandler handler : tc.getHandlers()) {
BlockNode handlerBlock = handler.getHandlerBlock();
if (handlerBlock != null) {
blocks.add(handlerBlock);
splitters.add(BlockUtils.getTopSplitterForHandler(handlerBlock));
} else {
mth.addDebugComment("No exception handler block: " + handler);
}
}
Set<BlockNode> exits = new HashSet<>();
for (BlockNode splitter : splitters) {
for (BlockNode handler : blocks) {
if (handler.contains(AFlag.REMOVE)) {
continue;
}
List<BlockNode> s = splitter.getSuccessors();
if (s.isEmpty()) {
mth.addDebugComment("No successors for splitter: " + splitter);
continue;
}
BlockNode ss = s.get(0);
BlockNode cross = BlockUtils.getPathCross(mth, ss, handler);
if (cross != null && cross != ss && cross != handler) {
exits.add(cross);
}
}
}
for (ExceptionHandler handler : tc.getHandlers()) {
processExcHandler(mth, handler, exits);
}
}
return processHandlersOutBlocks(mth, tcs);
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method isEmptySyntheticPath.
private static boolean isEmptySyntheticPath(BlockNode b1, BlockNode b2) {
BlockNode n1 = followEmptyPath(b1);
BlockNode n2 = followEmptyPath(b2);
return n1 == n2 || isEqualReturnBlocks(n1, n2);
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method processLoop.
private BlockNode processLoop(IRegion curRegion, LoopInfo loop, RegionStack stack) {
BlockNode loopStart = loop.getStart();
Set<BlockNode> exitBlocksSet = loop.getExitNodes();
// set exit blocks scan order priority
// this can help if loop have several exits (after using 'break' or 'return' in loop)
List<BlockNode> exitBlocks = new ArrayList<>(exitBlocksSet.size());
BlockNode nextStart = getNextBlock(loopStart);
if (nextStart != null && exitBlocksSet.remove(nextStart)) {
exitBlocks.add(nextStart);
}
if (exitBlocksSet.remove(loopStart)) {
exitBlocks.add(loopStart);
}
if (exitBlocksSet.remove(loop.getEnd())) {
exitBlocks.add(loop.getEnd());
}
exitBlocks.addAll(exitBlocksSet);
LoopRegion loopRegion = makeLoopRegion(curRegion, loop, exitBlocks);
if (loopRegion == null) {
BlockNode exit = makeEndlessLoop(curRegion, stack, loop, loopStart);
insertContinue(loop);
return exit;
}
curRegion.getSubBlocks().add(loopRegion);
IRegion outerRegion = stack.peekRegion();
stack.push(loopRegion);
IfInfo condInfo = makeIfInfo(mth, loopRegion.getHeader());
condInfo = searchNestedIf(condInfo);
confirmMerge(condInfo);
if (!loop.getLoopBlocks().contains(condInfo.getThenBlock())) {
// invert loop condition if 'then' points to exit
condInfo = IfInfo.invert(condInfo);
}
loopRegion.updateCondition(condInfo);
exitBlocks.removeAll(condInfo.getMergedBlocks());
if (!exitBlocks.isEmpty()) {
BlockNode loopExit = condInfo.getElseBlock();
if (loopExit != null) {
// add 'break' instruction before path cross between main loop exit and sub-exit
for (Edge exitEdge : loop.getExitEdges()) {
if (exitBlocks.contains(exitEdge.getSource())) {
insertLoopBreak(stack, loop, loopExit, exitEdge);
}
}
}
}
BlockNode out;
if (loopRegion.isConditionAtEnd()) {
BlockNode thenBlock = condInfo.getThenBlock();
out = thenBlock == loopStart ? condInfo.getElseBlock() : thenBlock;
loopStart.remove(AType.LOOP);
loop.getEnd().add(AFlag.ADDED_TO_REGION);
stack.addExit(loop.getEnd());
processedBlocks.clear(loopStart.getId());
Region body = makeRegion(loopStart, stack);
loopRegion.setBody(body);
loopStart.addAttr(AType.LOOP, loop);
loop.getEnd().remove(AFlag.ADDED_TO_REGION);
} else {
out = condInfo.getElseBlock();
if (outerRegion != null && out.contains(AFlag.LOOP_START) && !out.getAll(AType.LOOP).contains(loop) && RegionUtils.isRegionContainsBlock(outerRegion, out)) {
// exit to already processed outer loop
out = null;
}
stack.addExit(out);
BlockNode loopBody = condInfo.getThenBlock();
Region body;
if (Objects.equals(loopBody, loopStart)) {
// empty loop body
body = new Region(loopRegion);
} else {
body = makeRegion(loopBody, stack);
}
// add blocks from loop start to first condition block
BlockNode conditionBlock = condInfo.getFirstIfBlock();
if (loopStart != conditionBlock) {
Set<BlockNode> blocks = BlockUtils.getAllPathsBlocks(loopStart, conditionBlock);
blocks.remove(conditionBlock);
for (BlockNode block : blocks) {
if (block.getInstructions().isEmpty() && !block.contains(AFlag.ADDED_TO_REGION) && !RegionUtils.isRegionContainsBlock(body, block)) {
body.add(block);
}
}
}
loopRegion.setBody(body);
}
stack.pop();
insertContinue(loop);
return out;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class RegionMaker method makeRegion.
public Region makeRegion(BlockNode startBlock, RegionStack stack) {
Region r = new Region(stack.peekRegion());
if (startBlock == null) {
return r;
}
if (stack.containsExit(startBlock)) {
insertEdgeInsns(r, startBlock);
return r;
}
int startBlockId = startBlock.getId();
if (processedBlocks.get(startBlockId)) {
mth.addWarn("Removed duplicated region for block: " + startBlock + ' ' + startBlock.getAttributesString());
return r;
}
processedBlocks.set(startBlockId);
BlockNode next = startBlock;
while (next != null) {
next = traverse(r, next, stack);
regionsCount++;
if (regionsCount > regionsLimit) {
throw new JadxOverflowException("Regions count limit reached");
}
}
return r;
}
Aggregations