diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java new file mode 100644 index 000000000..8e52b6297 --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/PathEdge.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.ibm.wala.dataflow.IFDS; + + +/** + * + * an individual edge -> + * + * @author sfink + */ +public final class PathEdge { + + final T entry; + final int d1; + final T target; + final int d2; + + public static PathEdge createPathEdge(T s_p, int d1, T n, int d2) { + return new PathEdge(s_p, d1, n, d2); + } + + private PathEdge(T s_p, int d1, T n, int d2) { + this.entry = s_p; + this.d1 = d1; + this.target = n; + this.d2 = d2; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(); + result.append("<"); + result.append(entry.toString()); + result.append(","); + result.append(d1); + result.append("> -> <"); + result.append(target.toString()); + result.append(","); + result.append(d2); + result.append(">"); + return result.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + d1; + result = prime * result + d2; + result = prime * result + ((target == null) ? 0 : target.hashCode()); + result = prime * result + ((entry == null) ? 0 : entry.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final PathEdge other = (PathEdge) obj; + if (d1 != other.d1) + return false; + if (d2 != other.d2) + return false; + if (target == null) { + if (other.target != null) + return false; + } else if (!target.equals(other.target)) + return false; + if (entry == null) { + if (other.entry != null) + return false; + } else if (!entry.equals(other.entry)) + return false; + return true; + } + + public int getD1() { + return d1; + } + + public int getD2() { + return d2; + } + + public T getEntry() { + return entry; + } + + public T getTarget() { + return target; + } +} \ No newline at end of file diff --git a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java index 4287de05b..a9ec3818d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java +++ b/com.ibm.wala.core/src/com/ibm/wala/dataflow/IFDS/TabulationSolver.java @@ -208,11 +208,11 @@ public class TabulationSolver { tendToSoftCaches(); } - final PathEdge edge = popFromWorkList(); + final PathEdge edge = popFromWorkList(); if (DEBUG_LEVEL > 0) { System.err.println("TABULATE " + edge); } - int j = merge(edge.s_p, edge.d1, edge.n, edge.d2); + int j = merge(edge.entry, edge.d1, edge.target, edge.d2); if (j == -1 && DEBUG_LEVEL > 0) { System.err.println("merge -1: DROPPING"); } @@ -221,12 +221,12 @@ public class TabulationSolver { // this means that we don't want to push the edge. instead, // we'll push the merged fact. a little tricky, but i think should // work. - propagate(edge.s_p, edge.d1, edge.n, j); + propagate(edge.entry, edge.d1, edge.target, j); } else { - if (supergraph.isCall(edge.n)) { + if (supergraph.isCall(edge.target)) { // [13] processCall(edge); - } else if (supergraph.isExit(edge.n)) { + } else if (supergraph.isExit(edge.target)) { // [21] processExit(edge); } else { @@ -274,16 +274,16 @@ public class TabulationSolver { * * @param edge */ - private void processNormal(final PathEdge edge) { + private void processNormal(final PathEdge edge) { if (DEBUG_LEVEL > 0) { System.err.println("process normal: " + edge); } - for (Iterator it = supergraph.getSuccNodes(edge.n); it.hasNext();) { + for (Iterator it = supergraph.getSuccNodes(edge.target); it.hasNext();) { final T m = it.next(); if (DEBUG_LEVEL > 0) { System.err.println("normal successor: " + m); } - IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.n, m); + IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); IntSet D3 = computeFlow(edge.d2, f); if (DEBUG_LEVEL > 0) { System.err.println(" reached: " + D3); @@ -291,7 +291,7 @@ public class TabulationSolver { if (D3 != null) { D3.foreach(new IntSetAction() { public void act(int d3) { - propagate(edge.s_p, edge.d1, m, d3); + propagate(edge.entry, edge.d1, m, d3); } }); } @@ -304,13 +304,13 @@ public class TabulationSolver { * Note that we've changed the way we record summary edges. Summary edges are now associated with a callee (s_p,exit), * where the original algorithm used a call, return pair in the caller. */ - protected void processExit(final PathEdge edge) { + protected void processExit(final PathEdge edge) { if (DEBUG_LEVEL > 0) { System.err.println("process exit: " + edge); } // succ:= successor nodes of edge.n (the return block in the callee) - IntSet succ = supergraph.getSuccNodeNumbers(edge.n); + IntSet succ = supergraph.getSuccNodeNumbers(edge.target); if (succ == null) { // This should only happen for return from the entry point of the supergraph // (fake root method for whole-program analysis). @@ -321,17 +321,17 @@ public class TabulationSolver { return; } - final LocalSummaryEdges summaries = findOrCreateLocalSummaryEdges(supergraph.getProcOf(edge.n)); - int s_p_n = supergraph.getLocalBlockNumber(edge.s_p); - int x = supergraph.getLocalBlockNumber(edge.n); + final LocalSummaryEdges summaries = findOrCreateLocalSummaryEdges(supergraph.getProcOf(edge.target)); + int s_p_n = supergraph.getLocalBlockNumber(edge.entry); + int x = supergraph.getLocalBlockNumber(edge.target); if (!summaries.contains(s_p_n, x, edge.d1, edge.d2)) { summaries.insertSummaryEdge(s_p_n, x, edge.d1, edge.d2); } - final CallFlowEdges callFlow = findOrCreateCallFlowEdges(edge.s_p); + final CallFlowEdges callFlow = findOrCreateCallFlowEdges(edge.entry); // [22] for each c /in callers(p) - for (Iterator it = supergraph.getPredNodes(edge.s_p); it.hasNext();) { + for (Iterator it = supergraph.getPredNodes(edge.entry); it.hasNext();) { final T c = it.next(); final int cNum = supergraph.getLocalBlockNumber(c); if (DEBUG_LEVEL > 0) { @@ -359,7 +359,7 @@ public class TabulationSolver { * @param c a call site of edge.s_p * @param D4 set of d1 s.t. -> was recorded as call flow */ - private void propagateToReturnSites(final PathEdge edge, IntSet succ, final T c, final IntSet D4) { + private void propagateToReturnSites(final PathEdge edge, IntSet succ, final T c, final IntSet D4) { if (DEBUG_LEVEL > 1) { System.err.println("Successor nodes: " + succ); @@ -396,7 +396,7 @@ public class TabulationSolver { if (DEBUG_LEVEL > 1) { System.err.println("feasible return site: " + retSite); } - final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(c, edge.n, retSite); + final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(c, edge.target, retSite); if (retf instanceof IBinaryReturnFlowFunction) { propagateToReturnSiteWithBinaryFlowFunction(edge, c, D4, entries, retSite, retf); } else { @@ -515,23 +515,23 @@ public class TabulationSolver { /** * Handle lines [14 - 19] of the algorithm, propagating information into and across a call site. */ - protected void processCall(final PathEdge edge) { + protected void processCall(final PathEdge edge) { if (DEBUG_LEVEL > 0) { System.err.println("process call: " + edge); } // c:= number of the call node - final int c = supergraph.getNumber(edge.n); + final int c = supergraph.getNumber(edge.target); - final Collection returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.n)); + final Collection returnSites = Iterator2Collection.toCollection(supergraph.getReturnSites(edge.target)); // [14 - 16] - for (Iterator it = supergraph.getCalledNodes(edge.n); it.hasNext();) { + for (Iterator it = supergraph.getCalledNodes(edge.target); it.hasNext();) { final T callee = it.next(); if (DEBUG_LEVEL > 0) { System.err.println(" process callee: " + callee); } - IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.n, callee); + IUnaryFlowFunction f = flowFunctionMap.getCallFlowFunction(edge.target, callee); // reached := {d1} that reach the callee IntSet reached = computeFlow(edge.d2, f); if (DEBUG_LEVEL > 0) { @@ -569,7 +569,7 @@ public class TabulationSolver { // was recorded as a summary edge IntSet reachedBySummary = summaries.getSummaryEdges(s_p_num, x_num, d1); if (reachedBySummary != null) { - final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(edge.n, exit, returnSite); + final IFlowFunction retf = flowFunctionMap.getReturnFlowFunction(edge.target, exit, returnSite); reachedBySummary.foreach(new IntSetAction() { public void act(int d2) { if (retf instanceof IBinaryReturnFlowFunction) { @@ -577,7 +577,7 @@ public class TabulationSolver { if (D5 != null) { D5.foreach(new IntSetAction() { public void act(int d5) { - propagate(edge.s_p, edge.d1, returnSite, d5); + propagate(edge.entry, edge.d1, returnSite, d5); } }); } @@ -586,7 +586,7 @@ public class TabulationSolver { if (D5 != null) { D5.foreach(new IntSetAction() { public void act(int d5) { - propagate(edge.s_p, edge.d1, returnSite, d5); + propagate(edge.entry, edge.d1, returnSite, d5); } }); } @@ -604,17 +604,17 @@ public class TabulationSolver { } // special logic: in backwards problems, a "call" node can have // "normal" successors as well. deal with these. - for (Iterator it = supergraph.getNormalSuccessors(edge.n); it.hasNext();) { + for (Iterator it = supergraph.getNormalSuccessors(edge.target); it.hasNext();) { final T m = it.next(); if (DEBUG_LEVEL > 0) { System.err.println("normal successor: " + m); } - IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.n, m); + IUnaryFlowFunction f = flowFunctionMap.getNormalFlowFunction(edge.target, m); IntSet D3 = computeFlow(edge.d2, f); if (D3 != null) { D3.foreach(new IntSetAction() { public void act(int d3) { - propagate(edge.s_p, edge.d1, m, d3); + propagate(edge.entry, edge.d1, m, d3); } }); } @@ -628,9 +628,9 @@ public class TabulationSolver { } IUnaryFlowFunction f = null; if (hasCallee(returnSite)) { - f = flowFunctionMap.getCallToReturnFlowFunction(edge.n, returnSite); + f = flowFunctionMap.getCallToReturnFlowFunction(edge.target, returnSite); } else { - f = flowFunctionMap.getCallNoneToReturnFlowFunction(edge.n, returnSite); + f = flowFunctionMap.getCallNoneToReturnFlowFunction(edge.target, returnSite); } IntSet reached = computeFlow(edge.d2, f); if (DEBUG_LEVEL > 0) { @@ -643,7 +643,7 @@ public class TabulationSolver { Assertions._assert(x >= 0); Assertions._assert(edge.d1 >= 0); } - propagate(edge.s_p, edge.d1, returnSite, x); + propagate(edge.entry, edge.d1, returnSite, x); } }); } @@ -700,13 +700,13 @@ public class TabulationSolver { return f.getSources(d2); } - protected PathEdge popFromWorkList() { - return (PathEdge) worklist.take(); + protected PathEdge popFromWorkList() { + return worklist.take() ; } private PathEdge peekFromWorkList() { // horrible. don't use in performance-critical - PathEdge result = (PathEdge) worklist.take(); + PathEdge result = worklist.take(); worklist.insert(result); return result; } @@ -784,7 +784,7 @@ public class TabulationSolver { } protected void addToWorkList(T s_p, int i, T n, int j) { - worklist.insert(new PathEdge(s_p, i, n, j)); + worklist.insert(PathEdge.createPathEdge(s_p, i, n, j)); } protected LocalPathEdges findOrCreateLocalPathEdges(T s_p) { @@ -818,82 +818,6 @@ public class TabulationSolver { return result; } - /** - * @author sfink - * - * an individual edge -> - */ - public final class PathEdge { - final T s_p; - - final int d1; - - final T n; - - final int d2; - - PathEdge(T s_p, int d1, T n, int d2) { - this.s_p = s_p; - this.d1 = d1; - this.n = n; - this.d2 = d2; - if (DEBUG_LEVEL > 0 && Assertions.verifyAssertions) { - if (!supergraph.containsNode(s_p)) { - Assertions._assert(false, s_p.toString()); - } - if (!supergraph.containsNode(n)) { - Assertions._assert(false, n.toString()); - } - } - } - - @Override - public String toString() { - StringBuffer result = new StringBuffer(); - result.append("<"); - result.append(s_p.toString()); - result.append(","); - result.append(d1); - result.append("> -> <"); - result.append(n.toString()); - result.append(","); - result.append(d2); - result.append(">"); - return result.toString(); - } - - @Override - public int hashCode() { - return s_p.hashCode() + d1 * 401 + n.hashCode() * 409 + d2 * 419; - } - - @Override - public boolean equals(Object arg0) { - if (getClass().equals(arg0.getClass())) { - PathEdge that = (PathEdge) arg0; - return d1 == that.d1 && d2 == that.d2 && s_p.equals(that.s_p) && (n.equals(that.n)); - } else { - return false; - } - } - - public int getD1() { - return d1; - } - - public int getD2() { - return d2; - } - - public Object getSp() { - return s_p; - } - - public Object getN() { - return n; - } - } - public class Result implements TabulationResult { /** @@ -1011,16 +935,14 @@ public class TabulationSolver { return supergraph; } - protected class Worklist extends Heap { + protected class Worklist extends Heap> { Worklist() { super(100); } @Override - protected boolean compareElements(Object elt1, Object elt2) { - PathEdge p1 = (PathEdge) elt1; - PathEdge p2 = (PathEdge) elt2; + protected boolean compareElements(PathEdge p1, PathEdge p2) { if (p1.d2 != p2.d2) { if (problem.getDomain().isWeakerThan(p1.d2, p2.d2)) { return true; diff --git a/com.ibm.wala.core/src/com/ibm/wala/fixedpoint/impl/Worklist.java b/com.ibm.wala.core/src/com/ibm/wala/fixedpoint/impl/Worklist.java index 4f434c98a..2c85d6517 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/fixedpoint/impl/Worklist.java +++ b/com.ibm.wala.core/src/com/ibm/wala/fixedpoint/impl/Worklist.java @@ -19,7 +19,7 @@ import com.ibm.wala.util.collections.Heap; /** * Worklist for fixed-point solver implementation */ -public class Worklist extends Heap { +public class Worklist extends Heap { private final HashSet contents = HashSetFactory.make(); @@ -28,14 +28,12 @@ public class Worklist extends Heap { } @Override - protected final boolean compareElements(Object o1, Object o2) { - AbstractStatement eq1 = (AbstractStatement) o1; - AbstractStatement eq2 = (AbstractStatement) o2; + protected final boolean compareElements(AbstractStatement eq1, AbstractStatement eq2) { return (eq1.getOrderNumber() < eq2.getOrderNumber()); } public AbstractStatement takeStatement() throws NoSuchElementException { - AbstractStatement result = (AbstractStatement)super.take(); + AbstractStatement result = super.take(); contents.remove(result); return result; } diff --git a/com.ibm.wala.core/src/com/ibm/wala/util/collections/Heap.java b/com.ibm.wala.core/src/com/ibm/wala/util/collections/Heap.java index ddc3dee92..0d6b36b02 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/util/collections/Heap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/util/collections/Heap.java @@ -18,16 +18,16 @@ import java.util.NoSuchElementException; * @author Julian Dolby */ -public abstract class Heap { +public abstract class Heap { /** * @return true iff elt1 is considered < elt2 */ - abstract protected boolean compareElements(Object elt1, Object elt2); + abstract protected boolean compareElements(T elt1, T elt2); private int numberOfElements; - private Object[] backingStore; + private T[] backingStore; /** * @return number of elements in this heap @@ -36,9 +36,10 @@ public abstract class Heap { return numberOfElements; } + @SuppressWarnings("unchecked") public Heap(int initialCapacity) { numberOfElements = 0; - backingStore = new Object[initialCapacity]; + backingStore = (T[])new Object[initialCapacity]; } /** @@ -48,10 +49,8 @@ public abstract class Heap { return numberOfElements == 0; } - /** - * @param elt - */ - public void insert(Object elt) { + + public void insert(T elt) { ensureCapacity(numberOfElements + 1); bubbleUp(elt, numberOfElements); numberOfElements++; @@ -60,11 +59,11 @@ public abstract class Heap { /** * @return the first object in the priority queue */ - public Object take() throws NoSuchElementException { + public T take() throws NoSuchElementException { if (numberOfElements == 0) { throw new NoSuchElementException(); } - Object result = backingStore[0]; + T result = backingStore[0]; removeElement(0); return result; } @@ -81,12 +80,11 @@ public abstract class Heap { return index * 2 + 2; } - /** - * @param min - */ + + @SuppressWarnings("unchecked") final private void ensureCapacity(int min) { if (backingStore.length < min) { - Object newStore[] = new Object[2 * min]; + T newStore[] = (T[])new Object[2 * min]; System.arraycopy(backingStore, 0, newStore, 0, backingStore.length); backingStore = newStore; } @@ -100,14 +98,14 @@ public abstract class Heap { */ final private void removeElement(int index) { int ne = numberOfElements; - Object[] bs = backingStore; + T[] bs = backingStore; while (true) { int leftIndex = heapLeftChild(index); if (leftIndex < ne) { int rightIndex = heapRightChild(index); if (rightIndex < ne) { - Object leftObject = bs[leftIndex]; - Object rightObject = bs[rightIndex]; + T leftObject = bs[leftIndex]; + T rightObject = bs[rightIndex]; if (compareElements(leftObject, rightObject)) { bs[index] = leftObject; index = leftIndex; @@ -138,15 +136,15 @@ public abstract class Heap { * @param elt * @param index */ - final private void bubbleUp(Object elt, int index) { - Object[] bs = backingStore; + final private void bubbleUp(T elt, int index) { + T[] bs = backingStore; while (true) { if (index == 0) { bs[index] = elt; return; } int hpIndex = heapParent(index); - Object parent = bs[hpIndex]; + T parent = bs[hpIndex]; if (compareElements(parent, elt)) { bs[index] = elt; return;