1 cananian 1.1 // DataFlowSolver.java, created Thu May  8 20:07:24 2003 by cananian
 2 cananian 1.1 // Copyright (C) 2003 C. Scott Ananian <cananian@alumni.princeton.edu>
 3 cananian 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
 4 cananian 1.1 package harpoon.Analysis.Companions;
 5 cananian 1.1 
 6 cananian 1.2 import harpoon.ClassFile.HCode;
 7 cananian 1.1 import harpoon.IR.Properties.CFGEdge;
 8 cananian 1.1 import harpoon.IR.Properties.CFGraphable;
 9 cananian 1.3 import harpoon.Util.Collections.Graph;
10 cananian 1.4 import net.cscott.jutil.WorkSet;
11 cananian 1.1 
12 cananian 1.1 import java.util.Collection;
13 cananian 1.1 import java.util.HashMap;
14 cananian 1.1 import java.util.Iterator;
15 cananian 1.1 import java.util.Map;
16 cananian 1.1 /**
17 cananian 1.1  * The <code>DataFlowSolver</code> class provides a parameterized framework
18 cananian 1.3  * for building simple data flow analyses for various IRs.  The
19 cananian 1.3  * <code>DataFlowSolver.Forward</code> and <code>DataFlowSolver.Backward</code>
20 cananian 1.3  * subclasses contain code for forward and backward analyses, respectively.
21 cananian 1.1  * 
22 cananian 1.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
23 cananian 1.5  * @version $Id: DataFlowSolver.java,v 1.5 2004/02/08 03:19:17 cananian Exp $
24 cananian 1.1  */
25 cananian 1.3 public abstract class DataFlowSolver<N extends Graph.Node<N,E>,
26 cananian 1.3                                      E extends Graph.Edge<N,E>,
27 cananian 1.3                                      FACT> {
28 cananian 1.1     /** Compute the join operation on two dataflow <code>FACT</code>s. */
29 cananian 1.1     protected abstract FACT join(FACT e1, FACT e2);
30 cananian 1.1     /** Return the initial value of the dataflow <code>FACT</code> for the
31 cananian 1.3      *  given <code>Node</code> (often, an <code>HCodeElement</code>). */
32 cananian 1.3     protected abstract FACT init(N hce);
33 cananian 1.3     /** Compute all dataflow facts on the given <code>Graph</code>.
34 cananian 1.3      *  Note that <code>HCode</code> subclasses with elements implementing
35 cananian 1.3      *  <code>CFGraphable</code> are typically also instances of
36 cananian 1.3      *  <code>Graph</code>. */
37 cananian 1.3     public abstract Map<N,FACT> compute(Graph<N,E> hc);
38 cananian 1.1 
39 cananian 1.1     /**
40 cananian 1.1      * <code>DataFlowSolver.Forward</code> is a dataflow solver for
41 cananian 1.1      * forward dataflow analyses.  You need only define a <code>join</code>
42 cananian 1.1      * operation on your <code>FACT</code> type, an initial value for
43 cananian 1.3      * each node (usually, an <code>HCodeElement</code> implementation which
44 cananian 1.3      * also implements <code>Graph.Node</code>, such as <code>Quad</code>)
45 cananian 1.3      * via the return value of the <code>init()</code> method), and a means
46 cananian 1.3      * for computing the <code>OUT</code> dataflow fact given the
47 cananian 1.3      * <code>IN</code> fact for a node (<code>HCodeElement</code>).
48 cananian 1.1      * Calling <code>compute()</code> will then return a mapping from
49 cananian 1.3      * every <code>Graph.Node</code> to the final <code>IN</code>
50 cananian 1.1      * dataflow fact for that element. */
51 cananian 1.1     public static abstract class Forward
52 cananian 1.3         <N extends Graph.Node<N,E>, E extends Graph.Edge<N,E>, FACT>
53 cananian 1.3         extends DataFlowSolver<N,E,FACT> {
54 cananian 1.1         /** Compute the <code>OUT</code> fact given the <code>IN</code>
55 cananian 1.3          *  fact for a <code>Node</code> (<code>HCodeElement</code>). */
56 cananian 1.3         protected abstract FACT out(N hce, FACT in);
57 cananian 1.1         
58 cananian 1.3         /** Look up the FACT for the Node, adding the initial value to the
59 cananian 1.3          *  map if no value was present. */
60 cananian 1.3         private final FACT lookup(N hce, Map<N,FACT> map) {
61 cananian 1.1             if (!map.containsKey(hce))
62 cananian 1.1                 map.put(hce, init(hce));
63 cananian 1.1             return map.get(hce);
64 cananian 1.1         }
65 cananian 1.3         public final Map<N,FACT> compute(Graph<N,E> g) {
66 cananian 1.3             final Map<N,FACT> OUTresult = new HashMap<N,FACT>();
67 cananian 1.3             final WorkSet<N> worklist = new WorkSet<N>(g.nodes());
68 cananian 1.1             while (!worklist.isEmpty()) {
69 cananian 1.3                 N hce = worklist.removeFirst();
70 cananian 1.1                 // compute in using out result.
71 cananian 1.1                 FACT in = computeIN(hce, OUTresult);
72 cananian 1.1                 // now recompute new out.
73 cananian 1.1                 FACT out = out(hce, in);
74 cananian 1.1                 // if different from previous, add successors to worklist.
75 cananian 1.1                 if (!out.equals(lookup(hce, OUTresult))) {
76 cananian 1.1                     OUTresult.put(hce, out);
77 cananian 1.1                     for (Iterator<E> it=hce.succC().iterator(); it.hasNext();)
78 cananian 1.1                         worklist.add(it.next().to());
79 cananian 1.1                 }
80 cananian 1.1             }
81 cananian 1.1             // done!  but we want to return IN set, not OUT set.
82 cananian 1.3             final Map<N,FACT> INresult = new HashMap<N,FACT>();
83 cananian 1.5             for (N hce : g.nodes()) {
84 cananian 1.1                 INresult.put(hce, computeIN(hce, OUTresult));
85 cananian 1.1             }
86 cananian 1.1             // now really done.
87 cananian 1.1             return INresult;
88 cananian 1.1         }
89 cananian 1.3         private final FACT computeIN(N hce, Map<N,FACT> outMap) {
90 cananian 1.1             Iterator<E> it=hce.predC().iterator();
91 cananian 1.1             if (!it.hasNext()) return init(hce);
92 cananian 1.1             FACT f = lookup(it.next().from(), outMap);
93 cananian 1.1             while (it.hasNext())
94 cananian 1.1                 f = join(f, lookup(it.next().from(), outMap));
95 cananian 1.1             return f;
96 cananian 1.1         }
97 cananian 1.1     }
98 cananian 1.1 }