use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockUtils method getPathCross.
/**
* Return common cross block for input set.
*
* @return null if cross is a method exit block.
*/
@Nullable
public static BlockNode getPathCross(MethodNode mth, Collection<BlockNode> blocks) {
BitSet domFrontBS = newBlocksBitSet(mth);
boolean first = true;
for (BlockNode b : blocks) {
if (first) {
domFrontBS.or(b.getDomFrontier());
first = false;
} else {
domFrontBS.and(b.getDomFrontier());
}
}
domFrontBS.clear(mth.getExitBlock().getId());
if (domFrontBS.isEmpty()) {
return null;
}
BlockNode oneBlock = bitSetToOneBlock(mth, domFrontBS);
if (oneBlock != null) {
return oneBlock;
}
BitSet excluded = newBlocksBitSet(mth);
// exclude method exit and loop start blocks
excluded.set(mth.getExitBlock().getId());
// exclude loop start blocks
mth.getLoops().forEach(l -> excluded.set(l.getStart().getId()));
if (!mth.isNoExceptionHandlers()) {
// exclude exception handlers paths
mth.getExceptionHandlers().forEach(h -> mergeExcHandlerDomFrontier(mth, h, excluded));
}
domFrontBS.andNot(excluded);
oneBlock = bitSetToOneBlock(mth, domFrontBS);
if (oneBlock != null) {
return oneBlock;
}
BitSet combinedDF = newBlocksBitSet(mth);
int k = mth.getBasicBlocks().size();
while (true) {
// collect dom frontier blocks from current set until only one block left
forEachBlockFromBitSet(mth, domFrontBS, block -> {
BitSet domFrontier = block.getDomFrontier();
if (!domFrontier.isEmpty()) {
combinedDF.or(domFrontier);
combinedDF.clear(block.getId());
}
});
combinedDF.andNot(excluded);
int cardinality = combinedDF.cardinality();
if (cardinality == 1) {
return bitSetToOneBlock(mth, combinedDF);
}
if (cardinality == 0) {
return null;
}
if (k-- < 0) {
mth.addWarnComment("Path cross not found for " + blocks + ", limit reached: " + mth.getBasicBlocks().size());
return null;
}
// replace domFrontBS with combinedDF
domFrontBS.clear();
domFrontBS.or(combinedDF);
combinedDF.clear();
}
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockUtils method followEmptyPath.
/**
* Follow empty blocks and return end of path block (first not empty).
* Return start block if no such path.
*/
public static BlockNode followEmptyPath(BlockNode start) {
while (true) {
BlockNode next = getNextBlockOnEmptyPath(start);
if (next == null) {
return start;
}
start = next;
}
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockUtils method isFirstInsn.
public static boolean isFirstInsn(MethodNode mth, InsnNode insn) {
BlockNode startBlock = followEmptyPath(mth.getEnterBlock());
if (startBlock != null && !startBlock.getInstructions().isEmpty()) {
return startBlock.getInstructions().get(0) == insn;
}
// handle branching with empty blocks
BlockNode block = getBlockByInsn(mth, insn);
if (block == null) {
throw new JadxRuntimeException("Insn not found in method: " + insn);
}
if (block.getInstructions().get(0) != insn) {
return false;
}
Set<BlockNode> allPathsBlocks = getAllPathsBlocks(mth.getEnterBlock(), block);
for (BlockNode pathBlock : allPathsBlocks) {
if (!pathBlock.getInstructions().isEmpty() && pathBlock != block) {
return false;
}
}
return true;
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockUtils method visitSinglePath.
/**
* Visit blocks on path without branching or merging paths.
*/
public static void visitSinglePath(BlockNode startBlock, Consumer<BlockNode> visitor) {
if (startBlock == null) {
return;
}
visitor.accept(startBlock);
BlockNode next = getNextSinglePathBlock(startBlock);
while (next != null) {
visitor.accept(next);
next = getNextSinglePathBlock(next);
}
}
use of jadx.core.dex.nodes.BlockNode in project jadx by skylot.
the class BlockUtils method visitBlocksOnEmptyPath.
public static void visitBlocksOnEmptyPath(BlockNode start, Consumer<BlockNode> visitor) {
while (true) {
BlockNode next = getNextBlockOnEmptyPath(start);
if (next == null) {
return;
}
visitor.accept(next);
start = next;
}
}
Aggregations