package dk.brics.jspointers.flowgraph.analysis; import java.util.HashSet; import java.util.Set; import dk.brics.tajs.flowgraph.Node; import dk.brics.tajs.flowgraph.nodes.BinaryOperatorNode; import dk.brics.tajs.flowgraph.nodes.CallNode; import dk.brics.tajs.flowgraph.nodes.CatchNode; import dk.brics.tajs.flowgraph.nodes.ConstantNode; import dk.brics.tajs.flowgraph.nodes.DeclareFunctionNode; import dk.brics.tajs.flowgraph.nodes.NewObjectNode; import dk.brics.tajs.flowgraph.nodes.ReadPropertyNode; import dk.brics.tajs.flowgraph.nodes.ReadVariableNode; import dk.brics.tajs.flowgraph.nodes.TypeofNode; import dk.brics.tajs.optimizer2.Decorator; import dk.brics.tajs.optimizer2.analysis.FlowAnalysis; public class TypeAnalysisFlow extends FlowAnalysis<Set<Integer>> { private Decorator decorator; private Liveness liveness; public TypeAnalysisFlow(Decorator decorator, Liveness liveness) { super(new SetLattice<Integer>()); this.decorator = decorator; this.liveness = liveness; } @Override public Set<Node> getDependencySet(Node node) { return decorator.getAllSuccessorNodes(node); } @Override public Set<Node> getJoinSet(Node node) { return decorator.getAllPredecessorNodes(node); } private Set<Integer> addAndFilter(Set<Integer> set, int x, Node n) { if (!set.contains(x)) { Set<Integer> result = new HashSet<Integer>(set); result.add(x); result.retainAll(liveness.getLiveSetAfter(n)); return result; } else { // don't bother removing stuff from the set, since it's faster // to just return it identically return set; } } private Set<Integer> removeAndFilter(Set<Integer> set, int x, Node n) { if (set.contains(x)) { Set<Integer> result = new HashSet<Integer>(set); result.remove(x); result.retainAll(liveness.getLiveSetAfter(n)); return result; } else { return set; } } @Override public Set<Integer> visit(BinaryOperatorNode n, Set<Integer> l) { boolean maybeObjOrString = false; switch(n.getOperator()) { case ADD: if (l.contains(n.getArg1Var()) || l.contains(n.getArg2Var())) { maybeObjOrString = true; } break; } if (maybeObjOrString) { return addAndFilter(l, n.getResultVar(), n); } else { return removeAndFilter(l, n.getResultVar(), n); } } @Override public Set<Integer> visit(CallNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(ConstantNode n, Set<Integer> l) { switch (n.getType()) { case FUNCTION: case STRING: return addAndFilter(l, n.getResultVar(), n); default: return removeAndFilter(l, n.getResultVar(), n); } } @Override public Set<Integer> visit(DeclareFunctionNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(NewObjectNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(ReadPropertyNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(ReadVariableNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(TypeofNode n, Set<Integer> l) { return addAndFilter(l, n.getResultVar(), n); } @Override public Set<Integer> visit(CatchNode n, Set<Integer> l) { if (n.getTempVar() != Node.NO_VALUE) { return addAndFilter(l, n.getTempVar(), n); } else { return l; } } }