Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.jruby.ir.transformations.inlining;
  
  import java.util.Set;
  import java.util.List;
  import java.util.HashSet;
  
 
 public class CFGInliner {
     private CFG cfg;
     
     public CFGInliner(CFG build) {
         this. = build;
     }
 
     private CFG cloneSelf(InlinerInfo ii) {
         CFG selfClone = new CFG(.getScope());
 
         // clone bbs
         BasicBlock entry = .getEntryBB();
         BasicBlock exit = .getExitBB();
         for (BasicBlock b : .getBasicBlocks()) {
             if ((b != entry) && (b != exit)) {
                 selfClone.addBasicBlock(b.cloneForInlinedMethod(ii));
             }
         }
 
         // clone edges
         for (BasicBlock b.getBasicBlocks()) {
             if ((b != entry) && (b != exit)) {
                 BasicBlock rb = ii.getRenamedBB(b);
                 for (Edge<BasicBlocke : .getOutgoingEdges(b)) {
                     BasicBlock destination = e.getDestination().getData();
                     if (destination != exitselfClone.addEdge(rbii.getRenamedBB(destination), e.getType());
                 }
             }
         }
 
         return selfClone;
     }
 
     public void inlineMethod(IRScope scopeRubyModule implClassint classTokenBasicBlock callBBCallBase call) {
         // Temporarily turn off inlining of recursive methods
         // Conservative turning off for inlining of a method in a closure nested within the same method
         IRScope hostScope = .getScope();
         if (hostScope.getNearestMethod() == scopereturn;
 
 /*
         System.out.println("host cfg   :" + cfg.toStringGraph());
         System.out.println("host instrs:" + cfg.toStringInstrs());
         System.out.println("source cfg   :" + scope.getCFG().toStringGraph());
         System.out.println("source instrs:" + scope.getCFG().toStringInstrs());
 */
 
         // Host method data init
         InlinerInfo ii = new InlinerInfo(call);
         Label splitBBLabel = hostScope.getNewLabel();
         BasicBlock splitBB;
 
         // Inlinee method data init
         CFG methodCFG = scope.getCFG();
         BasicBlock mEntry = methodCFG.getEntryBB();
         BasicBlock mExit = methodCFG.getExitBB();
         List<BasicBlockmethodBBs = new ArrayList<BasicBlock>();
         for (BasicBlock bmethodCFG.getBasicBlocks()) methodBBs.add(b);
 
         // Check if we are inlining a recursive method
         if (hostScope.getNearestMethod() == scope) {
             // 1. clone self
             // SSS: FIXME: We need a clone-graph api method in cfg and graph
             CFG selfClone = cloneSelf(ii);
 
             // 2. add callee bbs and their edges
             // SSS: FIXME: We need a swallow-graph api method in cfg and graph
             for (BasicBlock b : selfClone.getBasicBlocks()) {
                 .addBasicBlock(b);
                 for (Edge<BasicBlocke : selfClone.getOutgoingEdges(b)) {
                     .addEdge(be.getDestination().getData(), e.getType());
                 }
             }
        } else {
            // 2. clone callee and add it to the host cfg
            for (BasicBlock b : methodCFG.getBasicBlocks()) {
                if (b != mEntry && b != mExit) {
                    .addBasicBlock(b.cloneForInlinedMethod(ii));
                }
            }
            for (BasicBlock x : methodCFG.getBasicBlocks()) {
                if (x != mEntry && x != mExit) {
                    BasicBlock rx = ii.getRenamedBB(x);
                    for (Edge<BasicBlocke : methodCFG.getOutgoingEdges(x)) {
                        BasicBlock b = e.getDestination().getData();
                        if (b != mExit.addEdge(rxii.getRenamedBB(b), e.getType());
                    }
                }
            }
        }
        // 3. split callsite bb, move outbound edges from callsite bb to split bb, and unhook call bb
        splitBB = callBB.splitAtInstruction(callsplitBBLabelfalse);
        .addBasicBlock(splitBB);
        for (Edge<BasicBlocke : .getOutgoingEdges(callBB)) {
            .addEdge(splitBBe.getDestination().getData(), e.getType());
        }
        .removeAllOutgoingEdgesForBB(callBB);
        // 4a. Hook up entry edges
        assert methodCFG.outDegree(mEntry) == 2: "Entry BB of inlinee method does not have outdegree 2: " + methodCFG.toStringGraph();
        for (Edge<BasicBlocke : methodCFG.getOutgoingEdges(mEntry)) {
            BasicBlock destination = e.getDestination().getData();
            if (destination != mExit) {
                BasicBlock dstBB = ii.getRenamedBB(destination);
                if (!ii.canMapArgsStatically()) {
                    dstBB.addInstr(new ToAryInstr((Variable)ii.getArgs(), new Array(call.getCallArgs()), .getScope().getManager().getTrue()));
                }
                .addEdge(callBBdstBB..);
            }
        }
        // 4b. Hook up exit edges
        for (Edge<BasicBlocke : methodCFG.getIncomingEdges(mExit)) {
            BasicBlock source = e.getSource().getData();
            if (source != mEntry) {
                BasicBlock clonedSource = ii.getRenamedBB(source);
                if (e.getType() == .) {
                    // e._src has an explicit throw that returns from the callee
                    // after inlining, if the caller instruction has a rescuer, then the
                    // throw has to be captured by the rescuer as well.
                    BasicBlock rescuerOfSplitBB = .getRescuerBBFor(splitBB);
                    if (rescuerOfSplitBB != null) {
                        .addEdge(clonedSourcerescuerOfSplitBB.);
                    } else {
                        .addEdge(clonedSource.getExitBB(), .);                        
                    }
                } else {
                    .addEdge(clonedSourcesplitBBe.getType());
                }
            }
        }
        // SSS FIXME: Are these used anywhere post-CFG building?
        // 5. Clone exception regions
        List<ExceptionRegionexceptionRegions = .getOutermostExceptionRegions();
        for (ExceptionRegion r : methodCFG.getOutermostExceptionRegions()) {
            exceptionRegions.add(r.cloneForInlining(ii));
        }
        // 6. Update bb rescuer map
        // 6a. splitBB will be protected by the same bb as callBB
        BasicBlock callBBrescuer = .getRescuerBBFor(callBB);
        if (callBBrescuer != null.setRescuerBB(splitBBcallBBrescuer);
        BasicBlock callBBensurer = .getEnsurerBBFor(callBB);
        if (callBBensurer != null.setEnsurerBB(splitBBcallBBensurer);
        // 6b. remap existing protections for bbs in mcfg to their renamed bbs.
        // 6c. bbs in mcfg that aren't protected by an existing bb will be protected by callBBrescuer.
        for (BasicBlock x : methodBBs) {
            if (x != mEntry && x != mExit) {
                BasicBlock xRenamed = ii.getRenamedBB(x);
                BasicBlock xProtector = methodCFG.getRescuerBBFor(x);
                if (xProtector != null) {
                    .setRescuerBB(xRenamedii.getRenamedBB(xProtector));
                } else if (callBBrescuer != null) {
                    .setRescuerBB(xRenamedcallBBrescuer);
                }
                BasicBlock xEnsurer = methodCFG.getEnsurerBBFor(x);
                if (xEnsurer != null) {
                    .setEnsurerBB(xRenamedii.getRenamedBB(xEnsurer));
                } else if (callBBensurer != null) {
                    .setEnsurerBB(xRenamedcallBBensurer);
                }
            }
        }
        // 7. Add inline guard that verifies that the method inlined is the same 
        // that gets called in future invocations.  In addition to the guard, add 
        // a failure path code.
        Label failurePathLabel = hostScope.getNewLabel();
        callBB.addInstr(new ModuleVersionGuardInstr(implClassclassTokencall.getReceiver(), failurePathLabel));
        BasicBlock failurePathBB = new BasicBlock(failurePathLabel);
        .addBasicBlock(failurePathBB);
        failurePathBB.addInstr(call);
        failurePathBB.addInstr(new JumpInstr(splitBBLabel));
        call.blockInlining();
        .addEdge(callBBfailurePathBB..);
        .addEdge(failurePathBBsplitBB..);
        // 8. Inline any closure argument passed into the call.
        Operand closureArg = call.getClosureArg(null);
        List yieldSites = ii.getYieldSites();
        if (closureArg != null && !yieldSites.isEmpty()) {
            // Detect unlikely but contrived scenarios where there are far too many yield sites that could lead to code blowup
            // if we inline the closure at all those yield sites!
            if (yieldSites.size() > 1) {
                throw new RuntimeException("Encountered " + yieldSites.size() + " yield sites.  Convert the yield to a call by converting the closure into a dummy method (have to convert all frame vars to call arguments, or at least convert the frame into a call arg");
            }
            if (!(closureArg instanceof WrappedIRClosure)) {
                throw new RuntimeException("Encountered a dynamic closure arg.  Cannot inline it here!  Convert the yield to a call by converting the closure into a dummy method (have to convert all frame vars to call arguments, or at least convert the frame into a call arg");
            }
            Tuple t = (TupleyieldSites.get(0);
            inlineClosureAtYieldSite(ii, ((WrappedIRClosureclosureArg).getClosure(), (BasicBlockt.a, (YieldInstrt.b);
        }
        // 9. Optimize cfg by merging straight-line bbs
        .collapseStraightLineBBs();
/*
        System.out.println("final cfg   :" + cfg.toStringGraph());
        System.out.println("final instrs:" + cfg.toStringInstrs());
*/
    }
    private void inlineClosureAtYieldSite(InlinerInfo iiIRClosure clBasicBlock yieldBBYieldInstr yield) {
        // 1. split yield site bb and move outbound edges from yield site bb to split bb.
        BasicBlock splitBB = yieldBB.splitAtInstruction(yield.getScope().getNewLabel(), false);
        .addBasicBlock(splitBB);
        for (Edge<BasicBlocke : .getOutgoingEdges(yieldBB)) {
            .addEdge(splitBBe.getDestination().getData(), e.getType());
        }
        .removeAllOutgoingEdgesForBB(yieldBB);
        // Allocate new inliner object to reset variable and label rename maps
        ii = ii.cloneForInliningClosure();
        ii.setupYieldArgsAndYieldResult(yieldyieldBBcl.getBlockBody().arity());
        // 2. Merge closure cfg into the current cfg
        CFG closureCFG = cl.getCFG();
        BasicBlock cEntry = closureCFG.getEntryBB();
        BasicBlock cExit = closureCFG.getExitBB();
        for (BasicBlock b : closureCFG.getBasicBlocks()) {
            if (b != cEntry && b != cExit) {
                .addBasicBlock(b.cloneForInlinedClosure(ii));
            }
        }
        for (BasicBlock b : closureCFG.getBasicBlocks()) {
            if (b != cEntry && b != cExit) {
                BasicBlock bClone = ii.getRenamedBB(b);
                for (Edge<BasicBlocke : closureCFG.getOutgoingEdges(b)) {
                    BasicBlock edst = e.getDestination().getData();
                    if (edst != cExit.addEdge(bCloneii.getRenamedBB(edst), e.getType());
                }
            }
        }
        
        // Hook up entry edges
        for (Edge<BasicBlocke : closureCFG.getOutgoingEdges(cEntry)) {
            BasicBlock destination = e.getDestination().getData();
            if (destination != cExit) {
                .addEdge(yieldBBii.getRenamedBB(destination), ..);
            }
        }
        
        // Hook up exit edges 
        for (Edge<BasicBlocke : closureCFG.getIncomingEdges(cExit)) {
            BasicBlock source = e.getSource().getData();
            if (source != cEntry) {
                BasicBlock clonedSource = ii.getRenamedBB(source);
                if (e.getType() == .) {
                    // e._src has an explicit throw that returns from the closure.
                    // After inlining, if the yield instruction has a rescuer, then the
                    // throw has to be captured by the rescuer as well.
                    BasicBlock rescuerOfSplitBB = .getRescuerBBFor(splitBB);
                    if (rescuerOfSplitBB != null) {
                        .addEdge(clonedSourcerescuerOfSplitBB.);
                    } else {
                        .addEdge(clonedSource.getExitBB(), .);
                    }
                } else {
                    .addEdge(clonedSourcesplitBBe.getType());
                }
            }
        }
        // SSS FIXME: Are these used anywhere post-CFG building?
        // 5. No need to clone rescued regions -- just assimilate them
        List<ExceptionRegionexceptionRegions = .getOutermostExceptionRegions();
        for (ExceptionRegion r : closureCFG.getOutermostExceptionRegions()) {
            exceptionRegions.add(r.cloneForInlining(ii));
        }
        // 6. Update bb rescuer map
        // 6a. splitBB will be protected by the same bb as yieldB
        BasicBlock yieldBBrescuer = .getRescuerBBFor(yieldBB);
        if (yieldBBrescuer != null.setRescuerBB(splitBByieldBBrescuer);
        BasicBlock yieldBBensurer = .getEnsurerBBFor(yieldBB);
        if (yieldBBensurer != null.setEnsurerBB(splitBByieldBBensurer);
        // 6b. remap existing protections for bbs in mcfg to their renamed bbs.
        // 6c. bbs in mcfg that aren't protected by an existing bb will be protected by yieldBBrescuer/yieldBBensurer
        for (BasicBlock cb : closureCFG.getBasicBlocks()) {
            if (cb != cEntry && cb != cExit) {
                BasicBlock cbProtector = ii.getRenamedBB(closureCFG.getRescuerBBFor(cb));
                if (cbProtector != null) {
                    .setRescuerBB(cbcbProtector);
                } else if (yieldBBrescuer != null) {
                    .setRescuerBB(cbyieldBBrescuer);
                }
                BasicBlock cbEnsurer = ii.getRenamedBB(closureCFG.getEnsurerBBFor(cb));
                if (cbEnsurer != null) {
                    .setEnsurerBB(cbcbEnsurer);
                } else if (yieldBBensurer != null) {
                    .setEnsurerBB(cbyieldBBensurer);
                }
            }
        }
    }
New to GrepCode? Check out our FAQ X