package ddg;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import misc.HashMapOfSets;
import ddg.DataDependenceGraph.DDG;
import ddg.DefUseCFG.BatchInserterFactory;
import ddg.DefUseCFG.DefUseCFG;
import ddg.DefUseCFG.DefUseCFGFactory;
public class DDGCreator
{
DefUseCFG cfg;
DefUseCFGFactory cfgFactory = new BatchInserterFactory();
HashMapOfSets in = new HashMapOfSets();
HashMapOfSets out = new HashMapOfSets();
HashMapOfSets gen = new HashMapOfSets();
HashSet<Object> changedNodes;
private class Definition
{
public Definition(Object aStatement, String aIdentifier)
{
statement = aStatement;
identifier = aIdentifier;
}
public Object statement;
public String identifier;
};
public void setFactory(DefUseCFGFactory aFactory)
{
cfgFactory = aFactory;
}
public DDG createForFunctionById(Long funcId)
{
DefUseCFG cfg = cfgFactory.create(funcId);
return createForDefUseCFG(cfg);
}
public DDG createForDefUseCFG(DefUseCFG aCfg)
{
cfg = aCfg;
calculateReachingDefs();
return createDDGFromReachingDefs();
}
private void calculateReachingDefs()
{
initReachingDefs();
while (!changedNodes.isEmpty())
{
Object currentBlock = popFromChangedNodes();
updateIn(currentBlock);
boolean changed = updateOut(currentBlock);
if (!changed)
continue;
List<Object> children = cfg.getChildBlocks().getListForKey(
currentBlock);
if (children == null)
continue;
for (Object o : children)
changedNodes.add(o);
}
}
private void initReachingDefs()
{
initOut();
initGenFromOut();
changedNodes = new HashSet<Object>();
changedNodes.addAll(cfg.getStatements());
}
private Object popFromChangedNodes()
{
Object x = changedNodes.iterator().next();
changedNodes.remove(x);
return x;
}
private void initOut()
{
for (Object statement : cfg.getStatements())
{
// this has the nice side-effect that an
// empty hash is created for the statement.
out.removeAllForKey(statement);
List<Object> symsDefined = cfg.getSymbolsDefined().getListForKey(
statement);
if (symsDefined == null)
continue;
for (Object s : symsDefined)
{
String symbol = (String) s;
out.add(statement, new Definition(statement, symbol));
}
}
}
private void initGenFromOut()
{
for (Object statement : cfg.getStatements())
{
for (Object o : out.getListForKey(statement))
gen.add(statement, o);
}
}
private void updateIn(Object x)
{
List<Object> parents = cfg.getParentBlocks().getListForKey(x);
if (parents == null)
return;
in.removeAllForKey(x);
// in(x) = union(out(p))_{p in parents(x)}
for (Object parent : parents)
{
HashSet<Object> parentOut = out.getListForKey(parent);
if (parentOut == null)
continue;
for (Object o : parentOut)
in.add(x, o);
}
}
private boolean updateOut(Object x)
{
HashSet<Object> listForKey = out.getListForKey(x);
HashSet<Object> oldOut = new HashSet<Object>(listForKey);
out.removeAllForKey(x);
// in(x)
HashSet<Object> inForX = in.getListForKey(x);
if (inForX != null)
{
for (Object o : inForX)
{
out.add(x, o);
}
}
// -kill(x)
List<Object> killX = cfg.getSymbolsDefined().getListForKey(x);
if (killX != null)
{
Iterator<Object> it = out.getListForKey(x).iterator();
while (it.hasNext())
{
Definition def = (Definition) it.next();
if (killX.contains(def.identifier))
it.remove();
}
}
// gen(X)
HashSet<Object> genX = gen.getListForKey(x);
if (genX != null)
{
for (Object o : genX)
{
out.add(x, o);
}
}
return !oldOut.equals(out.getListForKey(x));
}
private DDG createDDGFromReachingDefs()
{
DDG ddg = new DDG();
for (Object statement : cfg.getStatements())
{
HashSet<Object> inForBlock = in.getListForKey(statement);
if (inForBlock == null)
continue;
List<Object> usedSymbols = cfg.getSymbolsUsed().getListForKey(
statement);
if (usedSymbols == null)
continue;
for (Object d : inForBlock)
{
Definition def = (Definition) d;
if (usedSymbols.contains(def.identifier))
ddg.add(def.statement, statement, def.identifier);
}
}
return ddg;
}
}