/** * @return a Relation object to track implicit equations using the operator */ private static IBinaryNaturalRelation makeRelation(AbstractOperator op) { byte[] implementation = null; if (op instanceof AssignOperator) { // lots of assignments. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY, BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } else { // assume sparse assignments with any other operator. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } return new BasicNaturalRelation(implementation, BasicNaturalRelation.SIMPLE); }
/** * @return a Relation object to track implicit equations using the operator */ private static IBinaryNaturalRelation makeRelation(AbstractOperator op) { byte[] implementation = null; if (op instanceof AssignOperator) { // lots of assignments. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY, BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } else { // assume sparse assignments with any other operator. implementation = new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }; } return new BasicNaturalRelation(implementation, BasicNaturalRelation.SIMPLE); }
/** * If normalOutCount == n, this edge manager will eagerly allocated n words to * hold out edges for each node. (performance optimization for time) * * @param nodeManager * an object to track nodes * @param normalCase * what is the "normal" number of out edges for a node? * @throws IllegalArgumentException if normalCase < 0 */ public SparseNumberedEdgeManager(NumberedNodeManager<T> nodeManager, int normalCase, byte delegateImpl) throws IllegalArgumentException { if (nodeManager == null) { throw new IllegalArgumentException("null nodeManager"); } if (normalCase < 0) { throw new IllegalArgumentException("normalCase < 0"); } this.nodeManager = nodeManager; if (normalCase == 0) { successors = new BasicNaturalRelation(defaultImpl, delegateImpl); predecessors = new BasicNaturalRelation(defaultImpl, delegateImpl); } else { byte[] impl = new byte[normalCase]; Arrays.fill(impl, BasicNaturalRelation.SIMPLE); successors = new BasicNaturalRelation(impl, delegateImpl); predecessors = new BasicNaturalRelation(impl, delegateImpl); } }
/** * If normalOutCount == n, this edge manager will eagerly allocated n words to * hold out edges for each node. (performance optimization for time) * * @param nodeManager * an object to track nodes * @param normalCase * what is the "normal" number of out edges for a node? * @throws IllegalArgumentException if normalCase < 0 */ public SparseNumberedEdgeManager(NumberedNodeManager<T> nodeManager, int normalCase, byte delegateImpl) throws IllegalArgumentException { if (nodeManager == null) { throw new IllegalArgumentException("null nodeManager"); } if (normalCase < 0) { throw new IllegalArgumentException("normalCase < 0"); } this.nodeManager = nodeManager; if (normalCase == 0) { successors = new BasicNaturalRelation(defaultImpl, delegateImpl); predecessors = new BasicNaturalRelation(defaultImpl, delegateImpl); } else { byte[] impl = new byte[normalCase]; Arrays.fill(impl, BasicNaturalRelation.SIMPLE); successors = new BasicNaturalRelation(impl, delegateImpl); predecessors = new BasicNaturalRelation(impl, delegateImpl); } }
/** * If normalOutCount == n, this edge manager will eagerly allocated n words to * hold out edges for each node. (performance optimization for time) * * @param nodeManager * an object to track nodes * @param normalCase * what is the "normal" number of out edges for a node? * @throws IllegalArgumentException if normalCase < 0 */ public SparseNumberedEdgeManager(NumberedNodeManager<T> nodeManager, int normalCase, byte delegateImpl) throws IllegalArgumentException { if (nodeManager == null) { throw new IllegalArgumentException("null nodeManager"); } if (normalCase < 0) { throw new IllegalArgumentException("normalCase < 0"); } this.nodeManager = nodeManager; if (normalCase == 0) { successors = new BasicNaturalRelation(defaultImpl, delegateImpl); predecessors = new BasicNaturalRelation(defaultImpl, delegateImpl); } else { byte[] impl = new byte[normalCase]; Arrays.fill(impl, BasicNaturalRelation.SIMPLE); successors = new BasicNaturalRelation(impl, delegateImpl); predecessors = new BasicNaturalRelation(impl, delegateImpl); } }
/** * @return R, y \in R(x,y) if the node y is a predecessor of node x */ private IBinaryNaturalRelation computePredecessors(NumberedNodeManager<Object> nodeManager) { BasicNaturalRelation R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE }, BasicNaturalRelation.SIMPLE); // we split the following loops to improve temporal locality, // particularly for locals computePredecessorsForNonLocals(nodeManager, R); computePredecessorsForLocals(nodeManager, R); return R; }
/** * @return R, y \in R(x,y) if the node y is a predecessor of node x */ private IBinaryNaturalRelation computePredecessors(NumberedNodeManager<Object> nodeManager) { BasicNaturalRelation R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE }, BasicNaturalRelation.SIMPLE); // we split the following loops to improve temporal locality, // particularly for locals computePredecessorsForNonLocals(nodeManager, R); computePredecessorsForLocals(nodeManager, R); return R; }
/** * Compute a relation R s.t. (i,j) \in R iff (i,j) is a backedge according to a DFS of a numbered graph starting from some root. * * Not efficient. Recursive and uses hash sets. */ public static <T> IBinaryNaturalRelation computeBackEdges(NumberedGraph<T> G, T root) { if (G == null) { throw new IllegalArgumentException("G is null"); } final BasicNaturalRelation result = new BasicNaturalRelation(); // for large methods (e.g. obfuscated library code as found in android libraries 'com.google.ads.ad.a([B[B)V') // the recursive dfs can lead to a stack overflow error. // for smaller methods the recursive solution seems to be faster, so we keep it. if (G.getNumberOfNodes() <= THRESHOLD_FOR_NONRECURSIVE_DFS) { final Set<T> visited = HashSetFactory.make(); final Set<T> onstack = HashSetFactory.make(); dfs(result, root, G, visited, onstack); } else { dfsNonRecursive(result, root, G); } return result; }
/** * Compute a relation R s.t. (i,j) \in R iff (i,j) is a backedge according to a DFS of a numbered graph starting from some root. * * Not efficient. Recursive and uses hash sets. */ public static <T> IBinaryNaturalRelation computeBackEdges(NumberedGraph<T> G, T root) { if (G == null) { throw new IllegalArgumentException("G is null"); } final BasicNaturalRelation result = new BasicNaturalRelation(); // for large methods (e.g. obfuscated library code as found in android libraries 'com.google.ads.ad.a([B[B)V') // the recursive dfs can lead to a stack overflow error. // for smaller methods the recursive solution seems to be faster, so we keep it. if (G.getNumberOfNodes() <= THRESHOLD_FOR_NONRECURSIVE_DFS) { final Set<T> visited = HashSetFactory.make(); final Set<T> onstack = HashSetFactory.make(); dfs(result, root, G, visited, onstack); } else { dfsNonRecursive(result, root, G); } return result; }
/** * Compute a relation R s.t. (i,j) \in R iff (i,j) is a backedge according to a DFS of a numbered graph starting from some root. * * Not efficient. Recursive and uses hash sets. */ public static <T> IBinaryNaturalRelation computeBackEdges(NumberedGraph<T> G, T root) { if (G == null) { throw new IllegalArgumentException("G is null"); } final BasicNaturalRelation result = new BasicNaturalRelation(); // for large methods (e.g. obfuscated library code as found in android libraries 'com.google.ads.ad.a([B[B)V') // the recursive dfs can lead to a stack overflow error. // for smaller methods the recursive solution seems to be faster, so we keep it. if (G.getNumberOfNodes() <= THRESHOLD_FOR_NONRECURSIVE_DFS) { final Set<T> visited = HashSetFactory.make(); final Set<T> onstack = HashSetFactory.make(); dfs(result, root, G, visited, onstack); } else { dfsNonRecursive(result, root, G); } return result; }
/** * Record a summary edge for the flow d1 -> d2 from an entry s_p to an exit x. * * @param s_p local block number an entry * @param x local block number of an exit block * @param d1 source dataflow fact * @param d2 target dataflow fact */ public void insertSummaryEdge(int s_p, int x, int d1, int d2) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { // we expect R to usually be sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.SIMPLE); summaries.set(n, R); } R.add(d1, d2); // if (TabulationSolver.DEBUG_LEVEL > 1) { // // System.err.println("recording summary edge, now n=" + n + " summarized by " + R); // } }
/** * Record a summary edge for the flow d1 -> d2 from an entry s_p to an exit x. * * @param s_p local block number an entry * @param x local block number of an exit block * @param d1 source dataflow fact * @param d2 target dataflow fact */ public void insertSummaryEdge(int s_p, int x, int d1, int d2) { int n = getIndexForEntryExitPair(s_p, x); IBinaryNaturalRelation R = summaries.get(n); if (R == null) { // we expect R to usually be sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.SIMPLE); summaries.set(n, R); } R.add(d1, d2); // if (TabulationSolver.DEBUG_LEVEL > 1) { // // System.err.println("recording summary edge, now n=" + n + " summarized by " + R); // } }
if (R == null) { R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); paths.set(j, R); if (R2 == null) { R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(i, R2);
if (R == null) { R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); paths.set(j, R); if (R2 == null) { R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(i, R2);
/** * Record that in this procedure we've discovered a same-level realizable path from (s_p,0) to (n,d_j) * * @param n local block number of the basic block n */ @SuppressWarnings("unused") private void addZeroPathEdge(int n, int j) { BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); if (z == null) { z = new BitVectorIntSet(); zeroPaths.set(j, z); } z.add(n); if (altPaths != null) { IBinaryNaturalRelation R = altPaths.get(0); if (R == null) { // we expect the first dimension of R to be dense, the second sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(0, R); } R.add(n, j); } if (TabulationSolver.DEBUG_LEVEL > 1) { System.err.println("recording 0-path edge, now d2= " + j + " reached at " + z); } }
/** * Record that in this procedure we've discovered a same-level realizable path from (s_p,0) to (n,d_j) * * @param n local block number of the basic block n */ @SuppressWarnings("unused") private void addZeroPathEdge(int n, int j) { BitVectorIntSet z = (BitVectorIntSet) zeroPaths.get(j); if (z == null) { z = new BitVectorIntSet(); zeroPaths.set(j, z); } z.add(n); if (altPaths != null) { IBinaryNaturalRelation R = altPaths.get(0); if (R == null) { // we expect the first dimension of R to be dense, the second sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(0, R); } R.add(n, j); } if (TabulationSolver.DEBUG_LEVEL > 1) { System.err.println("recording 0-path edge, now d2= " + j + " reached at " + z); } }
/** * Record that in this procedure we've discovered a same-level realizable path from (s_p,i) to (n,i) * * @param n local block number of the basic block n */ @SuppressWarnings("unused") private void addIdentityPathEdge(int i, int n) { BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); if (s == null) { s = new BitVectorIntSet(); identityPaths.set(i, s); } s.add(n); if (altPaths != null) { IBinaryNaturalRelation R2 = altPaths.get(i); if (R2 == null) { // we expect the first dimension of R to be dense, the second sparse R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(i, R2); } R2.add(n, i); } if (TabulationSolver.DEBUG_LEVEL > 1) { System.err.println("recording self-path edge, now d1= " + i + " reaches " + s); } }
/** * Record that in this procedure we've discovered a same-level realizable path from (s_p,i) to (n,i) * * @param n local block number of the basic block n */ @SuppressWarnings("unused") private void addIdentityPathEdge(int i, int n) { BitVectorIntSet s = (BitVectorIntSet) identityPaths.get(i); if (s == null) { s = new BitVectorIntSet(); identityPaths.set(i, s); } s.add(n); if (altPaths != null) { IBinaryNaturalRelation R2 = altPaths.get(i); if (R2 == null) { // we expect the first dimension of R to be dense, the second sparse R2 = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.SIMPLE_SPACE_STINGY }, BasicNaturalRelation.TWO_LEVEL); altPaths.set(i, R2); } R2.add(n, i); } if (TabulationSolver.DEBUG_LEVEL > 1) { System.err.println("recording self-path edge, now d1= " + i + " reaches " + s); } }
/** * Record that we've discovered a call edge <c,d1> -> <s_p, d2> * * @param c global number identifying the call site node * @param d1 source fact at the call edge * @param d2 result fact (result of the call flow function) */ @SuppressWarnings("unused") public void addCallEdge(int c, int d1, int d2) { if (TabulationSolver.DEBUG_LEVEL > 0) { System.err.println("addCallEdge " + c + ' ' + d1 + ' ' + d2); } if (d1 == d2) { BimodalMutableIntSet s = (BimodalMutableIntSet) identityEdges.get(d1); if (s == null) { s = new BimodalMutableIntSet(); identityEdges.set(d1, s); } s.add(c); } else { IBinaryNaturalRelation R = edges.get(d2); if (R == null) { // we expect the first dimension of R to be dense, the second sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.TWO_LEVEL }, BasicNaturalRelation.TWO_LEVEL); edges.set(d2, R); } R.add(c, d1); } }
/** * Record that we've discovered a call edge <c,d1> -> <s_p, d2> * * @param c global number identifying the call site node * @param d1 source fact at the call edge * @param d2 result fact (result of the call flow function) */ @SuppressWarnings("unused") public void addCallEdge(int c, int d1, int d2) { if (TabulationSolver.DEBUG_LEVEL > 0) { System.err.println("addCallEdge " + c + ' ' + d1 + ' ' + d2); } if (d1 == d2) { BimodalMutableIntSet s = (BimodalMutableIntSet) identityEdges.get(d1); if (s == null) { s = new BimodalMutableIntSet(); identityEdges.set(d1, s); } s.add(c); } else { IBinaryNaturalRelation R = edges.get(d2); if (R == null) { // we expect the first dimension of R to be dense, the second sparse R = new BasicNaturalRelation(new byte[] { BasicNaturalRelation.TWO_LEVEL }, BasicNaturalRelation.TWO_LEVEL); edges.set(d2, R); } R.add(c, d1); } }