package org.jruby.ir.dataflow.analyses;
import org.jruby.ir.IREvalScript;
import org.jruby.ir.IRScope;
import org.jruby.ir.dataflow.DataFlowProblem;
import org.jruby.ir.operands.LocalVariable;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.representations.BasicBlock;
import java.util.*;
public class LiveVariablesProblem extends DataFlowProblem<LiveVariablesProblem, LiveVariableNode> {
public static final String NAME = "Live Variables Analysis";
public LiveVariablesProblem(IRScope scope) {
super(DataFlowProblem.DF_Direction.BACKWARD);
varsLiveOnScopeExit = new ArrayList<LocalVariable>();
setup(scope);
}
public Integer getDFVar(Variable v) {
return dfVarMap.get(v);
}
public boolean dfVarExists(Variable v) {
return getDFVar(v) != null;
}
public Variable getVariable(int id) {
return varDfVarMap.get(id);
}
@Override
public LiveVariableNode buildFlowGraphNode(BasicBlock bb) {
return new LiveVariableNode(this, bb);
}
public void addDFVar(Variable v) {
Integer dfv = addDataFlowVar();
dfVarMap.put(v, dfv);
varDfVarMap.put(dfv, v);
if (v instanceof LocalVariable && !v.isSelf()) {
//System.out.println("Adding df var for " + v + ":" + dfv.id);
localVars.add((LocalVariable) v);
}
}
Get variables that are live on entry to the cfg.
This is the case for closures which access variables from the parent scope.
sum = 0; a.each { |i| sum += i }; return sum
In the code snippet above, 'sum' is live on entry to the closure
/**
* Get variables that are live on entry to the cfg.
* This is the case for closures which access variables from the parent scope.
*
* sum = 0; a.each { |i| sum += i }; return sum
*
* In the code snippet above, 'sum' is live on entry to the closure
*/
public Collection<LocalVariable> getLocalVarsLiveOnScopeEntry() {
List<LocalVariable> liveVars = new ArrayList<LocalVariable>();
BitSet liveIn = getFlowGraphNode(getScope().getCFG().getEntryBB()).getLiveOutBitSet();
for (int i = 0; i < liveIn.size(); i++) {
if (!liveIn.get(i)) continue;
Variable v = getVariable(i);
if (v instanceof LocalVariable) {
liveVars.add((LocalVariable)v);
}
// System.out.println("variable " + v + " is live on entry!");
}
return liveVars;
}
@Override
public String getDataFlowVarsForOutput() {
StringBuilder buf = new StringBuilder();
for (Map.Entry<Variable, Integer> entry : dfVarMap.entrySet()) {
buf.append("DF Var ").append(entry.getValue()).append(" = ").append(entry.getKey()).append('\n');
}
return buf.toString();
}
public void markDeadInstructions() {
for (LiveVariableNode n : flowGraphNodes) {
n.markDeadInstructions();
}
}
public void setVarsLiveOnScopeExit(Collection<LocalVariable> vars) {
varsLiveOnScopeExit.addAll(vars);
}
public Collection<LocalVariable> getVarsLiveOnScopeExit() {
return varsLiveOnScopeExit;
}
public Set<Variable> getAllVars() {
return dfVarMap.keySet();
}
public Set<LocalVariable> getNonSelfLocalVars() {
return localVars;
}
@Override
public String getName() {
return NAME;
}
/* ----------- Private Interface ------------ */
private HashMap<Variable, Integer> dfVarMap = new HashMap<Variable, Integer>();
private HashMap<Integer, Variable> varDfVarMap = new HashMap<Integer, Variable>();
private HashSet<LocalVariable> localVars = new HashSet<LocalVariable>(); // Local variables that can be live across dataflow barriers
private Collection<LocalVariable> varsLiveOnScopeExit;
}