1 salcianu 1.1.2.10 // PAEscapeFunc.java, created Sun Jan  9 20:53:09 2000 by salcianu
  2 cananian 1.1.2.27 // Copyright (C) 2000 Alexandru SALCIANU <salcianu@retezat.lcs.mit.edu>
  3 salcianu 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 salcianu 1.1.2.1  package harpoon.Analysis.PointerAnalysis;
  5 salcianu 1.1.2.1  
  6 salcianu 1.1.2.1  import java.util.HashSet;
  7 salcianu 1.1.2.1  import java.util.Set;
  8 salcianu 1.1.2.1  import java.util.Iterator;
  9 salcianu 1.1.2.1  import java.util.Map;
 10 salcianu 1.4      import java.util.Collections;
 11 salcianu 1.1.2.1  
 12 salcianu 1.1.2.20 import harpoon.ClassFile.HMethod;
 13 salcianu 1.1.2.1  
 14 salcianu 1.1.2.21 import harpoon.Util.PredicateWrapper;
 15 salcianu 1.1.2.21 import harpoon.Util.DataStructs.Relation;
 16 salcianu 1.1.2.21 import harpoon.Util.DataStructs.LightRelation;
 17 salcianu 1.1.2.21 import harpoon.Util.DataStructs.RelationEntryVisitor;
 18 salcianu 1.1.2.21 
 19 salcianu 1.1.2.21 
 20 salcianu 1.1.2.1  /**
 21 salcianu 1.1.2.8   * <code>PAEscapeFunc</code> models the escape information.
 22 salcianu 1.1.2.14  For each <code>PANode</code> <code>node</code>, it maintains all the nodes
 23 salcianu 1.1.2.14  <code>node</code> escapes through (e.g. parameter nodes).
 24 salcianu 1.1.2.14  Also, it records whether <code>node</code> escapes into a method hole or not.
 25 salcianu 1.1.2.1   * 
 26 cananian 1.1.2.27  * @author  Alexandru SALCIANU <salcianu@retezat.lcs.mit.edu>
 27 cananian 1.6       * @version $Id: PAEscapeFunc.java,v 1.6 2004/02/08 03:20:03 cananian Exp $
 28 salcianu 1.1.2.1   */
 29 salcianu 1.1.2.25 public class PAEscapeFunc implements java.io.Serializable {
 30 salcianu 1.1.2.1  
 31 salcianu 1.1.2.1      // rel_n attaches to each node the set of all the nodes
 32 salcianu 1.1.2.1      // that it can escape through.
 33 salcianu 1.1.2.1      Relation rel_n;
 34 salcianu 1.1.2.1  
 35 salcianu 1.1.2.20     ////////////////
 36 salcianu 1.1.2.14     // set of nodes that escaped into an unanalyzed method
 37 salcianu 1.1.2.20     // Set escaped_into_mh;
 38 salcianu 1.1.2.20     ////////////////
 39 salcianu 1.1.2.20 
 40 salcianu 1.1.2.20     // rel_m attaches to each node the set of all the methods
 41 salcianu 1.1.2.20     // that it can escape into.
 42 salcianu 1.1.2.20     Relation rel_m;
 43 salcianu 1.1.2.1  
 44 salcianu 1.1.2.1      /** Creates a <code>EscapeFunc</code>. */
 45 salcianu 1.1.2.1      public PAEscapeFunc() {
 46 salcianu 1.1.2.21         rel_n  = new LightRelation();
 47 salcianu 1.1.2.20         ///////// escaped_into_mh = new HashSet();
 48 salcianu 1.1.2.21         rel_m  = new LightRelation();
 49 salcianu 1.1.2.1      }
 50 salcianu 1.1.2.1      
 51 salcianu 1.1.2.14     /** Records the fact that <code>node</code> can escape through
 52 salcianu 1.1.2.8          the node <code>n_hole</code>. Returns <code>true</code>
 53 salcianu 1.1.2.8          if new information has been gained */
 54 salcianu 1.5          public final boolean addNodeHole(PANode node, PANode n_hole) {
 55 salcianu 1.4              if(node.type == PANode.NULL) return false;
 56 salcianu 1.1.2.14         return rel_n.add(node, n_hole);
 57 salcianu 1.1.2.1      }
 58 salcianu 1.1.2.1  
 59 salcianu 1.1.2.14     /** Records the fact that <code>node</code> can escape through
 60 salcianu 1.1.2.8          the node <code>n_holes</code>. Returns <code>true</code>
 61 salcianu 1.1.2.8          if new information has been gained */
 62 salcianu 1.4          public final boolean addNodeHoles(PANode node, Set n_holes) {
 63 salcianu 1.4              if(node.type == PANode.NULL) return false;
 64 salcianu 1.1.2.14         return rel_n.addAll(node, n_holes);
 65 salcianu 1.1.2.1      }
 66 salcianu 1.1.2.1  
 67 salcianu 1.1.2.1      /** The dual of <code>addNodeHole</code> */
 68 salcianu 1.1.2.14     public final void removeNodeHole(PANode node, PANode n_hole){
 69 salcianu 1.1.2.14         rel_n.remove(node, n_hole);
 70 salcianu 1.1.2.1      }
 71 salcianu 1.1.2.1  
 72 salcianu 1.1.2.14     /** Removes a node hole from all the nodes:
 73 salcianu 1.1.2.14         <code>esc(n) = esc(n) - {n_hole}</code> for all <code>n</code>. */
 74 salcianu 1.1.2.5      public void removeNodeHoleFromAll(PANode n_hole){
 75 salcianu 1.1.2.14         // make a private copy of the set of keys so that I avoid
 76 salcianu 1.1.2.14         //  "java.util.ConcurrentModificationException"
 77 salcianu 1.1.2.21         Set set = new HashSet(rel_n.keys());
 78 salcianu 1.1.2.14         for(Iterator it = set.iterator(); it.hasNext(); )
 79 salcianu 1.1.2.14             rel_n.remove((PANode) it.next(), n_hole);
 80 salcianu 1.1.2.5      }
 81 salcianu 1.1.2.5  
 82 salcianu 1.1.2.20     /** Returns the set of all the node &quot;holes&quot; <code>node</code>
 83 salcianu 1.1.2.20         escapes through. */
 84 salcianu 1.1.2.20     public Set nodeHolesSet(PANode node){
 85 salcianu 1.1.2.21         return rel_n.getValues(node);
 86 salcianu 1.1.2.20     }
 87 salcianu 1.1.2.20 
 88 salcianu 1.1.2.20     /** Checks whether <code>node</code> escapes through a node or not. */
 89 salcianu 1.1.2.20     public boolean hasEscapedIntoANode(PANode node){
 90 salcianu 1.1.2.21         return !rel_n.getValues(node).isEmpty();
 91 salcianu 1.1.2.20     }
 92 salcianu 1.1.2.20 
 93 salcianu 1.1.2.14     /** Records the fact that <code>node</code> escaped into a method hole.
 94 salcianu 1.1.2.14         Returns <code>true</code> if this was a new information. */
 95 salcianu 1.4          public boolean addMethodHole(PANode node, HMethod hm) {
 96 salcianu 1.4              if(node.type == PANode.NULL) return false;
 97 salcianu 1.4      
 98 salcianu 1.4              if(PointerAnalysis.CONDENSED_ESCAPE_INFO) {
 99 salcianu 1.4                  if(!rel_m.getValues(node).isEmpty())
100 salcianu 1.4                      return false;
101 salcianu 1.4              }
102 salcianu 1.4      
103 salcianu 1.1.2.20         ////// return escaped_into_mh.add(node);
104 salcianu 1.1.2.20         return rel_m.add(node, hm);
105 salcianu 1.1.2.1      }
106 salcianu 1.1.2.1  
107 salcianu 1.1.2.20     /** Records the fact that <code>node</code> escaped into a set of
108 salcianu 1.1.2.20         method holes.
109 salcianu 1.1.2.20         Returns <code>true</code> if this was a new information. */
110 salcianu 1.1.2.20     public boolean addMethodHoles(PANode node, Set mholes){
111 salcianu 1.1.2.20         boolean changed = false;        
112 salcianu 1.1.2.20         for(Iterator it = mholes.iterator(); it.hasNext(); ){
113 salcianu 1.1.2.20             boolean changed_last = addMethodHole(node, (HMethod) it.next());
114 salcianu 1.1.2.20             changed = changed || changed_last;
115 salcianu 1.1.2.20         }
116 salcianu 1.1.2.20         return changed;
117 salcianu 1.1.2.1      }
118 vivien   1.1.2.24 
119 vivien   1.1.2.24 
120 vivien   1.1.2.24     /** The dual of <code>addMethodHole</code> */
121 vivien   1.1.2.24     public final void removeMethodHole(PANode node, HMethod hm){
122 vivien   1.1.2.24         rel_m.remove(node, hm);
123 vivien   1.1.2.24     }
124 vivien   1.1.2.24 
125 salcianu 1.1.2.1  
126 salcianu 1.1.2.20 
127 salcianu 1.1.2.20     /** The methods from the set <code>good_holes</code> are unharmful
128 salcianu 1.1.2.20         to the specific application that uses the pointer analysis. So, they
129 salcianu 1.1.2.20         can be erased from the set of method holes into which a specific node
130 salcianu 1.1.2.20         escapes. */
131 salcianu 1.1.2.20     public void removeMethodHoles(final Set good_holes) {
132 salcianu 1.4      
133 salcianu 1.4              // for condensed escape info, we cannot remove method holes
134 salcianu 1.4              if(PointerAnalysis.CONDENSED_ESCAPE_INFO)
135 salcianu 1.4                  return;
136 salcianu 1.4      
137 salcianu 1.4              rel_m.removeValues(new PredicateWrapper() {
138 salcianu 1.1.2.20                 public boolean check(Object obj) {
139 salcianu 1.1.2.20                     return good_holes.contains(obj);
140 salcianu 1.1.2.20                 }
141 salcianu 1.1.2.20             });
142 salcianu 1.1.2.20     }
143 salcianu 1.1.2.20 
144 salcianu 1.1.2.20     /** Returns the set of methods that <code>node</code> escapes into. */
145 salcianu 1.1.2.20     public Set methodHolesSet(PANode node){
146 salcianu 1.1.2.21         return rel_m.getValues(node);
147 salcianu 1.1.2.20     }
148 salcianu 1.1.2.20 
149 salcianu 1.1.2.20     /** Returns the set of nodes which escape into a method hole. */
150 salcianu 1.1.2.20     public Set getEscapedIntoMH(){
151 salcianu 1.1.2.20         ////// return escaped_into_mh;
152 salcianu 1.1.2.21         return rel_m.keys();
153 salcianu 1.1.2.19     }
154 salcianu 1.1.2.19 
155 salcianu 1.1.2.19     /** Checks whether <code>node</code> escapes into a method hole or not. */
156 salcianu 1.1.2.19     public boolean hasEscapedIntoAMethod(PANode node){
157 salcianu 1.1.2.20         ///// return escaped_into_mh.contains(node);
158 salcianu 1.1.2.21         return !rel_m.getValues(node).isEmpty();
159 salcianu 1.1.2.1      }
160 salcianu 1.1.2.1  
161 salcianu 1.1.2.20     /** Checks if <code>node</code> has escaped in some hole, ie if
162 salcianu 1.1.2.20         <code>node</code> could be accessed by unanalyzed code. */
163 salcianu 1.1.2.20     public boolean hasEscaped(PANode node){
164 salcianu 1.1.2.20         return
165 salcianu 1.1.2.20             hasEscapedIntoANode(node) || hasEscapedIntoAMethod(node);
166 salcianu 1.1.2.9      }
167 salcianu 1.1.2.23 
168 salcianu 1.1.2.23 
169 salcianu 1.1.2.23     /** Checks whether <code>node</code> escapes at most in the caller.
170 salcianu 1.1.2.23         ie it doesn't escape in an unanalyzed method, a thread or a static
171 salcianu 1.1.2.23         field. */
172 salcianu 1.1.2.23     public boolean escapesOnlyInCaller(PANode node) {
173 salcianu 1.1.2.23         if(hasEscapedIntoAMethod(node))
174 salcianu 1.1.2.23             return false; // escapes into an unanalyzed method
175 cananian 1.6              for(Object hole_nodeO : nodeHolesSet(node)) {
176 cananian 1.6                  PANode hole_node = (PANode) hole_nodeO;
177 salcianu 1.1.2.23             if(hole_node.type() != PANode.PARAM)
178 salcianu 1.1.2.23                 return false; // escapes into a thread or a static
179 salcianu 1.1.2.23         }
180 salcianu 1.1.2.23         return true;
181 salcianu 1.1.2.23     }
182 salcianu 1.1.2.23 
183 salcianu 1.1.2.9  
184 salcianu 1.1.2.9      /** Remove all the <code>PANode</code>s that appear in <code>set</code>
185 salcianu 1.1.2.9          from <code>this</code> object. */
186 salcianu 1.1.2.9      public void remove(Set set){
187 cananian 1.6              for(Object nodeO : set){
188 cananian 1.6                  PANode node = (PANode) nodeO;
189 salcianu 1.1.2.21             rel_n.removeKey(node);
190 salcianu 1.1.2.20             //////// escaped_into_mh.remove(node);
191 salcianu 1.1.2.21             rel_m.removeKey(node);
192 salcianu 1.1.2.9          }
193 salcianu 1.1.2.1      }
194 salcianu 1.1.2.1  
195 salcianu 1.4          public void union(PAEscapeFunc e2) {
196 salcianu 1.4              union(e2, null);
197 salcianu 1.4          }
198 salcianu 1.4      
199 salcianu 1.1.2.8      /** Computes the union of <code>this</code> <code>PAEscapeFunc</code>
200 salcianu 1.1.2.8          with <code>e2</code>. This function is called in the control flow
201 salcianu 1.1.2.8          <i>join</i> points. */
202 salcianu 1.4          public void union(PAEscapeFunc e2, Set/*<PANode>*/ ppgRoots) {
203 salcianu 1.4              // rel_n.union(e2.rel_n) + collect in ppgRoots nodes whose
204 salcianu 1.4              // escape info has changed
205 cananian 1.6              for(Object nodeO : e2.rel_n.keys()) {
206 cananian 1.6                  PANode node = (PANode) nodeO;
207 salcianu 1.4                  Set holes = e2.rel_n.getValues(node);
208 salcianu 1.4                  if(rel_n.addAll(node, holes) && (ppgRoots != null))
209 salcianu 1.4                      ppgRoots.add(node);
210 salcianu 1.4              }
211 salcianu 1.4      
212 salcianu 1.4              if(PointerAnalysis.CONDENSED_ESCAPE_INFO) {
213 salcianu 1.4                  //////// escaped_into_mh.addAll(e2.escaped_into_mh);
214 salcianu 1.4                  // avoid adding multiple method holes for the same node
215 salcianu 1.4                  for(Iterator/*<PANode>*/ it = e2.getEscapedIntoMH().iterator();
216 salcianu 1.4                      it.hasNext(); ) {
217 salcianu 1.4                      PANode node = (PANode) it.next();
218 salcianu 1.4                      Set/*<HMethod>*/ newMHs = e2.methodHolesSet(node);
219 salcianu 1.4                      if(!newMHs.isEmpty() && methodHolesSet(node).isEmpty()) {
220 salcianu 1.4                          addMethodHole(node, (HMethod) newMHs.iterator().next());
221 salcianu 1.4                          if(ppgRoots != null)
222 salcianu 1.4                              ppgRoots.add(node);
223 salcianu 1.4                      }
224 salcianu 1.4                  }
225 salcianu 1.4              }
226 salcianu 1.4              else { /* !PointerAnalysis.CONDENSED_ESCAPE_INFO) */
227 salcianu 1.4                  assert ppgRoots == null : 
228 salcianu 1.4                      "ppgRoots implemented only for CONDENSED_ESCAPE_INFO";
229 salcianu 1.4                  rel_m.union(e2.rel_m);
230 salcianu 1.4              }
231 salcianu 1.1.2.8      }
232 salcianu 1.1.2.8  
233 salcianu 1.4      
234 salcianu 1.1.2.8      /** Inserts the image of <code>e2</code> through the <code>mu</code>
235 salcianu 1.1.2.26         mapping into <code>this</code> <code>PAEscapeFunc</code>. */
236 salcianu 1.4          public void insert(PAEscapeFunc e2, final Relation mu, final Set noholes,
237 salcianu 1.4                             final Set/*<PANode>*/ ppgRoots) {
238 salcianu 1.1.2.8          // insert the node holes
239 salcianu 1.1.2.8          RelationEntryVisitor nvisitor =
240 salcianu 1.4                  new RelationEntryVisitor() {
241 salcianu 1.4                      public void visit(Object key, Object value) {
242 salcianu 1.4                          if(noholes.contains(value)) return;
243 salcianu 1.4                          PANode origHole = (PANode) value;
244 salcianu 1.4                          Set holes =
245 salcianu 1.4                              (origHole.type == PANode.LOST) ?
246 salcianu 1.4                              Collections.singleton(origHole) :
247 salcianu 1.4                              mu.getValues(origHole);
248 salcianu 1.4                          Set nodes = mu.getValues(key);
249 cananian 1.6                          for(Object nodeO : nodes) {
250 cananian 1.6                              PANode node = (PANode) nodeO;
251 salcianu 1.4                              if(addNodeHoles(node, holes) && (ppgRoots != null))
252 salcianu 1.4                                 ppgRoots.add(node);
253 salcianu 1.1.2.8                      }
254 salcianu 1.4                      }
255 salcianu 1.4                  };
256 salcianu 1.1.2.8  
257 salcianu 1.1.2.8          e2.rel_n.forAllEntries(nvisitor);
258 salcianu 1.1.2.8  
259 salcianu 1.1.2.20         ///// for(Iterator it = e2.escaped_into_mh.iterator(); it.hasNext(); ){
260 salcianu 1.1.2.20         /////    PANode node = (PANode) it.next();
261 salcianu 1.1.2.21         /////    escaped_into_mh.addAll(mu.getValues(node));
262 salcianu 1.1.2.20         ///// }
263 cananian 1.6              for(Object nodeO : e2.getEscapedIntoMH()) {
264 cananian 1.6                  PANode node = (PANode) nodeO;
265 salcianu 1.4                  Set imgs = mu.getValues(node);
266 salcianu 1.4                  Set holes = e2.methodHolesSet(node);
267 cananian 1.6                  for(Object node_imgO : imgs) {
268 cananian 1.6                      PANode node_img = (PANode) node_imgO;
269 salcianu 1.4                      if(addMethodHoles(node_img, holes) && (ppgRoots != null))
270 salcianu 1.4                          ppgRoots.add(node_img);
271 salcianu 1.1.2.20             }
272 salcianu 1.1.2.14         }
273 salcianu 1.1.2.11     }
274 salcianu 1.1.2.11 
275 salcianu 1.1.2.11     /* Specializes <code>this</code> according to <code>map</code>. */
276 salcianu 1.1.2.11     public PAEscapeFunc specialize(Map map){
277 salcianu 1.1.2.11         PAEscapeFunc e2 = new PAEscapeFunc();
278 salcianu 1.1.2.11 
279 cananian 1.6              for(Object nodeO : rel_n.keys()){
280 cananian 1.6                  PANode node = (PANode) nodeO;
281 salcianu 1.1.2.11             PANode node2 = PANode.translate(node, map);
282 salcianu 1.1.2.21             Iterator itnh = rel_n.getValues(node).iterator();
283 salcianu 1.1.2.21             while(itnh.hasNext())
284 salcianu 1.1.2.11                 e2.addNodeHole(node2,
285 salcianu 1.1.2.11                                PANode.translate((PANode)itnh.next(),map));
286 salcianu 1.1.2.11         }
287 salcianu 1.1.2.11         
288 salcianu 1.1.2.20         ///// for(Iterator it = escaped_into_mh.iterator(); it.hasNext(); ){
289 salcianu 1.1.2.20         /////    PANode node = (PANode) it.next();
290 salcianu 1.1.2.20         /////    e2.escaped_into_mh.add(PANode.translate(node, map));
291 salcianu 1.1.2.20         ///// }
292 cananian 1.6              for(Object nodeO : getEscapedIntoMH()) {
293 cananian 1.6                  PANode node = (PANode) nodeO;
294 salcianu 1.1.2.20             PANode node2 = PANode.translate(node, map);
295 salcianu 1.1.2.20             e2.addMethodHoles(node2, methodHolesSet(node));
296 salcianu 1.1.2.20         }       
297 salcianu 1.1.2.20         /////
298 salcianu 1.1.2.14 
299 salcianu 1.1.2.11         return e2;
300 salcianu 1.1.2.1      }
301 salcianu 1.1.2.1  
302 salcianu 1.1.2.14     /** Checks the equality of two <code>PAEscapeFunc</code> objects. */
303 salcianu 1.1.2.14     public boolean equals(Object obj){
304 salcianu 1.1.2.14         if(obj == null) return false;
305 salcianu 1.1.2.14         PAEscapeFunc e2 = (PAEscapeFunc) obj;
306 salcianu 1.1.2.14 
307 salcianu 1.1.2.20         ///// return 
308 salcianu 1.1.2.20         /////    rel_n.equals(e2.rel_n) &&
309 salcianu 1.1.2.20         /////    escaped_into_mh.equals(e2.escaped_into_mh);
310 salcianu 1.1.2.20         return
311 salcianu 1.4                  rel_n.equals(e2.rel_n) && 
312 salcianu 1.4                  (PointerAnalysis.CONDENSED_ESCAPE_INFO ? 
313 salcianu 1.4                   rel_m.keys().equals(e2.rel_m.keys()) :
314 salcianu 1.4                   rel_m.equals(e2.rel_m));
315 salcianu 1.1.2.3      }
316 salcianu 1.1.2.3  
317 salcianu 1.1.2.14     /** Returns the set of escaped nodes. */
318 salcianu 1.1.2.3      public Set escapedNodes(){
319 salcianu 1.1.2.21         HashSet set = new HashSet(rel_n.keys());
320 salcianu 1.1.2.20         ////// set.addAll(escaped_into_mh);
321 salcianu 1.1.2.21         set.addAll(rel_m.keys());
322 salcianu 1.1.2.20         //////
323 salcianu 1.1.2.3          return set;
324 salcianu 1.1.2.2      }
325 salcianu 1.1.2.2  
326 salcianu 1.1.2.5      /** Private constructor used only by <code>select</code> and
327 salcianu 1.1.2.5          <code>clone</code> */
328 salcianu 1.1.2.20     ///// private PAEscapeFunc(Relation rel_n, Set escaped_into_mh){
329 salcianu 1.1.2.20     /////       this.rel_n           = rel_n;
330 salcianu 1.1.2.20     /////       this.escaped_into_mh = escaped_into_mh;
331 salcianu 1.1.2.20     ///// }
332 salcianu 1.1.2.20     private PAEscapeFunc(Relation rel_n, Relation rel_m){
333 salcianu 1.1.2.20         this.rel_n = rel_n;
334 salcianu 1.1.2.20         this.rel_m = rel_m;
335 salcianu 1.1.2.1      }
336 salcianu 1.1.2.5  
337 salcianu 1.1.2.5      /** Returns a <code>PAEscapeFunc</code> containing escape information
338 salcianu 1.1.2.5          only about the nodes from the set <code>remaining_nodes</code>. */
339 salcianu 1.1.2.5      public PAEscapeFunc select(Set remaining_nodes){
340 salcianu 1.1.2.5          Relation _rel_n = rel_n.select(remaining_nodes);
341 salcianu 1.1.2.14 
342 salcianu 1.1.2.20         ///// Set set = new HashSet();
343 salcianu 1.1.2.20         ///// for(Iterator it = escaped_into_mh.iterator(); it.hasNext(); ){
344 salcianu 1.1.2.20         /////    PANode node = (PANode) it.next();
345 salcianu 1.1.2.20         /////    if(remaining_nodes.contains(node))
346 salcianu 1.1.2.20         /////   set.add(node);
347 salcianu 1.1.2.20         ///// }
348 salcianu 1.1.2.20         Relation _rel_m = rel_m.select(remaining_nodes);
349 salcianu 1.1.2.14         
350 salcianu 1.1.2.20         //// return new PAEscapeFunc(_rel_n, set);
351 salcianu 1.1.2.20         return new PAEscapeFunc(_rel_n, _rel_m);
352 salcianu 1.1.2.5      }
353 salcianu 1.1.2.5  
354 salcianu 1.1.2.1  
355 cananian 1.3          /** <code>clone</code> does a deep copy of <code>this</code> object. */
356 salcianu 1.1.2.1      public Object clone(){
357 salcianu 1.1.2.20         /////   return
358 salcianu 1.1.2.20         /////    new PAEscapeFunc((Relation)(rel_n.clone()),
359 salcianu 1.1.2.20         /////                (Set) ((HashSet) escaped_into_mh).clone());
360 salcianu 1.1.2.1          return
361 salcianu 1.1.2.21             new PAEscapeFunc((Relation) (rel_n.clone()),
362 salcianu 1.1.2.21                              (Relation) (rel_m.clone()));
363 salcianu 1.1.2.1      }
364 salcianu 1.1.2.1  
365 salcianu 1.1.2.6      /** Pretty-print debug function.
366 salcianu 1.1.2.6          Two equal <code>PAEscapeFunc</code>s are guaranteed to have the same
367 salcianu 1.1.2.6          string representation. */
368 salcianu 1.1.2.1      public String toString(){
369 salcianu 1.1.2.7          StringBuffer buffer = new StringBuffer(" Escape function:\n");
370 salcianu 1.1.2.1  
371 salcianu 1.1.2.21         Set set = new HashSet(rel_n.keys());
372 salcianu 1.1.2.20         ////// set.addAll(escaped_into_mh);
373 salcianu 1.1.2.21         set.addAll(rel_m.keys());
374 salcianu 1.1.2.1  
375 salcianu 1.1.2.6          Object[] nodes = Debug.sortedSet(set);
376 salcianu 1.1.2.6          for(int i = 0; i < nodes.length ; i++){
377 salcianu 1.1.2.6              PANode n = (PANode) nodes[i];
378 salcianu 1.1.2.6              buffer.append("  " + n + ":");
379 salcianu 1.1.2.1              
380 salcianu 1.1.2.6              Object[] nholes = Debug.sortedSet(nodeHolesSet(n));
381 salcianu 1.1.2.6              for(int j = 0 ; j < nholes.length ; j++){
382 salcianu 1.1.2.6                  buffer.append(" ");
383 salcianu 1.1.2.6                  buffer.append((PANode)nholes[j]);
384 salcianu 1.1.2.1              }
385 salcianu 1.1.2.6  
386 salcianu 1.1.2.20             Object[] mholes = Debug.sortedSet(methodHolesSet(n));
387 salcianu 1.1.2.20             for(int j = 0 ; j < mholes.length ; j++){
388 salcianu 1.4                      buffer.append("\n\t");
389 salcianu 1.1.2.20                 buffer.append((HMethod)mholes[j]);
390 salcianu 1.1.2.20             }
391 salcianu 1.1.2.14 
392 salcianu 1.1.2.20             ///// if(escaped_into_mh.contains(n))
393 salcianu 1.1.2.20             /////       buffer.append(" M");
394 salcianu 1.1.2.6              buffer.append("\n");
395 salcianu 1.1.2.1          }
396 salcianu 1.1.2.1          
397 salcianu 1.1.2.1          return buffer.toString();
398 salcianu 1.1.2.1      }
399 salcianu 1.1.2.1  }