1 cananian 1.1.2.1  // CFGrapher.java, created Mon Nov 29 23:32:45 1999 by cananian
  2 cananian 1.1.2.1  // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1  package harpoon.IR.Properties;
  5 cananian 1.1.2.1  
  6 cananian 1.1.2.3  import harpoon.ClassFile.HCode;
  7 cananian 1.1.2.1  import harpoon.ClassFile.HCodeEdge;
  8 cananian 1.1.2.1  import harpoon.ClassFile.HCodeElement;
  9 cananian 1.1.2.10 import harpoon.Util.ArrayIterator;
 10 cananian 1.6      import net.cscott.jutil.CombineIterator;
 11 cananian 1.6      import net.cscott.jutil.FilterIterator;
 12 cananian 1.6      import net.cscott.jutil.UnmodifiableIterator;
 13 cananian 1.1.2.1  
 14 cananian 1.1.2.10 import java.util.AbstractCollection;
 15 cananian 1.1.2.10 import java.util.AbstractSet;
 16 cananian 1.5      import java.util.ArrayList;
 17 cananian 1.1.2.6  import java.util.Arrays;
 18 cananian 1.1.2.1  import java.util.Collection;
 19 cananian 1.5      import java.util.Collections;
 20 cananian 1.1.2.10 import java.util.HashSet;
 21 cananian 1.1.2.6  import java.util.Iterator;
 22 cananian 1.5      import java.util.List;
 23 cananian 1.1.2.10 import java.util.NoSuchElementException;
 24 cananian 1.1.2.10 import java.util.Set;
 25 cananian 1.1.2.10 import java.util.Stack;
 26 cananian 1.1.2.1  /**
 27 cananian 1.1.2.1   * <code>CFGrapher</code> provides a means to externally associate
 28 cananian 1.1.2.1   * control-flow graph information with elements of an intermediate
 29 cananian 1.1.2.1   * representation.
 30 cananian 1.1.2.1   * 
 31 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 32 cananian 1.6       * @version $Id: CFGrapher.java,v 1.6 2004/02/08 01:55:20 cananian Exp $
 33 cananian 1.1.2.7   * @see harpoon.IR.Properties.CFGraphable
 34 cananian 1.1.2.1   */
 35 cananian 1.2.2.1  public abstract class CFGrapher<HCE extends HCodeElement> {
 36 cananian 1.1.2.8      /** Returns the first <code>HCodeElement</code>s to be executed; that is,
 37 cananian 1.1.2.8       *  the roots of the control-flow graph. */
 38 cananian 1.2.2.1      public HCE[] getFirstElements(HCode<HCE> hcode) {
 39 cananian 1.2.2.1          HCE[] r = hcode.elementArrayFactory().newArray(1);
 40 cananian 1.1.2.8          r[0] = getFirstElement(hcode);
 41 cananian 1.1.2.8          return r;
 42 cananian 1.1.2.8      }
 43 cananian 1.1.2.8      /** Returns the last <code>HCodeElement</code>s to be executed; that is,
 44 cananian 1.1.2.8       *  the leaves of the control-flow graph. */
 45 cananian 1.2.2.1      public abstract HCE[] getLastElements(HCode<HCE> hcode);
 46 cananian 1.1.2.8      /** This method is present for compatibility only.
 47 cananian 1.1.2.8       *  @deprecated Use getFirstElements() instead. */
 48 cananian 1.2.2.1      public abstract HCE getFirstElement(HCode<HCE> hcode);
 49 cananian 1.1.2.3  
 50 cananian 1.1.2.1      // JDK 1.2 collections API: [CSA, 15-Jun-1999]
 51 cananian 1.5          /** Returns a <code>List</code> of all the edges to and from
 52 cananian 1.1.2.1       *  this <code>HCodeElement</code>. */
 53 cananian 1.5          public List<HCodeEdge<HCE>> edgeC(HCE hc) {
 54 cananian 1.2.2.1          Collection<HCodeEdge<HCE>> p = predC(hc), s = succC(hc);
 55 cananian 1.5              List<HCodeEdge<HCE>> ea = new ArrayList(p.size()+s.size());
 56 cananian 1.5              ea.addAll(p); ea.addAll(s);
 57 cananian 1.5              return Collections.unmodifiableList(ea);
 58 cananian 1.1.2.6      }
 59 cananian 1.5          /** Returns a <code>List</code> of all the edges to
 60 cananian 1.1.2.1          this <code>HCodeElement</code>. 
 61 cananian 1.1.2.1          Each <code>HCodeEdge</code> returned is guaranteed to return 
 62 cananian 1.1.2.1          <code>hc</code> in response to a call to <code>to()</code>;
 63 cananian 1.1.2.1          the actual predecessor will be returned from
 64 cananian 1.1.2.1          <code>from()</code>.  
 65 cananian 1.1.2.1       */
 66 cananian 1.5          public abstract List<HCodeEdge<HCE>> predC(HCE hc);
 67 cananian 1.5          /** Returns a <code>List</code> of all the edges from
 68 cananian 1.1.2.1          this <code>HCodeElement</code>. 
 69 cananian 1.1.2.1          Each <code>HCodeEdge</code> returned is guaranteed to return
 70 cananian 1.1.2.1          <code>hc</code> in response to a call to
 71 cananian 1.1.2.1          <code>from()</code>; the actual successor to <code>this</code>
 72 cananian 1.1.2.1          will be returned from <code>to()</code>.
 73 cananian 1.1.2.1       */
 74 cananian 1.5          public abstract List<HCodeEdge<HCE>> succC(HCE hc);
 75 pnkfelix 1.1.2.9      
 76 pnkfelix 1.1.2.9      /** Returns a <code>Collection</code> of all the 
 77 pnkfelix 1.1.2.9          <code>HCodeElement</code>s preceeding <code>hc</code>.
 78 pnkfelix 1.1.2.9      */
 79 cananian 1.2.2.1      public Collection<HCE> predElemC(HCE hc) {
 80 cananian 1.2.2.1          final Collection<HCodeEdge<HCE>> predEdges = this.predC(hc);
 81 cananian 1.2.2.1          return new AbstractCollection<HCE>() {
 82 pnkfelix 1.1.2.9                  public int size() { return predEdges.size(); }
 83 cananian 1.2.2.1                  public Iterator<HCE> iterator() {
 84 cananian 1.2.2.1                      return new FilterIterator<HCodeEdge<HCE>,HCE>
 85 pnkfelix 1.1.2.9                          (predEdges.iterator(), 
 86 cananian 1.2.2.1                           new FilterIterator.Filter<HCodeEdge<HCE>,HCE>() { 
 87 cananian 1.2.2.1                              public HCE map(HCodeEdge<HCE> o)
 88 cananian 1.2.2.1                                  { return o.from(); }
 89 cananian 1.1.2.10                         });
 90 pnkfelix 1.1.2.9                  }
 91 pnkfelix 1.1.2.9              };
 92 pnkfelix 1.1.2.9      }
 93 pnkfelix 1.1.2.9      
 94 pnkfelix 1.1.2.9      /** Returns a <code>Collection</code> of all the 
 95 pnkfelix 1.1.2.9          <code>HCodeElement</code> succeeding <code>hc</code>.
 96 pnkfelix 1.1.2.9      */
 97 cananian 1.2.2.1      public Collection<HCE> succElemC(HCE hc) {
 98 cananian 1.2.2.1          final Collection<HCodeEdge<HCE>> succEdges = this.succC(hc);
 99 cananian 1.2.2.1          return new AbstractCollection<HCE>() {
100 pnkfelix 1.1.2.9                  public int size() { return succEdges.size(); }
101 cananian 1.2.2.1                  public Iterator<HCE> iterator() {
102 cananian 1.2.2.1                      return new FilterIterator<HCodeEdge<HCE>,HCE>
103 pnkfelix 1.1.2.9                          (succEdges.iterator(), 
104 cananian 1.2.2.1                           new FilterIterator.Filter<HCodeEdge<HCE>,HCE>() {
105 cananian 1.2.2.1                              public HCE map(HCodeEdge<HCE> o)
106 cananian 1.2.2.1                                  { return o.to(); }
107 cananian 1.1.2.10                         });
108 pnkfelix 1.1.2.9                  }
109 pnkfelix 1.1.2.9              };
110 cananian 1.1.2.10     }
111 cananian 1.1.2.10 
112 cananian 1.2.2.1      public Set<HCE> getElements(final HCode<HCE> code) {
113 cananian 1.2.2.1          return new AbstractSet<HCE>() {
114 cananian 1.1.2.10             public int size() {
115 cananian 1.1.2.10                 int i=0;
116 cananian 1.2.2.1                  for (Iterator<HCE> it=iterator(); it.hasNext(); it.next())
117 cananian 1.1.2.10                     i++;
118 cananian 1.1.2.10                 return i;
119 cananian 1.1.2.10             }
120 cananian 1.2.2.1              public Iterator<HCE> iterator() {
121 cananian 1.2.2.1                  return new UnmodifiableIterator<HCE>() {
122 cananian 1.1.2.10                     // implementation borrowed from IR/Quads/Code.
123 cananian 1.2.2.1                      Set<HCE> visited = new HashSet<HCE>();
124 cananian 1.2.2.1                      Stack<HCE> s = new Stack<HCE>();
125 cananian 1.1.2.10                     { // initialize stack/set.
126 cananian 1.2.2.1                          Iterator<HCE> it =
127 cananian 1.2.2.2                              new ArrayIterator<HCE>(getFirstElements(code));
128 cananian 1.2.2.1                          HCE[] leaves = getLastElements(code);
129 cananian 1.1.2.11                         if (leaves!=null)
130 cananian 1.2.2.1                              it = new CombineIterator<HCE>
131 cananian 1.2.2.1                                  (new ArrayIterator<HCE>(leaves), it);
132 cananian 1.1.2.10                         while (it.hasNext()) {
133 cananian 1.2.2.1                              HCE hce = it.next();
134 cananian 1.1.2.10                             s.push(hce); visited.add(hce);
135 cananian 1.1.2.10                         }
136 cananian 1.1.2.10                     }
137 cananian 1.1.2.10                     public boolean hasNext() { return !s.isEmpty(); }
138 cananian 1.2.2.1                      public HCE next() {
139 cananian 1.1.2.10                         if (s.empty()) throw new NoSuchElementException();
140 cananian 1.2.2.1                          HCE hce = s.pop();
141 cananian 1.1.2.10                         // push successors on stack before returning.
142 cananian 1.2.2.1                          Iterator<HCE> it=succElemC(hce).iterator();
143 cananian 1.1.2.10                         while (it.hasNext()) {
144 cananian 1.2.2.1                              HCE nxt = it.next();
145 cananian 1.1.2.10                             if (!visited.contains(nxt)) {
146 cananian 1.1.2.10                                 s.push(nxt); visited.add(nxt);
147 cananian 1.1.2.10                             }
148 cananian 1.1.2.10                         }
149 cananian 1.1.2.10                         return hce;
150 cananian 1.1.2.10                     }
151 cananian 1.1.2.10                 };
152 cananian 1.1.2.10             }
153 cananian 1.1.2.10         };
154 pnkfelix 1.1.2.9      }
155 pnkfelix 1.1.2.9      
156 cananian 1.1.2.8      /** Returns an edge-reversed grapher based on this one.
157 cananian 1.1.2.8       *  Certain algorithms operate more naturally on this
158 cananian 1.1.2.8       *  representation --- for example, the difference between a
159 cananian 1.1.2.8       *  dominator tree and a post-dominator tree is now simply
160 cananian 1.1.2.8       *  whether you use the <code>grapher</code> or
161 cananian 1.1.2.8       *  <code>grapher.edgeReversed()</code>. */
162 cananian 1.2.2.1      public CFGrapher<HCE> edgeReversed() {
163 cananian 1.2.2.1          if (reversed==null)
164 cananian 1.2.2.1              reversed=new ReverseGrapher<HCE>(this);
165 cananian 1.2.2.1          return reversed;
166 cananian 1.2.2.1      }
167 cananian 1.2.2.1      private CFGrapher<HCE> reversed = null;
168 cananian 1.2.2.1      private static class ReverseGrapher<HCE extends HCodeElement>
169 cananian 1.2.2.1          extends SerializableGrapher<HCE> {
170 cananian 1.2.2.1          private final CFGrapher<HCE> grapher;
171 cananian 1.2.2.1          ReverseGrapher(CFGrapher<HCE> grapher) { this.grapher = grapher; }
172 cananian 1.2.2.1          public HCE[] getFirstElements(HCode<HCE> hcode) {
173 cananian 1.1.2.8              return grapher.getLastElements(hcode);
174 cananian 1.1.2.8          }
175 cananian 1.2.2.1          public HCE getFirstElement(HCode<HCE> hcode) {
176 cananian 1.2.2.1              HCE[] r = getFirstElements(hcode);
177 cananian 1.1.2.8              if (r.length!=1)
178 cananian 1.1.2.8                  throw new Error("Deprecated use of getFirstElement() not "+
179 cananian 1.1.2.8                                  "supported with edge-reversed graphers.");
180 cananian 1.1.2.8              return r[0];
181 cananian 1.1.2.8          }
182 cananian 1.2.2.1          public HCE[] getLastElements(HCode<HCE> hcode) {
183 cananian 1.1.2.8              return grapher.getFirstElements(hcode);
184 cananian 1.1.2.8          }
185 cananian 1.5              public List<HCodeEdge<HCE>> predC(HCE hc) {
186 cananian 1.1.2.8              return reverseEdges(grapher.succC(hc));
187 cananian 1.1.2.8          }
188 cananian 1.5              public List<HCodeEdge<HCE>> succC(HCE hc) {
189 cananian 1.1.2.8              return reverseEdges(grapher.predC(hc));
190 cananian 1.1.2.8          }
191 cananian 1.2.2.1          private static <HCE extends HCodeElement>
192 cananian 1.5              List<HCodeEdge<HCE>> reverseEdges(List<HCodeEdge<HCE>> edges) {
193 cananian 1.5                  List<HCodeEdge<HCE>> ea =
194 cananian 1.5                      new ArrayList<HCodeEdge<HCE>>(edges.size());
195 cananian 1.5                  for (Iterator<HCodeEdge<HCE>> it=edges.iterator(); it.hasNext(); ){
196 cananian 1.2.2.1                  final HCodeEdge<HCE> e = it.next();
197 cananian 1.5                      ea.add(new HCodeEdge<HCE>() {
198 cananian 1.2.2.1                      public HCE from() { return e.to(); }
199 cananian 1.2.2.1                      public HCE to() { return e.from(); }
200 cananian 1.5                      });
201 cananian 1.1.2.8              }
202 cananian 1.5                  return Collections.unmodifiableList(ea);
203 cananian 1.1.2.8          }
204 cananian 1.2.2.1          public CFGrapher<HCE> edgeReversed() { return grapher; }
205 cananian 1.1.2.8      }
206 cananian 1.1.2.8  
207 cananian 1.1.2.1      /** Default <code>CFGrapher</code> for <code>HCodeElement</code>s
208 cananian 1.1.2.1       *  which implement <code>CFGraphable</code>.  Does nothing
209 cananian 1.1.2.1       *  but cast the supplied <code>HCodeElement</code> to a
210 cananian 1.1.2.1       *  <code>CFGraphable</code> and invoke the appropriate
211 cananian 1.1.2.1       *  corresponding method in the <code>CFGraphable</code>
212 cananian 1.1.2.3       *  interface.  The root of the control flow graph is
213 cananian 1.1.2.3       *  assumed to be whatever <code>HCode.getRootElement</code>
214 cananian 1.1.2.3       *  returns.
215 cananian 1.1.2.1       * @see java.util.Comparator
216 cananian 1.1.2.1       * @see java.lang.Comparable
217 cananian 1.6           * @see net.cscott.jutil.Default.comparator
218 cananian 1.1.2.1       */
219 cananian 1.2.2.1      // XXX in theory, we could use a type system to enforce the
220 cananian 1.2.2.1      //  constraint that DEFAULT is a CFGrapher that only works
221 cananian 1.2.2.1      //  for HCodeElements which are CFGraphable.  but the GJ
222 cananian 1.2.2.1      //  type system's not powerful enough.
223 cananian 1.1.2.5      public static final CFGrapher DEFAULT = new SerializableGrapher() {
224 cananian 1.1.2.3          public HCodeElement getFirstElement(HCode hcode) {
225 cananian 1.1.2.3              return hcode.getRootElement();
226 cananian 1.1.2.8          }
227 cananian 1.1.2.8          public HCodeElement[] getLastElements(HCode hcode) {
228 cananian 1.1.2.8              return hcode.getLeafElements();
229 cananian 1.1.2.3          }
230 cananian 1.1.2.1          public HCodeEdge[] edges(HCodeElement hc) {
231 cananian 1.1.2.1              return ((CFGraphable)hc).edges();
232 cananian 1.1.2.1          }
233 cananian 1.1.2.1          public HCodeEdge[] pred(HCodeElement hc) {
234 cananian 1.1.2.1              return ((CFGraphable)hc).pred();
235 cananian 1.1.2.1          }
236 cananian 1.1.2.1          public HCodeEdge[] succ(HCodeElement hc) {
237 cananian 1.1.2.1              return ((CFGraphable)hc).succ();
238 cananian 1.1.2.1          }
239 cananian 1.5              public List edgeC(HCodeElement hc) {
240 cananian 1.1.2.1              return ((CFGraphable)hc).edgeC();
241 cananian 1.1.2.1          }
242 cananian 1.5              public List predC(HCodeElement hc) {
243 cananian 1.1.2.1              return ((CFGraphable)hc).predC();
244 cananian 1.1.2.1          }
245 cananian 1.5              public List succC(HCodeElement hc) {
246 cananian 1.1.2.1              return ((CFGraphable)hc).succC();
247 cananian 1.1.2.1          }
248 cananian 1.1.2.1      };
249 cananian 1.2.2.1      private static abstract class SerializableGrapher<HCE extends HCodeElement>
250 cananian 1.2.2.1          extends CFGrapher<HCE>
251 cananian 1.1.2.5          implements java.io.Serializable { }
252 cananian 1.2      }