private void optimize() { // SSS FIXME: Can't we not add some of these exception edges in the first place?? // Remove exception edges from blocks that couldn't possibly thrown an exception! List<Edge> toRemove = new ArrayList<Edge>(); for (BasicBlock b : graph.allData()) { boolean noExceptions = true; for (Instr i : b.getInstrs()) { if (i.canRaiseException()) { noExceptions = false; break; } } if (noExceptions) { for (Edge<BasicBlock> e : graph.vertexFor(b).getOutgoingEdgesOfType(EdgeType.EXCEPTION)) { BasicBlock source = e.getSource().getData(); BasicBlock destination = e.getDestination().getData(); toRemove.add(e); if (rescuerMap.get(source) == destination) rescuerMap.remove(source); if (ensurerMap.get(source) == destination) ensurerMap.remove(source); } } } if (!toRemove.isEmpty()) { for (Edge edge : toRemove) { graph.removeEdge(edge); } } deleteOrphanedBlocks(graph); }
public BasicBlock cloneForInlining(InlinerInfo ii) { BasicBlock clonedBB = ii.getOrCreateRenamedBB(this); for (Instr i : getInstrs()) { Instr clonedInstr = i.cloneForInlining(ii); if (clonedInstr != null) { clonedBB.addInstr(clonedInstr); if (clonedInstr instanceof YieldInstr) ii.recordYieldSite(clonedBB, (YieldInstr) clonedInstr); } } return clonedBB; }
void removeBB(BasicBlock b) { graph.removeVertexFor(b); bbMap.remove(b.getLabel()); rescuerMap.remove(b); ensurerMap.remove(b); // SSS FIXME: Patch up rescued regions as well?? }
public void setupYieldArgsAndYieldResult(YieldInstr yi, BasicBlock yieldBB, Arity blockArity) { int blockArityValue = blockArity.getValue(); Operand yieldInstrArg = yi.getYieldArg(); if ((yieldInstrArg == UndefinedValue.UNDEFINED) || (blockArityValue == 0)) { this.yieldArg = new Array(); // Zero-elt array } else if (yieldInstrArg instanceof Array) { this.yieldArg = yieldInstrArg; // 1:1 arg match if (((Array) yieldInstrArg).size() == blockArityValue) canMapArgsStatically = true; } else { // SSS FIXME: The code below is not entirely correct. We have to process 'yi.getYieldArg()' // similar // to how InterpretedIRBlockBody (1.8 and 1.9 modes) processes it. We may need a special // instruction // that takes care of aligning the stars and bringing good fortune to arg yielder and arg // receiver. IRScope callerScope = getInlineHostScope(); boolean needSpecialProcessing = (blockArityValue != -1) && (blockArityValue != 1); Variable yieldArgArray = callerScope.getNewTemporaryVariable(); yieldBB.addInstr( new ToAryInstr(yieldArgArray, yieldInstrArg, callerScope.getManager().getTrue())); this.yieldArg = yieldArgArray; } this.yieldResult = yi.getResult(); }
public BasicBlock getOrCreateRenamedBB(BasicBlock bb) { BasicBlock renamedBB = getRenamedBB(bb); if (renamedBB == null) { renamedBB = new BasicBlock(this.callerCFG, getRenamedLabel(bb.getLabel())); bbRenameMap.put(bb, renamedBB); } return renamedBB; }
public String toStringInstrs() { StringBuilder buf = new StringBuilder(); for (BasicBlock b : getSortedBasicBlocks()) { buf.append(b.toStringInstrs()); } buf.append("\n\n------ Rescue block map ------\n"); for (BasicBlock bb : rescuerMap.keySet()) { buf.append("BB ") .append(bb.getID()) .append(" --> BB ") .append(rescuerMap.get(bb).getID()) .append("\n"); } buf.append("\n\n------ Ensure block map ------\n"); for (BasicBlock bb : ensurerMap.keySet()) { buf.append("BB ") .append(bb.getID()) .append(" --> BB ") .append(ensurerMap.get(bb).getID()) .append("\n"); } List<IRClosure> closures = scope.getClosures(); if (!closures.isEmpty()) { buf.append("\n\n------ Closures encountered in this scope ------\n"); for (IRClosure c : closures) { buf.append(c.toStringBody()); } buf.append("------------------------------------------------\n"); } return buf.toString(); }
public BasicBlock splitAtInstruction( Instr splitPoint, Label newLabel, boolean includeSplitPointInstr) { BasicBlock newBB = new BasicBlock(_cfg, newLabel); int idx = 0; int numInstrs = _instrs.size(); boolean found = false; for (Instr i : _instrs) { if (i == splitPoint) found = true; // Move instructions from split point into the new bb if (found) { if (includeSplitPointInstr || i != splitPoint) newBB.addInstr(i); } else { idx++; } } // Remove all instructions from current bb that were moved over. for (int j = 0; j < numInstrs - idx; j++) _instrs.remove(idx); return newBB; }
@Override public String toString() { StringBuilder buf = new StringBuilder("Vertex "); buf.append(basicBlock.getID()).append(":\nincoming edges\n"); for (Edge edge : getIncomingEdges()) { buf.append(edge).append("\n"); } buf.append("outgoing edges\n"); for (Edge edge : getOutgoingEdges()) { buf.append(edge).append("\n"); } return buf.toString(); }
private LinkedList<BasicBlock> buildPostOrderList() { LinkedList<BasicBlock> list = new LinkedList<BasicBlock>(); BasicBlock root = getEntryBB(); Stack<BasicBlock> stack = new Stack<BasicBlock>(); stack.push(root); BitSet bbSet = new BitSet(1 + getMaxNodeID()); bbSet.set(root.getID()); // Non-recursive post-order traversal (the added flag is required to handle cycles and common // ancestors) while (!stack.empty()) { // Check if all children of the top of the stack have been added BasicBlock b = stack.peek(); boolean allChildrenDone = true; for (BasicBlock dst : getOutgoingDestinations(b)) { int dstID = dst.getID(); if (!bbSet.get(dstID)) { allChildrenDone = false; stack.push(dst); bbSet.set(dstID); } } // If all children have been added previously, we are ready with 'b' in this round! if (allChildrenDone) { stack.pop(); list.add(b); } } // Sanity check! for (BasicBlock b : getBasicBlocks()) { if (!bbSet.get(b.getID())) { printError("BB " + b.getID() + " missing from po list!"); break; } } return list; }
/** Build the Control Flow Graph */ public DirectedGraph<BasicBlock> build(List<Instr> instrs) { // Map of label & basic blocks which are waiting for a bb with that label Map<Label, List<BasicBlock>> forwardRefs = new HashMap<Label, List<BasicBlock>>(); // Map of return address variable and all possible targets (required to connect up ensure blocks // with their targets) Map<Variable, Set<Label>> retAddrMap = new HashMap<Variable, Set<Label>>(); Map<Variable, BasicBlock> retAddrTargetMap = new HashMap<Variable, BasicBlock>(); // List of bbs that have a 'return' instruction List<BasicBlock> returnBBs = new ArrayList<BasicBlock>(); // List of bbs that have a 'throw' instruction List<BasicBlock> exceptionBBs = new ArrayList<BasicBlock>(); // Stack of nested rescue regions Stack<ExceptionRegion> nestedExceptionRegions = new Stack<ExceptionRegion>(); // List of all rescued regions List<ExceptionRegion> allExceptionRegions = new ArrayList<ExceptionRegion>(); // Dummy entry basic block (see note at end to see why) entryBB = createBB(nestedExceptionRegions); // First real bb BasicBlock firstBB = createBB(nestedExceptionRegions); // Build the rest! BasicBlock currBB = firstBB; BasicBlock newBB = null; boolean bbEnded = false; boolean nextBBIsFallThrough = true; for (Instr i : instrs) { Operation iop = i.getOperation(); if (iop == Operation.LABEL) { Label l = ((LabelInstr) i).label; newBB = createBB(l, nestedExceptionRegions); // Jump instruction bbs dont add an edge to the succeeding bb by default if (nextBBIsFallThrough) graph.addEdge(currBB, newBB, EdgeType.FALL_THROUGH); currBB = newBB; bbEnded = false; nextBBIsFallThrough = true; // Add forward reference edges List<BasicBlock> frefs = forwardRefs.get(l); if (frefs != null) { for (BasicBlock b : frefs) { graph.addEdge(b, newBB, EdgeType.REGULAR); } } } else if (bbEnded && (iop != Operation.EXC_REGION_END)) { newBB = createBB(nestedExceptionRegions); // Jump instruction bbs dont add an edge to the succeeding bb by default if (nextBBIsFallThrough) graph.addEdge(currBB, newBB, EdgeType.FALL_THROUGH); // currBB cannot be null! currBB = newBB; bbEnded = false; nextBBIsFallThrough = true; } if (i instanceof ExceptionRegionStartMarkerInstr) { // SSS: Do we need this anymore? // currBB.addInstr(i); ExceptionRegionStartMarkerInstr ersmi = (ExceptionRegionStartMarkerInstr) i; ExceptionRegion rr = new ExceptionRegion(ersmi.firstRescueBlockLabel, ersmi.ensureBlockLabel); rr.addBB(currBB); allExceptionRegions.add(rr); if (nestedExceptionRegions.empty()) { outermostERs.add(rr); } else { nestedExceptionRegions.peek().addNestedRegion(rr); } nestedExceptionRegions.push(rr); } else if (i instanceof ExceptionRegionEndMarkerInstr) { // SSS: Do we need this anymore? // currBB.addInstr(i); nestedExceptionRegions.pop().setEndBB(currBB); } else if (iop.endsBasicBlock()) { bbEnded = true; currBB.addInstr(i); Label tgt; nextBBIsFallThrough = false; if (i instanceof BranchInstr) { tgt = ((BranchInstr) i).getJumpTarget(); nextBBIsFallThrough = true; } else if (i instanceof JumpInstr) { tgt = ((JumpInstr) i).getJumpTarget(); } else if (iop.isReturn()) { // BREAK, RETURN, CLOSURE_RETURN tgt = null; returnBBs.add(currBB); } else if (i instanceof ThrowExceptionInstr) { tgt = null; exceptionBBs.add(currBB); } else if (i instanceof JumpIndirectInstr) { tgt = null; Set<Label> retAddrs = retAddrMap.get(((JumpIndirectInstr) i).getJumpTarget()); for (Label l : retAddrs) { addEdge(currBB, l, forwardRefs); } // Record the target bb for the retaddr var for any set_addr instrs that appear later and // use the same retaddr var retAddrTargetMap.put(((JumpIndirectInstr) i).getJumpTarget(), currBB); } else { throw new RuntimeException( "Unhandled case in CFG builder for basic block ending instr: " + i); } if (tgt != null) addEdge(currBB, tgt, forwardRefs); } else if (iop != Operation.LABEL) { currBB.addInstr(i); } if (i instanceof SetReturnAddressInstr) { Variable v = i.getResult(); Label tgtLbl = ((SetReturnAddressInstr) i).getReturnAddr(); BasicBlock tgtBB = retAddrTargetMap.get(v); // If we have the target bb, add the edge // If not, record it for fixup later if (tgtBB != null) { addEdge(tgtBB, tgtLbl, forwardRefs); } else { Set<Label> addrs = retAddrMap.get(v); if (addrs == null) { addrs = new HashSet<Label>(); retAddrMap.put(v, addrs); } addrs.add(tgtLbl); } } else if (i instanceof CallInstr) { // Build CFG for the closure if there exists one Operand closureArg = ((CallInstr) i).getClosureArg(); if (closureArg instanceof MetaObject) { ((IRClosure) ((MetaObject) closureArg).scope).buildCFG(); } } } // Process all rescued regions for (ExceptionRegion rr : allExceptionRegions) { BasicBlock firstRescueBB = bbMap.get(rr.getFirstRescueBlockLabel()); // 1. Tell the region that firstRescueBB is its protector! rr.setFirstRescueBB(firstRescueBB); // 2. Record a mapping from the region's exclusive basic blocks to the first bb that will // start exception handling for all their exceptions. // 3. Add an exception edge from every exclusive bb of the region to firstRescueBB BasicBlock ensureBlockBB = rr.getEnsureBlockLabel() == null ? null : bbMap.get(rr.getEnsureBlockLabel()); for (BasicBlock b : rr.getExclusiveBBs()) { rescuerMap.put(b, firstRescueBB); graph.addEdge(b, firstRescueBB, EdgeType.EXCEPTION); if (ensureBlockBB != null) { ensurerMap.put(b, ensureBlockBB); // SSS FIXME: This is a conservative edge because when a rescue block is present // that catches an exception, control never reaches the ensure block directly. // Only when we get an error or threadkill even, or when breaks propagate upward // do we need to hit an ensure directly. This edge is present to account for that // control-flow scneario. graph.addEdge(b, ensureBlockBB, EdgeType.EXCEPTION); } } } buildExitBasicBlock( nestedExceptionRegions, firstBB, returnBBs, exceptionBBs, nextBBIsFallThrough, currBB, entryBB); optimize(); // remove useless cfg edges & orphaned bbs return graph; }