// Allocate new inliner object to reset variable and label rename maps
ii = ii.cloneForInliningClosure();
ii.setupYieldArgsAndYieldResult(yield, yieldBB, cl.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) {
cfg.addBasicBlock(b.cloneForInlinedClosure(ii));
}
}
for (BasicBlock b : closureCFG.getBasicBlocks()) {
if (b != cEntry && b != cExit) {
BasicBlock bClone = ii.getRenamedBB(b);
for (Edge<BasicBlock> e : closureCFG.getOutgoingEdges(b)) {
BasicBlock edst = e.getDestination().getData();
if (edst != cExit) cfg.addEdge(bClone, ii.getRenamedBB(edst), e.getType());
}
}
}
// Hook up entry edges
for (Edge<BasicBlock> e : closureCFG.getOutgoingEdges(cEntry)) {
BasicBlock destination = e.getDestination().getData();
if (destination != cExit) {
cfg.addEdge(yieldBB, ii.getRenamedBB(destination), CFG.EdgeType.FALL_THROUGH);
}
}
// Hook up exit edges
for (Edge<BasicBlock> e : closureCFG.getIncomingEdges(cExit)) {
BasicBlock source = e.getSource().getData();
if (source != cEntry) {
BasicBlock clonedSource = ii.getRenamedBB(source);
if (e.getType() == EdgeType.EXCEPTION) {
// 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 = cfg.getRescuerBBFor(splitBB);
if (rescuerOfSplitBB != null) {
cfg.addEdge(clonedSource, rescuerOfSplitBB, EdgeType.EXCEPTION);
} else {
cfg.addEdge(clonedSource, cfg.getExitBB(), EdgeType.EXIT);
}
} else {
cfg.addEdge(clonedSource, splitBB, e.getType());
}
}
}
// SSS FIXME: Are these used anywhere post-CFG building?
// 5. No need to clone rescued regions -- just assimilate them
List<ExceptionRegion> exceptionRegions = cfg.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 = cfg.getRescuerBBFor(yieldBB);
if (yieldBBrescuer != null) cfg.setRescuerBB(splitBB, yieldBBrescuer);
BasicBlock yieldBBensurer = cfg.getEnsurerBBFor(yieldBB);
if (yieldBBensurer != null) cfg.setEnsurerBB(splitBB, yieldBBensurer);
// 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) {
cfg.setRescuerBB(cb, cbProtector);
} else if (yieldBBrescuer != null) {
cfg.setRescuerBB(cb, yieldBBrescuer);
}
BasicBlock cbEnsurer = ii.getRenamedBB(closureCFG.getEnsurerBBFor(cb));
if (cbEnsurer != null) {
cfg.setEnsurerBB(cb, cbEnsurer);
} else if (yieldBBensurer != null) {
cfg.setEnsurerBB(cb, yieldBBensurer);
}