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 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; }
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; }
/** 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; }