obj);
+
+ /**
+ * Merges the wrappers controlled by this control flow graph with the
+ * ones of another CFG.
+ *
+ * This means that this.wrap(x) must return the same object as b.wrap(x)
+ * after this.mergeWrappers(b) has been called. If both CFGs originally
+ * produce different wrappers for the same object, implementors may
+ * resolve to either value (or a completely new one) as long as both
+ * objects afterwards agree on the same wrapper.
+ *
+ * @param otherCfg The other control flow graph with which to merge
+ * the wrappers.
+ */
+ public void mergeWrappers(InterproceduralCFG otherCfg);
+
+ /**
+ * Gets the start point of the outermost loop containing the given
+ * statement. This functions only considers intraprocedural loops.
+ * @param stmt The statement for which to get the loop start point.
+ * @return The start point of the outermost loop containing the given
+ * statement, or NULL if the given statement is not contained in a
+ * loop.
+ */
+ public N getLoopStartPointFor(N stmt);
+
+ /**
+ * Gets all exit nodes that can transfer the control flow to the given
+ * return site.
+ * @param stmt The return site for which to get the exit nodes
+ * @return The set of exit nodes that transfer the control flow to the
+ * given return site.
+ */
+ public Set getExitNodesForReturnSite(N stmt);
+
+}
diff --git a/src/soot/jimple/interproc/ifds/JoinLattice.java b/src/soot/jimple/interproc/ifds/JoinLattice.java
new file mode 100644
index 0000000..9d0762d
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/JoinLattice.java
@@ -0,0 +1,17 @@
+package soot.jimple.interproc.ifds;
+
+/**
+ * This class defines a lattice in terms of its top and bottom elements
+ * and a join operation.
+ *
+ * @param The domain type for this lattice.
+ */
+public interface JoinLattice {
+
+ V topElement();
+
+ V bottomElement();
+
+ V join(V left, V right);
+
+}
diff --git a/src/soot/jimple/interproc/ifds/Lattice.java b/src/soot/jimple/interproc/ifds/Lattice.java
new file mode 100644
index 0000000..7d9c4a8
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/Lattice.java
@@ -0,0 +1,13 @@
+package soot.jimple.interproc.ifds;
+
+/**
+ * Interface that extends joinable half-lattices to full latices supporting
+ * both meet and join operations.
+ *
+ * @author Steven Arzt
+ */
+public interface Lattice extends JoinLattice {
+
+ V meet(V left, V right);
+
+}
diff --git a/src/soot/jimple/interproc/ifds/Main.java b/src/soot/jimple/interproc/ifds/Main.java
new file mode 100644
index 0000000..9f8f10d
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/Main.java
@@ -0,0 +1,146 @@
+package soot.jimple.interproc.ifds;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import soot.Local;
+import soot.MethodOrMethodContext;
+import soot.PackManager;
+import soot.Scene;
+import soot.SceneTransformer;
+import soot.SootMethod;
+import soot.Transform;
+import soot.Unit;
+import soot.jimple.AssignStmt;
+import soot.jimple.Jimple;
+import soot.jimple.StaticInvokeExpr;
+import soot.jimple.interproc.ifds.problems.IFDSLocalInfoFlow;
+import soot.jimple.interproc.ifds.solver.IFDSSolver;
+import soot.jimple.interproc.ifds.template.JimpleBasedInterproceduralCFG;
+import soot.jimple.interproc.incremental.UpdatableWrapper;
+import soot.jimple.toolkits.callgraph.CallGraph;
+import soot.jimple.toolkits.callgraph.Edge;
+import soot.jimple.toolkits.callgraph.ReachableMethods;
+
+public class Main {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+
+ PackManager.v().getPack("wjtp").add(new Transform("wjtp.ifds", new SceneTransformer() {
+ protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes") Map options) {
+ System.out.println("Running IFDS on initial CFG...");
+ IFDSTabulationProblem,UpdatableWrapper,UpdatableWrapper,
+ InterproceduralCFG,UpdatableWrapper>> problem =
+ new IFDSLocalInfoFlow(new JimpleBasedInterproceduralCFG());
+
+ IFDSSolver,UpdatableWrapper,UpdatableWrapper,
+ InterproceduralCFG,UpdatableWrapper>> solver =
+ new IFDSSolver,UpdatableWrapper,UpdatableWrapper,
+ InterproceduralCFG,UpdatableWrapper>>(problem);
+ solver.solve(false);
+
+ for (Unit u : Scene.v().getMainMethod().getActiveBody().getUnits())
+ System.out.println(u);
+
+ Unit ret = Scene.v().getMainMethod().getActiveBody().getUnits().getLast();
+ for (UpdatableWrapper l: solver.ifdsResultsAt(problem.interproceduralCFG().wrapWeak(ret)))
+ System.err.println(l);
+ System.out.println("Done.");
+
+ // Patch the control-flow graph. We insert a new call from the main() method
+ // to our artificial helper method "otherMethod".
+ System.out.println("Patching cfg...");
+ SootMethod helperMethod = Scene.v().getMainClass().getMethodByName("otherMethod");
+ helperMethod.retrieveActiveBody();
+
+ Local localTestMe = null;
+ Local localFoo = null;
+ for (Local l : Scene.v().getMainMethod().getActiveBody().getLocals()) {
+ if (l.getName().equals("r0"))
+ localTestMe = l;
+ else if (l.getName().equals("r1"))
+ localFoo = l;
+ }
+ StaticInvokeExpr invokeExpr = Jimple.v().newStaticInvokeExpr(helperMethod.makeRef(), localTestMe);
+ assert localTestMe != null;
+ assert localFoo != null;
+
+ AssignStmt invokeStmt = Jimple.v().newAssignStmt(localFoo, invokeExpr);
+ for (Unit u : Scene.v().getMainMethod().getActiveBody().getUnits())
+ if (u.toString().contains("doFoo")) {
+ Scene.v().getMainMethod().getActiveBody().getUnits().insertBefore (invokeStmt, u);
+ break;
+ }
+
+ CallGraph cg = Scene.v().getCallGraph();
+ Edge edge = new Edge(Scene.v().getMainMethod(), invokeStmt, helperMethod);
+ cg.addEdge(edge);
+
+ // Check that our new method is indeed reachable
+ List eps = new ArrayList();
+ eps.addAll(Scene.v().getEntryPoints());
+ ReachableMethods reachableMethods = new ReachableMethods(cg, eps.iterator());
+ reachableMethods.update();
+ boolean found = false;
+ for(Iterator iter = reachableMethods.listener(); iter.hasNext(); ) {
+ SootMethod m = iter.next().method();
+ if (m.getName().equals("otherMethod"))
+ found = true;
+ }
+ if (found)
+ System.out.println("Patched method found");
+ else
+ System.err.println("Patched method NOT found");
+
+ // Patch the control-flow graph. We add an assignment to the
+ // "foo" variable inside the loop
+ /*
+ System.out.println("Patching cfg...");
+ Local fooLocal = null;
+ Local argsLocal = null;
+ for (Local l : Scene.v().getMainMethod().getActiveBody().getLocals())
+ if (l.getName().equals("r1"))
+ fooLocal = l;
+ else if (l.getName().equals("r0"))
+ argsLocal = l;
+ AssignStmt assignStmt = Jimple.v().newAssignStmt(fooLocal, argsLocal);
+ JAssignStmt point = null;
+ for (Unit unit : Scene.v().getMainMethod().getActiveBody().getUnits()) {
+ if (unit instanceof JAssignStmt) {
+ JAssignStmt stmt = (JAssignStmt) unit;
+ if (stmt.getLeftOp().toString().equals("i0"))
+ if (stmt.getRightOp().toString().equals("i0 + -1")) {
+ point = stmt;
+ break;
+ }
+ }
+ }
+ if (point == null) {
+ System.err.println("Injection point not found");
+ return;
+ }
+ Scene.v().getMainMethod().getActiveBody().getUnits().insertBefore (assignStmt, point);
+ */
+
+ System.out.println("Running IFDS on patched CFG...");
+
+ JimpleBasedInterproceduralCFG cfg = new JimpleBasedInterproceduralCFG();
+ solver.update(cfg);
+
+ ret = Scene.v().getMainMethod().getActiveBody().getUnits().getLast();
+ for (UpdatableWrapper l: solver.ifdsResultsAt(problem.interproceduralCFG().wrapWeak(ret))) {
+ System.err.println(l);
+ }
+ System.out.println("Done.");
+ }
+ }));
+
+ soot.Main.main(args);
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/MustSynchronize.java b/src/soot/jimple/interproc/ifds/MustSynchronize.java
new file mode 100644
index 0000000..b3ffa05
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/MustSynchronize.java
@@ -0,0 +1,10 @@
+package soot.jimple.interproc.ifds;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+import java.lang.annotation.Target;
+
+/** Semantic annotation stating that the annotated field must be synchronized.
+ * This annotation is meant as a structured comment only, and has no immediate effect. */
+@Target(FIELD)
+public @interface MustSynchronize{ String value() default ""; }
\ No newline at end of file
diff --git a/src/soot/jimple/interproc/ifds/ProfiledFlowFunctions.java b/src/soot/jimple/interproc/ifds/ProfiledFlowFunctions.java
new file mode 100644
index 0000000..512bba3
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/ProfiledFlowFunctions.java
@@ -0,0 +1,48 @@
+package soot.jimple.interproc.ifds;
+
+/**
+ * A wrapper that can be used to profile flow functions.
+ */
+public class ProfiledFlowFunctions implements FlowFunctions {
+
+ protected final FlowFunctions delegate;
+
+ public long durationNormal, durationCall, durationReturn, durationCallReturn;
+
+ public ProfiledFlowFunctions(FlowFunctions delegate) {
+ this.delegate = delegate;
+ }
+
+ public FlowFunction getNormalFlowFunction(N curr, N succ) {
+ long before = System.currentTimeMillis();
+ FlowFunction ret = delegate.getNormalFlowFunction(curr, succ);
+ long duration = System.currentTimeMillis() - before;
+ durationNormal += duration;
+ return ret;
+ }
+
+ public FlowFunction getCallFlowFunction(N callStmt, M destinationMethod) {
+ long before = System.currentTimeMillis();
+ FlowFunction res = delegate.getCallFlowFunction(callStmt, destinationMethod);
+ long duration = System.currentTimeMillis() - before;
+ durationCall += duration;
+ return res;
+ }
+
+ public FlowFunction getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite) {
+ long before = System.currentTimeMillis();
+ FlowFunction res = delegate.getReturnFlowFunction(callSite, calleeMethod, exitStmt, returnSite);
+ long duration = System.currentTimeMillis() - before;
+ durationReturn += duration;
+ return res;
+ }
+
+ public FlowFunction getCallToReturnFlowFunction(N callSite, N returnSite) {
+ long before = System.currentTimeMillis();
+ FlowFunction res = delegate.getCallToReturnFlowFunction(callSite, returnSite);
+ long duration = System.currentTimeMillis() - before;
+ durationCallReturn += duration;
+ return res;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/SynchronizedBy.java b/src/soot/jimple/interproc/ifds/SynchronizedBy.java
new file mode 100644
index 0000000..a4c6245
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/SynchronizedBy.java
@@ -0,0 +1,10 @@
+package soot.jimple.interproc.ifds;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+import java.lang.annotation.Target;
+
+/** Semantic annotation that the annotated field is synchronized.
+ * This annotation is meant as a structured comment only, and has no immediate effect. */
+@Target(FIELD)
+public @interface SynchronizedBy{ String value() default ""; }
\ No newline at end of file
diff --git a/src/soot/jimple/interproc/ifds/ThreadSafe.java b/src/soot/jimple/interproc/ifds/ThreadSafe.java
new file mode 100644
index 0000000..70f3985
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/ThreadSafe.java
@@ -0,0 +1,10 @@
+package soot.jimple.interproc.ifds;
+
+/**
+ * This annotation tells that the class was designed to be used by multiple threads, with concurrent updates.
+ */
+public @interface ThreadSafe {
+
+ String value() default "";
+
+}
diff --git a/src/soot/jimple/interproc/ifds/ZeroedFlowFunctions.java b/src/soot/jimple/interproc/ifds/ZeroedFlowFunctions.java
new file mode 100644
index 0000000..52d4eb9
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/ZeroedFlowFunctions.java
@@ -0,0 +1,55 @@
+package soot.jimple.interproc.ifds;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class ZeroedFlowFunctions implements FlowFunctions {
+
+ protected final FlowFunctions delegate;
+ protected final D zeroValue;
+
+ public ZeroedFlowFunctions(FlowFunctions delegate, D zeroValue) {
+ this.delegate = delegate;
+ this.zeroValue = zeroValue;
+ }
+
+ public FlowFunction getNormalFlowFunction(N curr, N succ) {
+ return new ZeroedFlowFunction(delegate.getNormalFlowFunction(curr, succ));
+ }
+
+ public FlowFunction getCallFlowFunction(N callStmt, M destinationMethod) {
+ return new ZeroedFlowFunction(delegate.getCallFlowFunction(callStmt, destinationMethod));
+ }
+
+ public FlowFunction getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite) {
+ return new ZeroedFlowFunction(delegate.getReturnFlowFunction(callSite, calleeMethod, exitStmt, returnSite));
+ }
+
+ public FlowFunction getCallToReturnFlowFunction(N callSite, N returnSite) {
+ return new ZeroedFlowFunction(delegate.getCallToReturnFlowFunction(callSite, returnSite));
+ }
+
+ protected class ZeroedFlowFunction implements FlowFunction {
+
+ protected FlowFunction del;
+
+ private ZeroedFlowFunction(FlowFunction del) {
+ this.del = del;
+ }
+
+ @Override
+ public Set computeTargets(D source) {
+ if (source == zeroValue || source.equals(zeroValue)) {
+ HashSet res = new LinkedHashSet(del.computeTargets(source));
+ res.add(zeroValue);
+ return res;
+ } else {
+ return del.computeTargets(source);
+ }
+ }
+
+ }
+
+
+}
diff --git a/src/soot/jimple/interproc/ifds/edgefunc/AllBottom.java b/src/soot/jimple/interproc/ifds/edgefunc/AllBottom.java
new file mode 100644
index 0000000..75222ba
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/edgefunc/AllBottom.java
@@ -0,0 +1,74 @@
+package soot.jimple.interproc.ifds.edgefunc;
+
+import soot.jimple.interproc.ifds.EdgeFunction;
+
+
+public class AllBottom implements EdgeFunction {
+
+ private final V bottomElement;
+
+ public AllBottom(V bottomElement){
+ this.bottomElement = bottomElement;
+ }
+
+ @Override
+ public V computeTarget(V source) {
+ return bottomElement;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EdgeFunction composeWith(EdgeFunction secondFunction) {
+ if (secondFunction instanceof AllBottomInverse)
+ if (((AllBottomInverse) secondFunction).getBottomElement() == this.bottomElement)
+ return EdgeIdentity.v();
+
+ return secondFunction;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EdgeFunction joinWith(EdgeFunction otherFunction) {
+ // For otherFunction in {allTop, allBottom, id}, we always get allBottom
+ if(otherFunction == this || otherFunction.equalTo(this)) return this;
+ if(otherFunction instanceof AllBottomInverse)
+ if (((AllBottomInverse) otherFunction).getBottomElement() == this.bottomElement)
+ return this;
+ if(otherFunction instanceof AllTop) {
+ return this;
+ }
+ if(otherFunction instanceof EdgeIdentity) {
+ return this;
+ }
+ throw new IllegalStateException("(AllBottom) unexpected edge function: "+otherFunction);
+ }
+
+ @Override
+ public boolean equalTo(EdgeFunction other) {
+ if(other instanceof AllBottom) {
+ @SuppressWarnings("rawtypes")
+ AllBottom allBottom = (AllBottom) other;
+ return allBottom.bottomElement.equals(bottomElement);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "allbottom";
+ }
+
+ @Override
+ public EdgeFunction invert() {
+ return new AllBottomInverse(bottomElement);
+ }
+
+ /**
+ * Gets the bottom element on which this function was constructed
+ * @return The bottom element on which this function was constructed
+ */
+ V getBottomElement() {
+ return this.bottomElement;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/edgefunc/AllBottomInverse.java b/src/soot/jimple/interproc/ifds/edgefunc/AllBottomInverse.java
new file mode 100644
index 0000000..f53eaa8
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/edgefunc/AllBottomInverse.java
@@ -0,0 +1,76 @@
+package soot.jimple.interproc.ifds.edgefunc;
+
+import soot.jimple.interproc.ifds.EdgeFunction;
+
+/**
+ * Inverse function of {@link AllBottom}
+ */
+public class AllBottomInverse implements EdgeFunction {
+
+ private final V bottomElement;
+
+ public AllBottomInverse(V bottomElement){
+ this.bottomElement = bottomElement;
+ }
+
+ @Override
+ public V computeTarget(V source) {
+ return bottomElement;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EdgeFunction composeWith(EdgeFunction secondFunction) {
+ if (secondFunction instanceof AllBottom)
+ if (((AllBottom) secondFunction).getBottomElement() == this.bottomElement)
+ return this;
+ if (secondFunction instanceof EdgeIdentity)
+ return this;
+
+ throw new RuntimeException("Unknown function composition");
+ }
+
+ @Override
+ public EdgeFunction joinWith(EdgeFunction otherFunction) {
+ // For otherFunction in {allTop, allBottom, id}, we always get allBottom
+ if(otherFunction == this || otherFunction.equalTo(this)) return this;
+ if(otherFunction instanceof AllBottom)
+ return EdgeIdentity.v();
+ if(otherFunction instanceof AllTopInverse) {
+ return this;
+ }
+ if(otherFunction instanceof EdgeIdentity) {
+ return this;
+ }
+ throw new IllegalStateException("(AllBottomInverse) unexpected edge function: "+otherFunction);
+ }
+
+ @Override
+ public boolean equalTo(EdgeFunction other) {
+ if(other instanceof AllBottomInverse) {
+ @SuppressWarnings("rawtypes")
+ AllBottomInverse allBottom = (AllBottomInverse) other;
+ return allBottom.bottomElement.equals(bottomElement);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "allbottominverse";
+ }
+
+ @Override
+ public EdgeFunction invert() {
+ return new AllBottom(bottomElement);
+ }
+
+ /**
+ * Gets the bottom element on which this function was constructed
+ * @return The bottom element on which this function was constructed
+ */
+ V getBottomElement() {
+ return this.bottomElement;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/edgefunc/AllTop.java b/src/soot/jimple/interproc/ifds/edgefunc/AllTop.java
new file mode 100644
index 0000000..451e40a
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/edgefunc/AllTop.java
@@ -0,0 +1,62 @@
+package soot.jimple.interproc.ifds.edgefunc;
+
+import soot.jimple.interproc.ifds.EdgeFunction;
+
+
+public class AllTop implements EdgeFunction {
+
+ private final V topElement;
+
+ public AllTop(V topElement){
+ this.topElement = topElement;
+ }
+
+ @Override
+ public V computeTarget(V source) {
+ return topElement;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EdgeFunction composeWith(EdgeFunction secondFunction) {
+ if (secondFunction instanceof AllTopInverse)
+ if (((AllTopInverse) secondFunction).getTopElement() == this.topElement)
+ return EdgeIdentity.v();
+
+ return secondFunction;
+ }
+
+ @Override
+ public EdgeFunction joinWith(EdgeFunction otherFunction) {
+ return otherFunction;
+ }
+
+ @Override
+ public boolean equalTo(EdgeFunction other) {
+ if(other instanceof AllTop) {
+ @SuppressWarnings("rawtypes")
+ AllTop allTop = (AllTop) other;
+ return allTop.topElement.equals(topElement);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "alltop";
+ }
+
+ @Override
+ public EdgeFunction invert() {
+ return new AllTopInverse(this.topElement);
+ }
+
+ /**
+ * Gets the top element on which this function was constructed
+ * @return The top element on which this function was constructed
+ */
+ V getTopElement() {
+ return this.topElement;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/edgefunc/AllTopInverse.java b/src/soot/jimple/interproc/ifds/edgefunc/AllTopInverse.java
new file mode 100644
index 0000000..0842884
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/edgefunc/AllTopInverse.java
@@ -0,0 +1,62 @@
+package soot.jimple.interproc.ifds.edgefunc;
+
+import soot.jimple.interproc.ifds.EdgeFunction;
+
+
+public class AllTopInverse implements EdgeFunction {
+
+ private final V topElement;
+
+ public AllTopInverse(V topElement){
+ this.topElement = topElement;
+ }
+
+ @Override
+ public V computeTarget(V source) {
+ return topElement;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EdgeFunction composeWith(EdgeFunction secondFunction) {
+ if (secondFunction instanceof AllTop)
+ if (((AllTop) secondFunction).getTopElement() == this.topElement)
+ return EdgeIdentity.v();
+
+ throw new RuntimeException("Unknown function composition");
+ }
+
+ @Override
+ public EdgeFunction joinWith(EdgeFunction otherFunction) {
+ return otherFunction;
+ }
+
+ @Override
+ public boolean equalTo(EdgeFunction other) {
+ if(other instanceof AllTopInverse) {
+ @SuppressWarnings("rawtypes")
+ AllTopInverse allTop = (AllTopInverse) other;
+ return allTop.topElement.equals(topElement);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "alltop";
+ }
+
+ @Override
+ public EdgeFunction invert() {
+ return new AllTop(this.topElement);
+ }
+
+ /**
+ * Gets the top element on which this function was constructed
+ * @return The top element on which this function was constructed
+ */
+ V getTopElement() {
+ return this.topElement;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/edgefunc/EdgeIdentity.java b/src/soot/jimple/interproc/ifds/edgefunc/EdgeIdentity.java
new file mode 100644
index 0000000..1bf4344
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/edgefunc/EdgeIdentity.java
@@ -0,0 +1,60 @@
+package soot.jimple.interproc.ifds.edgefunc;
+
+import soot.jimple.interproc.ifds.EdgeFunction;
+
+/**
+ * The identity function on graph edges
+ * @param The type of values to be computed along flow edges.
+ */
+public class EdgeIdentity implements EdgeFunction {
+
+ @SuppressWarnings("rawtypes")
+ private final static EdgeIdentity instance = new EdgeIdentity();
+
+ private EdgeIdentity(){} //use v() instead
+
+ @Override
+ public V computeTarget(V source) {
+ return source;
+ }
+
+ @Override
+ public EdgeFunction composeWith(EdgeFunction secondFunction) {
+ return secondFunction;
+ }
+
+ @Override
+ public EdgeFunction joinWith(EdgeFunction otherFunction) {
+ if(otherFunction == this || otherFunction.equalTo(this)) return this;
+ if(otherFunction instanceof AllBottom) {
+ return otherFunction;
+ }
+ if(otherFunction instanceof AllTop) {
+ return this;
+ }
+ //do not know how to join; hence ask other function to decide on this
+ return otherFunction.joinWith(this);
+ }
+
+ @Override
+ public boolean equalTo(EdgeFunction other) {
+ //singleton
+ return other==this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static EdgeIdentity v() {
+ return instance;
+ }
+
+ @Override
+ public String toString() {
+ return "id";
+ }
+
+ @Override
+ public EdgeFunction invert() {
+ return this;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/flowfunc/Gen.java b/src/soot/jimple/interproc/ifds/flowfunc/Gen.java
new file mode 100644
index 0000000..090f5b9
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/flowfunc/Gen.java
@@ -0,0 +1,38 @@
+package soot.jimple.interproc.ifds.flowfunc;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import soot.jimple.interproc.ifds.FlowFunction;
+
+/**
+ * Function that creates a new value (e.g. returns a set containing a fixed value when given
+ * a specific parameter), but acts like the identity function for all other parameters.
+ *
+ * @param The type of data-flow facts to be computed by the tabulation problem.
+ */
+public class Gen implements FlowFunction {
+
+ private final D genValue;
+ private final D zeroValue;
+
+ public Gen(D genValue, D zeroValue){
+ assert genValue != null;
+ assert zeroValue != null;
+
+ this.genValue = genValue;
+ this.zeroValue = zeroValue;
+ }
+
+ public Set computeTargets(D source) {
+ if (source.equals(zeroValue)) {
+ HashSet res = new HashSet();
+ res.add(source);
+ res.add(genValue);
+ return res;
+ } else
+ return Collections.singleton(source);
+ }
+
+}
\ No newline at end of file
diff --git a/src/soot/jimple/interproc/ifds/flowfunc/Identity.java b/src/soot/jimple/interproc/ifds/flowfunc/Identity.java
new file mode 100644
index 0000000..6a97ec6
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/flowfunc/Identity.java
@@ -0,0 +1,24 @@
+package soot.jimple.interproc.ifds.flowfunc;
+
+import java.util.Collections;
+import java.util.Set;
+
+import soot.jimple.interproc.ifds.FlowFunction;
+
+public class Identity implements FlowFunction {
+
+ @SuppressWarnings("rawtypes")
+ private final static Identity instance = new Identity();
+
+ private Identity(){} //use v() instead
+
+ public Set computeTargets(D source) {
+ return Collections.singleton(source);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Identity v() {
+ return instance;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/flowfunc/Kill.java b/src/soot/jimple/interproc/ifds/flowfunc/Kill.java
new file mode 100644
index 0000000..9f55b02
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/flowfunc/Kill.java
@@ -0,0 +1,30 @@
+package soot.jimple.interproc.ifds.flowfunc;
+
+import java.util.Collections;
+import java.util.Set;
+
+import soot.jimple.interproc.ifds.FlowFunction;
+
+/**
+ * Function that kills a specific value (i.e. returns an empty set for when given this
+ * value as an argument), but behaves like the identity function for all other values.
+ *
+ * @param The type of data-flow facts to be computed by the tabulation problem.
+ */
+public class Kill implements FlowFunction {
+
+ private final D killValue;
+
+ public Kill(D killValue){
+ assert killValue != null;
+ this.killValue = killValue;
+ }
+
+ public Set computeTargets(D source) {
+ if (source == killValue || source.equals(killValue)) {
+ return Collections.emptySet();
+ } else
+ return Collections.singleton(source);
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/flowfunc/KillAll.java b/src/soot/jimple/interproc/ifds/flowfunc/KillAll.java
new file mode 100644
index 0000000..6b0deb5
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/flowfunc/KillAll.java
@@ -0,0 +1,30 @@
+package soot.jimple.interproc.ifds.flowfunc;
+
+import java.util.Collections;
+import java.util.Set;
+
+import soot.jimple.interproc.ifds.FlowFunction;
+
+/**
+ * The empty function, i.e. a function which returns an empty set for all points
+ * in the definition space.
+ *
+ * @param The type of data-flow facts to be computed by the tabulation problem.
+ */
+public class KillAll implements FlowFunction {
+
+ @SuppressWarnings("rawtypes")
+ private final static KillAll instance = new KillAll();
+
+ private KillAll(){} //use v() instead
+
+ public Set computeTargets(D source) {
+ return Collections.emptySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static KillAll v() {
+ return instance;
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/flowfunc/Transfer.java b/src/soot/jimple/interproc/ifds/flowfunc/Transfer.java
new file mode 100644
index 0000000..1eb8262
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/flowfunc/Transfer.java
@@ -0,0 +1,35 @@
+package soot.jimple.interproc.ifds.flowfunc;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import soot.jimple.interproc.ifds.FlowFunction;
+
+public class Transfer implements FlowFunction {
+
+ private final D toValue;
+ private final D fromValue;
+
+ public Transfer(D toValue, D fromValue){
+ assert toValue != null;
+ assert fromValue != null;
+
+ this.toValue = toValue;
+ this.fromValue = fromValue;
+ }
+
+ public Set computeTargets(D source) {
+ if (source == fromValue || source.equals(fromValue)) {
+ HashSet res = new HashSet();
+ res.add(source);
+ res.add(toValue);
+ return res;
+ } else if (source.equals(toValue)) {
+ return Collections.emptySet();
+ } else {
+ return Collections.singleton(source);
+ }
+ }
+
+}
diff --git a/src/soot/jimple/interproc/ifds/problems/IFDSLocalInfoFlow.java b/src/soot/jimple/interproc/ifds/problems/IFDSLocalInfoFlow.java
new file mode 100644
index 0000000..f14688c
--- /dev/null
+++ b/src/soot/jimple/interproc/ifds/problems/IFDSLocalInfoFlow.java
@@ -0,0 +1,149 @@
+package soot.jimple.interproc.ifds.problems;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import soot.Local;
+import soot.NullType;
+import soot.Scene;
+import soot.SootMethod;
+import soot.Unit;
+import soot.Value;
+import soot.jimple.AssignStmt;
+import soot.jimple.DefinitionStmt;
+import soot.jimple.IdentityStmt;
+import soot.jimple.InvokeExpr;
+import soot.jimple.ParameterRef;
+import soot.jimple.ReturnStmt;
+import soot.jimple.Stmt;
+import soot.jimple.internal.JimpleLocal;
+import soot.jimple.interproc.ifds.FlowFunction;
+import soot.jimple.interproc.ifds.FlowFunctions;
+import soot.jimple.interproc.ifds.InterproceduralCFG;
+import soot.jimple.interproc.ifds.flowfunc.Gen;
+import soot.jimple.interproc.ifds.flowfunc.Identity;
+import soot.jimple.interproc.ifds.flowfunc.Kill;
+import soot.jimple.interproc.ifds.flowfunc.KillAll;
+import soot.jimple.interproc.ifds.flowfunc.Transfer;
+import soot.jimple.interproc.ifds.template.DefaultIFDSTabulationProblem;
+import soot.jimple.interproc.incremental.DefaultUpdatableWrapper;
+import soot.jimple.interproc.incremental.UpdatableWrapper;
+
+public class IFDSLocalInfoFlow extends
+ DefaultIFDSTabulationProblem,
+ InterproceduralCFG, UpdatableWrapper>> {
+
+ private static final UpdatableWrapper zeroValue = new DefaultUpdatableWrapper
+ (new JimpleLocal("zero", NullType.v()));
+
+ public IFDSLocalInfoFlow(InterproceduralCFG,UpdatableWrapper> icfg) {
+ super(icfg);
+ }
+
+ public FlowFunctions, UpdatableWrapper, UpdatableWrapper> createFlowFunctionsFactory() {
+ return new FlowFunctions,UpdatableWrapper,UpdatableWrapper>() {
+
+ @Override
+ public FlowFunction> getNormalFlowFunction
+ (UpdatableWrapper src, UpdatableWrapper dest) {
+ if (src.getContents() instanceof IdentityStmt
+ && interproceduralCFG().getMethodOf(src)==interproceduralCFG().wrapWeak(Scene.v().getMainMethod())) {
+ IdentityStmt is = (IdentityStmt) src.getContents();
+ Local leftLocal = (Local) is.getLeftOp();
+ Value right = is.getRightOp();
+ if (right instanceof ParameterRef) {
+ return new Gen>
+ (interproceduralCFG().wrapWeak(leftLocal), zeroValue());
+ }
+ }
+
+ if(src.getContents() instanceof AssignStmt) {
+ AssignStmt assignStmt = (AssignStmt) src.getContents();
+ Value right = assignStmt.getRightOp();
+ if(assignStmt.getLeftOp() instanceof Local) {
+ final Local leftLocal = (Local) assignStmt.getLeftOp();
+ if(right instanceof Local) {
+ final Local rightLocal = (Local) right;
+ return new Transfer