package org.jruby.ir.passes;
import org.jruby.ir.interpreter.FullInterpreterContext;
import org.jruby.ir.representations.BasicBlock;
import org.jruby.ir.representations.CFG;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
import java.util.*;
public class DominatorTreeBuilder extends CompilerPass {
private static int NULL = -1;
private static final Logger LOG = LoggerFactory.getLogger(DominatorTreeBuilder.class);
@Override
public String getLabel() {
return "Build Dominator Tree";
}
@Override
public Object execute(FullInterpreterContext fic, Object... data) {
CFG cfg = (CFG) data[0];
try {
buildDominatorTree(cfg, cfg.postOrderList(), cfg.getMaxNodeID());
} catch (Exception e) {
LOG.debug("Caught exception building dom tree for {}", fic.getCFG());
}
return null;
}
@Override
public boolean invalidate(FullInterpreterContext fic) {
return false;
}
public void buildDominatorTree(CFG cfg, LinkedList<BasicBlock> postOrderList, int maxNodeId) {
int[] bbToPoNumbers = new int[maxNodeId + 1];
BasicBlock[] poNumbersToBB = new BasicBlock[maxNodeId + 1];
int n = 0;
ListIterator<BasicBlock> it = postOrderList.listIterator();
while (it.hasNext()) {
BasicBlock b = it.next();
bbToPoNumbers[b.getID()] = n;
poNumbersToBB[n] = b;
n++;
}
int[] idoms = new int[maxNodeId + 1];
BasicBlock root = cfg.getEntryBB();
int rootPoNumber = bbToPoNumbers[root.getID()];
idoms[rootPoNumber] = rootPoNumber;
boolean changed = true;
while (changed) {
changed = false;
it = postOrderList.listIterator(cfg.size());
while (it.hasPrevious()) {
BasicBlock b = it.previous();
if (b == root) continue;
int bPoNumber = bbToPoNumbers[b.getID()];
int oldBIdom = idoms[bPoNumber];
int newBIdom = NULL;
for (BasicBlock src : cfg.getIncomingSources(b)) {
int srcPoNumber = bbToPoNumbers[src.getID()];
if (idoms[srcPoNumber] != NULL) {
newBIdom = srcPoNumber;
break;
}
}
assert newBIdom != NULL;
int processedPred = newBIdom;
for (BasicBlock src: cfg.getIncomingSources(b)) {
int srcPoNumber = bbToPoNumbers[src.getID()];
int srcIdom = idoms[srcPoNumber];
if ((srcIdom != NULL) && (srcPoNumber != processedPred)) {
newBIdom = intersectDomSets(idoms, srcPoNumber, newBIdom);
}
}
if (oldBIdom != newBIdom) {
changed = true;
idoms[bPoNumber] = newBIdom;
}
}
}
Map<BasicBlock, BasicBlock> idomMap = new HashMap<BasicBlock, BasicBlock>();
for (int i = 0; i < maxNodeId; i++) {
idomMap.put(poNumbersToBB[i], poNumbersToBB[idoms[i]]);
}
}
private int intersectDomSets(int[] idomMap, int nb1, int nb2) {
while (nb1 != nb2) {
while (nb1 < nb2) {
nb1 = idomMap[nb1];
}
while (nb2 < nb1) {
nb2 = idomMap[nb2];
}
}
return nb1;
}
}