package dk.brics.jspointers;
import java.awt.List;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import dk.brics.jscontrolflow.Function;
import dk.brics.jscontrolflow.analysis.privatevars.PrivateVariables;
import dk.brics.jscontrolflow.scope.Scope;
import dk.brics.jscontrolflow.scope.WithScope;
import dk.brics.jscontrolflow.statements.Assignment;
import dk.brics.jsparser.node.Node;
import dk.brics.jspointers.dataflow.AllocNode;
import dk.brics.jspointers.dataflow.CoerceToPrimitive;
import dk.brics.jspointers.dataflow.ConstNode;
import dk.brics.jspointers.dataflow.DataflowGraph;
import dk.brics.jspointers.dataflow.FlowNode;
import dk.brics.jspointers.dataflow.FunctionInstanceNode;
import dk.brics.jspointers.dataflow.IdentityNode;
import dk.brics.jspointers.dataflow.InitializeFunctionNode;
import dk.brics.jspointers.dataflow.InitializeNode;
import dk.brics.jspointers.dataflow.InputPoint;
import dk.brics.jspointers.dataflow.InterscopeIdentityNode;
import dk.brics.jspointers.dataflow.InvokeNode;
import dk.brics.jspointers.dataflow.InvokeResultNode;
import dk.brics.jspointers.dataflow.LoadAndInvokeNode;
import dk.brics.jspointers.dataflow.LoadDynamicNode;
import dk.brics.jspointers.dataflow.LoadNode;
import dk.brics.jspointers.dataflow.NativeCallNode;
import dk.brics.jspointers.dataflow.OutputPoint;
import dk.brics.jspointers.dataflow.PlusNode;
import dk.brics.jspointers.dataflow.ReturnNode;
import dk.brics.jspointers.dataflow.StoreDynamicNode;
import dk.brics.jspointers.dataflow.StoreIfPresentNode;
import dk.brics.jspointers.dataflow.StoreNode;
import dk.brics.jspointers.dataflow.StubNode;
import dk.brics.jspointers.dataflow.VarReadGlobalNode;
import dk.brics.jspointers.dataflow.VarReadInterscopeNode;
import dk.brics.jspointers.dataflow.VarReadNode;
import dk.brics.jspointers.dataflow.VarWriteGlobalNode;
import dk.brics.jspointers.dataflow.VarWriteInterscopeNode;
import dk.brics.jspointers.dataflow.VarWriteNode;
import dk.brics.jspointers.flowgraph.analysis.Liveness;
import dk.brics.jspointers.flowgraph.analysis.TypeAnalysis;
import dk.brics.jspointers.lattice.values.ApplyFunctionValue;
import dk.brics.jspointers.lattice.values.BooleanValue;
import dk.brics.jspointers.lattice.values.CallFunctionValue;
import dk.brics.jspointers.lattice.values.DOMObjectValue;
import dk.brics.jspointers.lattice.values.FunctionFunctionValue;
import dk.brics.jspointers.lattice.values.NullValue;
import dk.brics.jspointers.lattice.values.NumberValue;
import dk.brics.jspointers.lattice.values.ObjectFunctionValue;
import dk.brics.jspointers.lattice.values.StringValue;
import dk.brics.jspointers.lattice.values.UndefinedValue;
import dk.brics.jspointers.lattice.values.Value;
import dk.brics.jsutil.MultiMap;
public class DataflowCreator {
public static DataflowGraph createDataflowGraph(Collection<Function> topLevels, Collection<Function> harness) {
final MultiMap<Assignment, OutputPoint> stmt2output = new MultiMap<Assignment, OutputPoint>();
final MultiMap<Assignment, InputPoint> stmt2dest = new MultiMap<Assignment, InputPoint>();
final MultiMap<WithScope, InterscopeIdentityNode> with2interscopes = new MultiMap<WithScope, InterscopeIdentityNode>();
final Map<WithScope, StubNode> with2stub = new HashMap<WithScope, StubNode>();
final DataflowGraph dataflow = new DataflowGraph(topLevels);
// create the initializer node
InitializeNode init = new InitializeNode();
dataflow.getNodes().add(init);
dataflow.setInitializer(init);
for (final Function topLevel : topLevels) {
PrivateVariables privateVars = new PrivateVariables(topLevel);
for (final Function function : topLevel.getTransitiveInnerFunctions(true)) {
final Liveness liveness = new Liveness(fgd, function, privateVars);
final ReachingDefs reachingDefs = new ReachingDefs(fgd, function, liveness, privateVars);
final TypeAnalysis ta = new TypeAnalysis(fgd, function, liveness);
final Liveness live = new Liveness(fgd, function, privateVars, ta);
if (flowgraph.getHarnessFunctions().contains(function) && function.getName() != null) {
dataflow.getNamedHarnessFunctions().put(function.getName(), function);
}
final LinkedList<FlowNode> nodes = new LinkedList<FlowNode>();
// maps a CatchNode to all the output points it can take exception instances from
final MultiMap<CatchNode,OutputPoint> catchNodeSrcPoints = new MultiMap<CatchNode, OutputPoint>();
// only create one var read/write per local variable
final Map<String, VarReadNode> localVarReads = new HashMap<String, VarReadNode>();
final Map<String, VarWriteNode> localVarWrites = new HashMap<String, VarWriteNode>();
// create some unique nodes for this function
// FunctionInstanceNode
final FunctionInstanceNode funcInstanceNode = new FunctionInstanceNode(function);
nodes.add(funcInstanceNode);
dataflow.getFunctionInstanceFlowNodes().put(function, funcInstanceNode);
// normal ReturnNode
final ReturnNode normalReturn = new ReturnNode(function, false);
nodes.add(normalReturn);
dataflow.getNormalReturns().put(function, normalReturn);
// exceptional ReturnNode
final ReturnNode exceptionalReturn = new ReturnNode(function, true);
nodes.add(exceptionalReturn);
dataflow.getExceptionalReturns().put(function, exceptionalReturn);
// coercion node for each exception handler
final Map<Node,CoerceToPrimitive> exhandler2coercion = new HashMap<Node, CoerceToPrimitive>();
// create parameter VarReadNodes for private parameters
for (int i=0; i<function.getParameterNames().size(); i++) {
String name = function.getParameterNames().get(i);
if (privateVars.contains(name)) {
VarReadNode read = new VarReadNode(name, function);
read.getFunctionInstance().addSource(funcInstanceNode.getResult());
localVarReads.put(name, read);
nodes.add(read);
stmt2output.add(new ParameterAssignment(function, i), read.getResult());
}
}
// convert all statements in function body
for (BasicBlock block : function.getBlocks()) {
final boolean isHarness = flowgraph.getHarnessFunctions().contains(function) || flowgraph.getToplevelHarnessBlocks().contains(block);
for (final Node node : block.getNodes()) {
node.visitBy(new AbstractNodeVisitor() {
private void coerceToPrimitive(int var) {
// TODO make TypeAnalysis distinguish strings and objects
if (!ta.getVariables(node).contains(var))
return; // cannot be object, no need to coerce
Node exhandler = findExceptionHandler(node);
CoerceToPrimitive coerce = exhandler2coercion.get(exhandler);
if (coerce == null) {
coerce = new CoerceToPrimitive();
nodes.add(coerce);
exhandler2coercion.put(exhandler, coerce);
if (exhandler instanceof CatchNode) {
CatchNode cn = (CatchNode)exhandler;
catchNodeSrcPoints.add(cn, coerce.getExceptionalResult());
} else {
exceptionalReturn.getValue().addSource(coerce.getExceptionalResult());
}
}
link(var, coerce.getValue());
}
private ConstNode constant(Value value) {
ConstNode c = new ConstNode(value, function);
c.getFunctionInstance().addSource(funcInstanceNode.getResult());
nodes.add(c);
return c;
}
private Node findExceptionHandler(Node node) {
BasicBlock exblock = node.getBlock().getExceptionHandler();
while (exblock != null) {
Node first = exblock.getFirstNode();
if (first instanceof ExceptionalReturnNode || first instanceof CatchNode) {
return first;
}
exblock = exblock.getExceptionHandler();
}
return (ExceptionalReturnNode)function.getExceptionalExit().getFirstNode();
}
private void linkOutput(AssignmentNode asn, OutputPoint output) {
stmt2output.add(new TempVarAssignment(asn), output);
}
@Override
public void visit(ReadPropertyNode n, Void a) {
if (!live.isLiveAfter(n, n.getResultVar()))
return;
if (n.getPropertyStr() != null) {
LoadNode load = new LoadNode(n.getPropertyStr());
link(n.getBaseVar(), load.getBase());
linkOutput(n, load.getResult());
nodes.add(load);
} else {
LoadDynamicNode load = new LoadDynamicNode();
link(n.getBaseVar(), load.getBase());
link(n.getPropertyVar(), load.getProperty());
linkOutput(n, load.getResult());
nodes.add(load);
}
}
@Override
public void visit(WritePropertyNode n, Void a) {
if (n.getPropertyStr() != null) {
StoreNode store = new StoreNode(n.getPropertyStr());
link(n.getBaseVar(), store.getBase());
link(n.getValueVar(), store.getValue());
nodes.add(store);
} else {
StoreDynamicNode store = new StoreDynamicNode();
link(n.getBaseVar(), store.getBase());
link(n.getPropertyVar(), store.getProperty());
link(n.getValueVar(), store.getValue());
nodes.add(store);
}
}
private void handleReadHarnessVariable(ReadVariableNode n) {
String varname = n.getVarName();
if (varname.equals("$number") || varname.equals("$int")) {
linkOutput(n, constant(NumberValue.Instance).getOutput());
}
else if (varname.equals("$string")) {
linkOutput(n, constant(StringValue.Instance).getOutput());
}
else if (varname.equals("$bool")) {
linkOutput(n, constant(BooleanValue.Instance).getOutput());
}
else {
throw new RuntimeException("Unknown harness variable " + varname);
}
}
@Override
public void visit(EnterWithNode n, Void a) {
StubNode stub = new StubNode();
link(n.getObjectVar(), stub.getInput());
nodes.add(stub);
with2stub.put(new WithScope(n), stub);
}
@Override
public void visit(ReadVariableNode n, Void a) {
if (!live.isLiveAfter(n, n.getResultVar()))
return;
if (isHarness && n.getVarName().startsWith("$")) {
handleReadHarnessVariable(n); // in the harness files, treat variables starting with $ specially
return;
}
if (!isHarness && n.getVarName().startsWith("$")) {
System.out.printf("Non-harness variable %s at %s\n", n.getVarName(), n.getSourceLocation());
}
Scope scope = scopes.getScopeOfStmt(n);
boolean definite = false;
int depth = 0;
while (scope != null && !definite) {
if (scope instanceof WithScope) {
WithScope w = (WithScope)scope;
LoadNode load = new LoadNode(n.getVarName());
if (depth == 0) {
link(w.getNode(), w.getNode().getObjectVar(), load.getBase());
} else {
InterscopeIdentityNode interscope = new InterscopeIdentityNode(depth);
interscope.getFunctionInstance().addSource(funcInstanceNode.getResult());
with2interscopes.add(w, interscope);
load.getBase().addSource(interscope.getResult());
nodes.add(interscope);
}
linkOutput(n, load.getResult());
nodes.add(load);
} else if (scope instanceof FunctionScope) {
FunctionScope f = (FunctionScope)scope;
if (f.getFunction().getOuterFunction() == null) {
VarReadGlobalNode read = new VarReadGlobalNode(n.getVarName());
read.getFunctionInstance().addSource(funcInstanceNode.getResult());
linkOutput(n, read.getResult());
nodes.add(read);
definite = true;
}
else if (scopeVars.contains(scope, n.getVarName())) {
if (depth == 0) {
VarReadNode read = localVarReads.get(n.getVarName());
if (read == null) {
read = new VarReadNode(n.getVarName(), function);
read.getFunctionInstance().addSource(funcInstanceNode.getResult());
nodes.add(read);
localVarReads.put(n.getVarName(), read);
}
linkOutput(n, read.getResult());
} else {
VarReadInterscopeNode read = new VarReadInterscopeNode(n.getVarName(), f.getFunction(), depth);
read.getFunctionInstance().addSource(funcInstanceNode.getResult());
linkOutput(n, read.getResult());
nodes.add(read);
}
definite = true;
}
depth++;
} else {
throw new RuntimeException("Unknown scope kind: " + scope.getClass());
}
scope = scopes.getParentScope(scope);
}
}
@Override
public void visit(WriteVariableNode n, Void a) {
Scope scope = scopes.getScopeOfStmt(n);
boolean definite = false;
int depth = 0;
while (scope != null && !definite) {
if (scope instanceof WithScope) {
WithScope ws = (WithScope)scope;
StoreIfPresentNode store = new StoreIfPresentNode(n.getVarName());
if (depth == 0) {
link(ws.getNode(), ws.getNode().getObjectVar(), store.getBase());
} else {
InterscopeIdentityNode interscope = new InterscopeIdentityNode(depth);
interscope.getFunctionInstance().addSource(funcInstanceNode.getResult());
with2interscopes.add(ws, interscope);
store.getBase().addSource(interscope.getResult());
nodes.add(interscope);
}
link(n.getValueVar(), store.getValue());
nodes.add(store);
} else if (scope instanceof FunctionScope) {
FunctionScope f = (FunctionScope)scope;
if (f.getFunction() == graph.getMain()) {
VarWriteGlobalNode write = new VarWriteGlobalNode(n.getVarName());
link(n.getValueVar(), write.getValue());
nodes.add(write);
}
else if (scopeVars.contains(scope, n.getVarName())) {
if (depth == 0) {
VarWriteNode write = localVarWrites.get(n.getVarName());
if (write == null) {
write = new VarWriteNode(n.getVarName(), function);
nodes.add(write);
localVarWrites.put(n.getVarName(), write);
}
link(n.getValueVar(), write.getValue());
} else {
VarWriteInterscopeNode write = new VarWriteInterscopeNode(n.getVarName(), f.getFunction(), depth);
link(n.getValueVar(), write.getValue());
write.getFunctionInstance().addSource(funcInstanceNode.getResult());
nodes.add(write);
}
definite = true;
}
depth++;
} else {
throw new RuntimeException("Unknown scope kind: " + scope.getClass());
}
scope = scopes.getParentScope(scope);
}
}
@Override
public void visit(ConstantNode n, Void a) {
if (!live.isLiveAfter(n, n.getResultVar()))
return;
switch (n.getType()) {
case NUMBER:
linkOutput(n, constant(NumberValue.Instance).getOutput());
break;
case STRING:
linkOutput(n, constant(StringValue.Instance).getOutput());
break;
case BOOLEAN:
linkOutput(n, constant(BooleanValue.Instance).getOutput());
break;
case NULL:
linkOutput(n, constant(NullValue.Instance).getOutput());
break;
case UNDEFINED:
linkOutput(n, constant(UndefinedValue.Instance).getOutput());
break;
case FUNCTION:
InitializeFunctionNode init = new InitializeFunctionNode(n.getFunction());
init.getOuterFunction().addSource(funcInstanceNode.getResult());
nodes.add(init);
linkOutput(n, init.getResult());
break;
default:
throw new RuntimeException("Unknown constant kind: " + n.getType());
}
}
@Override
public void visit(DeclareFunctionNode n, Void a) {
InitializeFunctionNode init = new InitializeFunctionNode(n.getFunction());
init.getOuterFunction().addSource(funcInstanceNode.getResult());
nodes.add(init);
linkOutput(n, init.getResult());
// write function to scope
if (n.getFunction().getName() != null) {
if (function.getOuterFunction() == null) {
VarWriteGlobalNode write = new VarWriteGlobalNode(n.getFunction().getName());
write.getValue().addSource(init.getResult());
nodes.add(write);
} else {
VarWriteNode write = new VarWriteNode(n.getFunction().getName(), function);
write.getValue().addSource(init.getResult());
nodes.add(write);
}
}
}
private void addBinopCoercions(BinaryOperatorNode n) {
switch (n.getOperator()) {
case IN:
case INSTANCEOF:
return; // no primitive coercion
}
coerceToPrimitive(n.getArg1Var());
coerceToPrimitive(n.getArg2Var());
}
@Override
public void visit(BinaryOperatorNode n, Void a) {
addBinopCoercions(n);
if (!live.isLiveAfter(n, n.getResultVar()))
return;
switch (n.getOperator()) {
case ADD:
if (ta.getVariables(n).contains(n.getArg1Var()) || ta.getVariables(n).contains(n.getArg2Var())) {
PlusNode plus = new PlusNode();
link(n.getArg1Var(), plus.getArgument());
link(n.getArg2Var(), plus.getArgument());
linkOutput(n, plus.getOutput());
nodes.add(plus);
} else {
linkOutput(n, constant(NumberValue.Instance).getOutput());
}
break;
case EQ: // definitely boolean result
case SEQ:
case NE:
case SNE:
case GT:
case GE:
case LT:
case LE:
case INSTANCEOF:
case IN:
linkOutput(n, constant(BooleanValue.Instance).getOutput());
break;
case AND: // definitely number result
case OR:
case XOR:
case DIV:
case MUL:
case SUB:
case USHR:
case SHR:
case SHL:
case REM:
linkOutput(n, constant(NumberValue.Instance).getOutput());
break;
default:
throw new RuntimeException("Unexpected binary operator: " + n.getOperator());
}
}
@Override
public void visit(UnaryOperatorNode n, Void a) {
coerceToPrimitive(n.getArgVar());
if (!live.isLiveAfter(n, n.getResultVar()))
return;
switch (n.getOperator()) {
case NOT: // boolean result
linkOutput(n, constant(BooleanValue.Instance).getOutput());
break;
case MINUS: // number result
case PLUS:
case COMPLEMENT:
linkOutput(n, constant(NumberValue.Instance).getOutput());
break;
default:
throw new RuntimeException("Unexpected unary operator: " + n.getOperator());
}
}
@Override
public void visit(TypeofNode n, Void a) {
if (!live.isLiveAfter(n, n.getResultVar()))
return;
linkOutput(n, constant(StringValue.Instance).getOutput());
}
private boolean tryHandleCallNodeAsLoadAndInvoke(CallNode n) {
Set<Assignment> asns = reachingDefs.getReachingDefsForTempVar(n, n.getFunctionVar());
if (asns.size() != 1)
return false;
Assignment asn = asns.iterator().next();
if (!(asn instanceof TempVarAssignment))
return false;
TempVarAssignment tasn = (TempVarAssignment)asn;
if (!(tasn.getNode() instanceof ReadPropertyNode))
return false;
ReadPropertyNode read = (ReadPropertyNode)tasn.getNode();
if (read.getPropertyStr() == null)
return false;
if (!reachingDefs.getReachingDefsForTempVar(read, read.getBaseVar()).equals(reachingDefs.getReachingDefsForTempVar(n, n.getBaseVar())))
return false;
LoadAndInvokeNode loadAndInvoke = new LoadAndInvokeNode(read.getPropertyStr(), n.getNumberOfArgs(), n);
link(read.getBaseVar(), loadAndInvoke.getBase());
for (int i=0; i<n.getNumberOfArgs(); i++) {
link(n.getArgVar(i), loadAndInvoke.getArguments().get(i));
}
InvokeResultNode res = new InvokeResultNode(false, loadAndInvoke);
link(n.getFunctionVar(), res.getFunc());
link(read.getBaseVar(), res.getThisArg()); // TODO: Refactor InvokeResult to share more with its IInvocation
linkOutput(n, res.getResult());
// link exceptional result
Node exhandler = findExceptionHandler(n);
if (exhandler instanceof CatchNode) {
CatchNode cn = (CatchNode)exhandler;
catchNodeSrcPoints.add(cn, res.getExceptionalResult());
} else if (exhandler instanceof ExceptionalReturnNode) {
exceptionalReturn.getValue().addSource(res.getExceptionalResult());
} else {
throw new RuntimeException("Unexpected exception handler: " + exhandler);
}
nodes.add(loadAndInvoke);
nodes.add(res);
dataflow.getCalls().add(n, loadAndInvoke);
return true;
}
@Override
public void visit(CallNode n, Void a) {
if (tryHandleCallNodeAsLoadAndInvoke(n)) {
return;
}
// FIXME: Fix the Rhino->FlowGraph converter to get a more robust way of detecting omitted this arg!
boolean omittedThisArg = reachingDefs.getReachingDefsForTempVar(n, n.getBaseVar()).isEmpty();
Object callsiteId = n;
InvokeNode invoke = new InvokeNode(n.getNumberOfArgs(), n.isConstructorCall(), omittedThisArg, callsiteId);
InvokeResultNode res = new InvokeResultNode(n.isConstructorCall(), invoke);
// link this arg
if (!n.isConstructorCall()) {
link(n.getBaseVar(), invoke.getBase());
} else {
AllocNode alloc = new AllocNode(n, function);
invoke.getBase().addSource(alloc.getResult());
res.getThisArg().addSource(alloc.getResult());
alloc.getFunctionInstance().addSource(funcInstanceNode.getResult());
nodes.add(alloc);
}
// link function arg
link(n.getFunctionVar(), invoke.getFunc());
link(n.getFunctionVar(), res.getFunc());
// link actual arguments
for (int i=0; i<n.getNumberOfArgs(); i++) {
link(n.getArgVar(i), invoke.getArguments().get(i));
}
// link normal result
linkOutput(n, res.getResult());
// link exceptional result
Node exhandler = findExceptionHandler(n);
if (exhandler instanceof CatchNode) {
CatchNode cn = (CatchNode)exhandler;
catchNodeSrcPoints.add(cn, res.getExceptionalResult());
} else if (exhandler instanceof ExceptionalReturnNode) {
exceptionalReturn.getValue().addSource(res.getExceptionalResult());
} else {
throw new RuntimeException("Unexpected exception handler: " + exhandler);
}
// call2node.put(n, invoke);
nodes.add(invoke);
nodes.add(res);
dataflow.getCalls().add(n, invoke);
}
@Override
public void visit(dk.brics.tajs.flowgraph.nodes.ReturnNode n, Void a) {
if (n.getValueVar() != Node.NO_VALUE) {
if (!isHarness) {
System.out.print("");
}
link(n.getValueVar(), normalReturn.getValue());
}
}
@Override
public void visit(NewObjectNode n, Void a) {
AllocNode alloc = new AllocNode(n, function);
linkOutput(n, alloc.getResult());
alloc.getFunctionInstance().addSource(funcInstanceNode.getResult());
nodes.add(alloc);
}
@Override
public void visit(ThrowNode n, Void a) {
Node exhandler = findExceptionHandler(n);
if (exhandler instanceof CatchNode) {
CatchNode cn = (CatchNode)exhandler;
IdentityNode in = new IdentityNode();
link(n, n.getValueVar(), in.getValue());
catchNodeSrcPoints.add(cn, in.getResult());
nodes.add(in);
} else if (exhandler instanceof ExceptionalReturnNode) {
link(n, n.getValueVar(), exceptionalReturn.getValue());
} else {
throw new RuntimeException("Unexpected exception handler: " + exhandler);
}
}
private void link(int var, InputPoint input) {
link(node, var, input);
}
private void link(Node node, int var, InputPoint input) {
if (input == null)
throw new RuntimeException("input arg was null");
for (Assignment asn : reachingDefs.getReachingDefsForTempVar(node, var)) {
stmt2dest.add(asn, input);
}
}
}, null);
}
} // end of block loop
// setup CatchNodes
for (CatchNode cn : catchNodeSrcPoints.keySet()) {
Assignment an = new TempVarAssignment(cn);
if (cn.getTempVar() != Node.NO_VALUE) {
// the exception is stored in the temporary variable
stmt2output.addAll(an, catchNodeSrcPoints.getView(cn));
} else {
// an object 'ScopeObj' is allocated, and the exception is stored as a property on that
// with the name of the property being the variable name of the CatchNode
// This type of CatchNode is followed by a 'with' statement to model the catch block's scope
AllocNode scopeObjAlloc = new AllocNode(cn, function);
scopeObjAlloc.getFunctionInstance().addSource(funcInstanceNode.getResult());
StoreNode store = new StoreNode(cn.getVarName());
store.getBase().addSource(scopeObjAlloc.getResult());
for (OutputPoint op : catchNodeSrcPoints.getView(cn)) {
store.getValue().addSource(op);
}
stmt2output.add(an, scopeObjAlloc.getResult());
nodes.add(scopeObjAlloc);
nodes.add(store);
}
}
dataflow.getNodes().addAll(nodes);
dataflow.getFunctionFlownodes().addAll(function, nodes);
} // end of function loop
} // end of toplevel loop
// connect nodes
for (Assignment asn : stmt2dest.keySet()) {
for (InputPoint in : stmt2dest.getView(asn)) {
for (OutputPoint out : stmt2output.getView(asn)) {
in.addSource(out);
}
}
}
// set interscope nodes
for (WithScope w : with2interscopes.keySet()) {
StubNode stub = with2stub.get(w);
if (stub == null)
throw new RuntimeException("With stmt " + w.getNode().getSourceLocation() + " does not get a stub node");
for (InterscopeIdentityNode id : with2interscopes.getView(w)) {
id.setForeignInputPoint(stub.getInput());
}
}
// create native flow nodes [TODO less error-prone way to do this?]
dataflow.getNativeFlowNodes().put(CallFunctionValue.Instance, new NativeCallNode(CallFunctionValue.Instance));
dataflow.getNativeFlowNodes().put(ObjectFunctionValue.Instance, new NativeCallNode(ObjectFunctionValue.Instance));
dataflow.getNativeFlowNodes().put(FunctionFunctionValue.Instance, new NativeCallNode(FunctionFunctionValue.Instance));
dataflow.getNativeFlowNodes().put(ApplyFunctionValue.Instance, new NativeCallNode(ApplyFunctionValue.Instance));
dataflow.getNativeFlowNodes().put(DOMObjectValue.Instance, new NativeCallNode(DOMObjectValue.Instance));
dataflow.getNodes().addAll(dataflow.getNativeFlowNodes().values());
return dataflow;
}
}