private List<BasicBlock> buildBasicBlocksSequence(BasicBlock first) { List<BasicBlock> result = new ArrayList<>(2); BasicBlock block = program.basicBlockAt(mappings[first.getIndex()]); while (previousPtr.get(block.getIndex()) != block.getIndex()) { result.add(block); block = program.basicBlockAt(previousPtr.get(block.getIndex())); } result.add(block); Collections.reverse(result); return result; }
@Override public void visit(JumpInstruction insn) { try { output.writeByte(16); output.writeShort(insn.getTarget().getIndex()); } catch (IOException e) { throw new IOExceptionWrapper(e); } }
private Variable use(Variable var) { Variable mappedVar = variableMap[var.getIndex()]; if (mappedVar == null) { throw new AssertionError("Variable used before definition: @" + var.getDisplayLabel() + " at $" + currentBlock.getIndex()); } usedPhis.set(mappedVar.getIndex()); return mappedVar; }
@Override public void visit(BranchingInstruction insn) { try { output.writeByte(14); output.writeByte(insn.getCondition().ordinal()); output.writeShort(insn.getOperand().getIndex()); output.writeShort(insn.getConsequent().getIndex()); output.writeShort(insn.getAlternative().getIndex()); } catch (IOException e) { throw new IOExceptionWrapper(e); } }
@Override public void visit(SwitchInstruction insn) { try { output.writeByte(17); output.writeShort(insn.getCondition().getIndex()); output.writeShort(insn.getDefaultTarget().getIndex()); output.writeShort(insn.getEntries().size()); for (SwitchTableEntry entry : insn.getEntries()) { output.writeInt(entry.getCondition()); output.writeShort(entry.getTarget().getIndex()); } } catch (IOException e) { throw new IOExceptionWrapper(e); } }
Statement generateJumpStatement(BasicBlock target) { if (nextBlock == target && blockMap[target.getIndex()] == null) { return null; } Decompiler.Block block = blockMap[target.getIndex()]; if (block == null) { throw new IllegalStateException("Could not find block for basic block $" + target.getIndex()); } if (target.getIndex() == indexer.nodeAt(block.end)) { BreakStatement breakStmt = new BreakStatement(); breakStmt.setLocation(currentLocation); breakStmt.setTarget(block.statement); return breakStmt; } else { ContinueStatement contStmt = new ContinueStatement(); contStmt.setLocation(currentLocation); contStmt.setTarget(block.statement); return contStmt; } } private Statement generateJumpStatement(SwitchStatement stmt, int target) {
@Override public void visit(BinaryBranchingInstruction insn) { try { output.writeByte(15); output.writeByte(insn.getCondition().ordinal()); output.writeShort(insn.getFirstOperand().getIndex()); output.writeShort(insn.getSecondOperand().getIndex()); output.writeShort(insn.getConsequent().getIndex()); output.writeShort(insn.getAlternative().getIndex()); } catch (IOException e) { throw new IOExceptionWrapper(e); } }
private void markAssignment(Variable var) { Deque<BasicBlock> worklist = new ArrayDeque<>(); worklist.push(currentBlock); if (variableDefined[var.getIndex()]) { for (TryCatchBlock tryCatch : currentBlock.getTryCatchBlocks()) { placePhi(tryCatch.getHandler().getIndex(), var, currentBlock, worklist); } } else { variableDefined[var.getIndex()] = true; } while (!worklist.isEmpty()) { BasicBlock block = worklist.pop(); int[] frontiers = domFrontiers[block.getIndex()]; if (frontiers != null) { for (int frontier : frontiers) { placePhi(frontier, var, block, worklist); } } } }
private BitSet getUsedVarsInBlock(LivenessAnalyzer liveness, BasicBlock block) { BitSet usedVars = new BitSet(); TransitionExtractor transitionExtractor = new TransitionExtractor(); block.getLastInstruction().acceptVisitor(transitionExtractor); for (BasicBlock successor : transitionExtractor.getTargets()) { usedVars.or(liveness.liveIn(successor.getIndex())); } for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { usedVars.or(liveness.liveIn(tryCatch.getHandler().getIndex())); } return usedVars; }
private void createNewBookmarks(List<TryCatchBlock> tryCatchBlocks) { // Add new bookmarks for (int i = tryCatchBookmarks.size(); i < tryCatchBlocks.size(); ++i) { TryCatchBlock tryCatch = tryCatchBlocks.get(tryCatchBlocks.size() - 1 - i); TryCatchBookmark bookmark = new TryCatchBookmark(); bookmark.block = stack.peek(); bookmark.offset = bookmark.block.body.size(); bookmark.exceptionHandler = tryCatch.getHandler().getIndex(); bookmark.exceptionType = tryCatch.getExceptionType(); bookmark.exceptionVariable = tryCatch.getHandler().getExceptionVariable() != null ? tryCatch.getHandler().getExceptionVariable().getIndex() : null; bookmark.block.tryCatches.add(bookmark); tryCatchBookmarks.add(bookmark); } }
/** * Original head becomes start of `if (condition)`, it's not loop head anymore. * Hence we don't need phi inputs that come from back edges. */ private void removeInternalPhiInputsFromCondition() { BasicBlock block = program.basicBlockAt(head); for (Phi phi : block.getPhis()) { List<Incoming> incomings = phi.getIncomings(); for (int i = 0; i < incomings.size(); ++i) { Incoming incoming = incomings.get(i); if (nodes.contains(incoming.getSource().getIndex())) { incomings.remove(i--); } } } }
private boolean isTrivialBlock(BasicBlock block) { if (exceptionHandlers[block.getIndex()]) { return false; } if (block.instructionCount() != 1 || block.getExceptionVariable() != null) { return false; } Instruction instruction = block.getLastInstruction(); return instruction instanceof JumpInstruction || instruction instanceof BranchingInstruction || instruction instanceof BinaryBranchingInstruction; }
public static List<List<Incoming>> getPhiOutputs(Program program) { List<List<Incoming>> outputs = new ArrayList<>(program.basicBlockCount()); for (int i = 0; i < program.basicBlockCount(); ++i) { outputs.add(new ArrayList<>()); } for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); for (Phi phi : block.getPhis()) { for (Incoming incoming : phi.getIncomings()) { outputs.get(incoming.getSource().getIndex()).add(incoming); } } } return outputs; }
/** * Head copy is not a loop head anymore and there aren't transition from outside of former loop, * therefore delete all external phi inputs. */ private void removeExternalPhiInputsFromConditionCopy() { BasicBlock block = program.basicBlockAt(headCopy); for (Phi phi : block.getPhis()) { List<Incoming> incomings = phi.getIncomings(); for (int i = 0; i < incomings.size(); ++i) { Incoming incoming = incomings.get(i); if (!nodesAndCopies.contains(incoming.getSource().getIndex())) { incomings.remove(i--); } } } } }
public BasicBlockMapper(IntUnaryOperator mapFunction) { this((BasicBlock block) -> block.getProgram().basicBlockAt(mapFunction.applyAsInt(block.getIndex()))); }
@Override public void visit(RaiseInstruction insn) { exceptions.add(insn.getException().getIndex()); exceptions.add(currentBlock.getIndex()); }
private void fillExceptionHandlers(Program program) { exceptionHandlers = new boolean[program.basicBlockCount()]; for (int i = 0; i < exceptionHandlers.length; ++i) { BasicBlock block = program.basicBlockAt(i); for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { exceptionHandlers[tryCatch.getHandler().getIndex()] = true; } } }
private Variable applySigmaRename(BasicBlock target, Variable var) { Sigma[] blockSigmas = sigmas[currentBlock.getIndex()]; if (blockSigmas == null) { return var; } for (Sigma sigma : blockSigmas) { if (sigma.getValue() != var) { continue; } for (Outgoing outgoing : sigma.getOutgoings()) { if (outgoing.getTarget() == target) { return outgoing.getValue(); } } } return var; }
private void copyBasicBlocks(IntSet nodesToCopy) { int[] nodes = this.nodes.toArray(); Arrays.sort(nodes); for (int node : nodes) { nodesAndCopies.add(node); if (nodesToCopy.contains(node)) { int copy = program.createBasicBlock().getIndex(); if (head == node) { headCopy = copy; } copiedNodes.put(node, copy); nodesAndCopies.add(copy); } } }
public static Graph buildControlFlowGraph(Program program) { GraphBuilder graphBuilder = new GraphBuilder(program.basicBlockCount()); TransitionExtractor transitionExtractor = new TransitionExtractor(); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); Instruction insn = block.getLastInstruction(); if (insn != null) { insn.acceptVisitor(transitionExtractor); if (transitionExtractor.getTargets() != null) { for (BasicBlock successor : transitionExtractor.getTargets()) { graphBuilder.addEdge(i, successor.getIndex()); } } } for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { graphBuilder.addEdge(i, tryCatch.getHandler().getIndex()); } } return graphBuilder.build(); }