use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.
the class BlockFinallyExtract method extractFinally.
/**
* Search and remove common code from 'catch' and 'handlers'.
*/
private static boolean extractFinally(MethodNode mth, ExceptionHandler handler) {
int count = handler.getBlocks().size();
BitSet bs = new BitSet(count);
List<BlockNode> blocks = new ArrayList<BlockNode>(count);
for (BlockNode block : handler.getBlocks()) {
List<InsnNode> insns = block.getInstructions();
if (!insns.isEmpty()) {
if (insns.get(0).getType() != InsnType.MOVE_EXCEPTION) {
blocks.add(block);
}
bs.set(block.getId());
}
}
if (blocks.isEmpty()) {
// nothing to do
return false;
}
List<BlocksRemoveInfo> removes = new LinkedList<BlocksRemoveInfo>();
Set<BlockNode> splitters = new HashSet<BlockNode>();
// remove 'finally' from handlers
TryCatchBlock tryBlock = handler.getTryBlock();
if (tryBlock.getHandlersCount() > 1) {
for (ExceptionHandler otherHandler : tryBlock.getHandlers()) {
if (otherHandler == handler) {
continue;
}
for (BlockNode hb : otherHandler.getBlocks()) {
BlocksRemoveInfo removeInfo = removeInsns(mth, hb, blocks, bs);
if (removeInfo != null) {
removes.add(removeInfo);
break;
}
}
}
if (removes.size() != tryBlock.getHandlersCount() - 1) {
return false;
}
}
for (ExceptionHandler otherHandler : tryBlock.getHandlers()) {
SplitterBlockAttr splitterAttr = otherHandler.getHandlerBlock().get(AType.SPLITTER_BLOCK);
if (splitterAttr != null) {
BlockNode splBlock = splitterAttr.getBlock();
if (!splBlock.getCleanSuccessors().isEmpty()) {
splitters.add(splBlock);
}
}
}
// remove 'finally' from 'try' blocks (dominated by splitter block)
boolean removed = false;
for (BlockNode splitter : splitters) {
BlockNode start = splitter.getCleanSuccessors().get(0);
List<BlockNode> list = BlockUtils.collectBlocksDominatedBy(splitter, start);
for (BlockNode block : list) {
if (bs.get(block.getId())) {
continue;
}
BlocksRemoveInfo removeInfo = removeInsns(mth, block, blocks, bs);
if (removeInfo != null) {
removes.add(removeInfo);
removed = true;
break;
}
}
}
if (!removed) {
return false;
}
// 'finally' extract confirmed, run remove steps
LiveVarAnalysis laBefore = null;
boolean runReMap = isReMapNeeded(removes);
if (runReMap) {
laBefore = new LiveVarAnalysis(mth);
laBefore.runAnalysis();
}
for (BlocksRemoveInfo removeInfo : removes) {
if (!applyRemove(mth, removeInfo)) {
return false;
}
}
LiveVarAnalysis laAfter = null;
// remove 'move-exception' instruction
BlockNode handlerBlock = handler.getHandlerBlock();
InsnNode me = BlockUtils.getLastInsn(handlerBlock);
if (me != null && me.getType() == InsnType.MOVE_EXCEPTION) {
boolean replaced = false;
List<InsnNode> insnsList = handlerBlock.getInstructions();
if (!handlerBlock.getCleanSuccessors().isEmpty()) {
laAfter = new LiveVarAnalysis(mth);
laAfter.runAnalysis();
RegisterArg resArg = me.getResult();
BlockNode succ = handlerBlock.getCleanSuccessors().get(0);
if (laAfter.isLive(succ, resArg.getRegNum())) {
// kill variable
InsnNode kill = new InsnNode(InsnType.NOP, 0);
kill.setResult(resArg);
kill.add(AFlag.REMOVE);
insnsList.set(insnsList.size() - 1, kill);
replaced = true;
}
}
if (!replaced) {
insnsList.remove(insnsList.size() - 1);
handlerBlock.add(AFlag.SKIP);
}
}
// generate 'move' instruction for mapped register pairs
if (runReMap) {
if (laAfter == null) {
laAfter = new LiveVarAnalysis(mth);
laAfter.runAnalysis();
}
performVariablesReMap(mth, removes, laBefore, laAfter);
}
handler.setFinally(true);
return true;
}
use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.
the class BlockFinallyExtract method isStartBlock.
/**
* 'Finally' instructions can start in the middle of the first block.
*/
private static BlocksRemoveInfo isStartBlock(BlockNode remBlock, BlockNode startBlock) {
List<InsnNode> remInsns = remBlock.getInstructions();
List<InsnNode> startInsns = startBlock.getInstructions();
if (remInsns.size() < startInsns.size()) {
return null;
}
// first - fast check
int startPos = remInsns.size() - startInsns.size();
int endPos = 0;
if (!checkInsns(remInsns, startInsns, startPos, null)) {
if (checkInsns(remInsns, startInsns, 0, null)) {
startPos = 0;
endPos = startInsns.size();
} else {
boolean found = false;
for (int i = 1; i < startPos; i++) {
if (checkInsns(remInsns, startInsns, i, null)) {
startPos = i;
endPos = startInsns.size() + i;
found = true;
break;
}
}
if (!found) {
return null;
}
}
}
BlocksPair startPair = new BlocksPair(remBlock, startBlock);
BlocksRemoveInfo removeInfo = new BlocksRemoveInfo(startPair);
removeInfo.setStartSplitIndex(startPos);
removeInfo.setEndSplitIndex(endPos);
if (endPos != 0) {
removeInfo.setEnd(startPair);
}
// second - run checks again for collect registers mapping
if (!checkInsns(remInsns, startInsns, startPos, removeInfo)) {
return null;
}
return removeInfo;
}
use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.
the class BlockFinallyExtract method removeInsns.
private static BlocksRemoveInfo removeInsns(MethodNode mth, BlockNode remBlock, List<BlockNode> blocks, BitSet bs) {
if (blocks.isEmpty()) {
return null;
}
BlockNode startBlock = blocks.get(0);
BlocksRemoveInfo removeInfo = checkFromFirstBlock(remBlock, startBlock, bs);
if (removeInfo == null) {
return null;
}
Set<BlocksPair> outs = removeInfo.getOuts();
if (outs.size() == 1) {
return removeInfo;
}
// check if several 'return' blocks maps to one out
if (mergeReturns(mth, outs)) {
return removeInfo;
}
LOG.debug("Unexpected finally block outs count: {}", outs);
return null;
}
use of jadx.core.dex.visitors.blocksmaker.helpers.BlocksRemoveInfo in project jadx by skylot.
the class BlockFinallyExtract method performVariablesReMap.
private static void performVariablesReMap(MethodNode mth, List<BlocksRemoveInfo> removes, LiveVarAnalysis laBefore, LiveVarAnalysis laAfter) {
BitSet processed = new BitSet(mth.getRegsCount());
for (BlocksRemoveInfo removeInfo : removes) {
processed.clear();
BlocksPair start = removeInfo.getStart();
BlockNode insertBlockBefore = start.getFirst();
BlockNode insertBlock = start.getSecond();
if (removeInfo.getRegMap().isEmpty() || insertBlock == null) {
continue;
}
for (Map.Entry<RegisterArg, RegisterArg> entry : removeInfo.getRegMap().entrySet()) {
RegisterArg fromReg = entry.getKey();
RegisterArg toReg = entry.getValue();
int fromRegNum = fromReg.getRegNum();
int toRegNum = toReg.getRegNum();
if (!processed.get(fromRegNum)) {
boolean liveFromBefore = laBefore.isLive(insertBlockBefore, fromRegNum);
boolean liveFromAfter = laAfter.isLive(insertBlock, fromRegNum);
// boolean liveToBefore = laBefore.isLive(insertBlock, toRegNum);
boolean liveToAfter = laAfter.isLive(insertBlock, toRegNum);
if (liveToAfter && liveFromBefore) {
// merge 'to' and 'from' registers
InsnNode merge = new InsnNode(InsnType.MERGE, 2);
merge.setResult(toReg.duplicate());
merge.addArg(toReg.duplicate());
merge.addArg(fromReg.duplicate());
injectInsn(mth, insertBlock, merge);
} else if (liveFromBefore) {
// remap variable
InsnNode move = new InsnNode(InsnType.MOVE, 1);
move.setResult(toReg.duplicate());
move.addArg(fromReg.duplicate());
injectInsn(mth, insertBlock, move);
} else if (liveFromAfter) {
// kill variable
InsnNode kill = new InsnNode(InsnType.NOP, 0);
kill.setResult(fromReg.duplicate());
kill.add(AFlag.REMOVE);
injectInsn(mth, insertBlock, kill);
}
processed.set(fromRegNum);
}
}
}
}
Aggregations