package org.jruby.ir.dataflow;
import org.jruby.ir.interpreter.FullInterpreterContext;
import org.jruby.ir.representations.BasicBlock;
import java.util.*;
public abstract class DataFlowProblem<T extends DataFlowProblem<T, U>, U extends FlowGraphNode<T, U>> {
/* -------------- Public fields and methods below ---------------- */
public enum DF_Direction { FORWARD, BACKWARD, BIDIRECTIONAL }
public final DF_Direction direction;
public DataFlowProblem(DF_Direction direction) {
this.direction = direction;
}
// ------- Abstract methods without a default implementation -------
abstract public U buildFlowGraphNode(BasicBlock bb);
abstract public String getName();
// ------- Default implementation methods below -------
Are there are available data flow facts to run this problem? SSS FIXME: Silly optimization? /** Are there are available data flow facts to run this problem? SSS FIXME: Silly optimization? */
public boolean isEmpty() {
return false;
}
public DF_Direction getFlowDirection() {
return direction;
}
public void setup(FullInterpreterContext fic) {
this.fic = fic;
buildFlowGraph();
}
public FullInterpreterContext getFIC() {
return fic;
}
/* Compute Meet Over All Paths solution for this dataflow problem on the input CFG.
* This implements a standard worklist algorithm. */
public void compute_MOP_Solution() {
if (isEmpty()) return; // Don't bother to compute soln if we have no facts available.
// 1. Initialize work list based on flow direction to make processing efficient!
LinkedList<U> workList = generateWorkList();
// 2. Initialize a bitset with a flag set for all basic blocks
int numNodes = fic.getCFG().getMaxNodeID();
BitSet bbSet = new BitSet(1+numNodes);
bbSet.flip(0, numNodes); // set all bits from default of 0 to 1 (enebo: could we invert this in algo?)
// 3. Iteratively compute data flow info
while (!workList.isEmpty()) {
workList.removeFirst().computeDataFlowInfo(workList, bbSet);
}
}
Generate an ordered list of flow graph nodes in a forward or backward order depending
on direction.
/**
* Generate an ordered list of flow graph nodes in a forward or backward order depending
* on direction.
*/
protected LinkedList<U> generateWorkList() {
LinkedList<U> wl = new LinkedList<>();
Iterator<BasicBlock> it = direction == DF_Direction.FORWARD ?
fic.getCFG().getReversePostOrderTraverser() : fic.getCFG().getPostOrderTraverser();
while (it.hasNext()) {
wl.add(getFlowGraphNode(it.next()));
}
return wl;
}
public int getDFVarsCount() {
return nextVariableId + 1;
}
/* Individual analyses should override this */
public String getDataFlowVarsForOutput() {
return "";
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("----").append(getName()).append("----\n");
buf.append("---- Data Flow Vars: ----\n");
buf.append(getDataFlowVarsForOutput());
buf.append("-------------------------\n");
for (FlowGraphNode n: flowGraphNodes) {
buf.append("DF State for BB ").append(n.basicBlock.getID()).append(":\n").append(n.toString());
}
return buf.toString();
}
public U getFlowGraphNode(BasicBlock bb) {
return basicBlockToFlowGraph.get(bb);
}
public U getEntryNode() {
return getFlowGraphNode(fic.getCFG().getEntryBB());
}
public U getExitNode() {
return getFlowGraphNode(fic.getCFG().getExitBB());
}
public int addDataFlowVar() {
nextVariableId++;
return nextVariableId;
}
/* -------------- Protected fields and methods below ---------------- */
protected List<U> flowGraphNodes;
protected FullInterpreterContext fic;
/* -------------- Private fields and methods below ---------------- */
private int nextVariableId = -1;
// Map for hash-speed retrieval of flowgraph nodes instead of walking flowGraphNodes.
private Map<BasicBlock, U> basicBlockToFlowGraph;
private void buildFlowGraph() {
flowGraphNodes = new LinkedList<>();
basicBlockToFlowGraph = new HashMap<>();
for (BasicBlock bb: fic.getCFG().getBasicBlocks()) {
U fgNode = buildFlowGraphNode(bb);
fgNode.init();
fgNode.buildDataFlowVars();
flowGraphNodes.add(fgNode);
basicBlockToFlowGraph.put(bb, fgNode);
}
}
}