1 salcianu 1.1.2.1  // PAThreadMap.java, created Sun Jan  9 15:49:32 2000 by salcianu
  2 cananian 1.1.2.3  // 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.lang.System;
  7 salcianu 1.1.2.1  import java.util.Hashtable;
  8 salcianu 1.1.2.1  import java.util.Enumeration;
  9 salcianu 1.1.2.1  import java.util.Map;
 10 salcianu 1.1.2.1  import java.util.Iterator;
 11 salcianu 1.1.2.2  import java.util.Set;
 12 salcianu 1.1.2.1  
 13 salcianu 1.1.2.8  import java.util.Arrays;
 14 salcianu 1.1.2.8  
 15 salcianu 1.1.2.7  import harpoon.Util.Util;
 16 salcianu 1.1.2.7  
 17 salcianu 1.1.2.14 import harpoon.Util.DataStructs.Relation;
 18 salcianu 1.1.2.14 
 19 salcianu 1.1.2.1  /**
 20 salcianu 1.1.2.1   * <code>PAThreadMap</code> implements the parallel thread map
 21 salcianu 1.1.2.1   * (i.e. the "tau" function from the algorithm). For each thread node
 22 salcianu 1.1.2.1   * n, tau(n) is a conservative approximation of the number of instances
 23 salcianu 1.1.2.1   * of nT that could run in parallel with the current thread.
 24 salcianu 1.1.2.1   * tau(n) is a number from the set {0,1,2} where 0 stands for no instance,
 25 salcianu 1.1.2.1   * 1 for at most one instance and 2 for possibly multiple instances.
 26 salcianu 1.1.2.1   * 
 27 salcianu 1.1.2.1   * <code>PAThreadMap</code> is more or less a <code>Hashtable</code> with
 28 salcianu 1.1.2.1   * some access functions to enforce the new rules for addition and
 29 salcianu 1.1.2.1   * substraction.
 30 salcianu 1.1.2.1   *
 31 salcianu 1.1.2.1   * @author  Alexandru SALCIANU <salcianu@retezat.lcs.mit.edu>
 32 cananian 1.5       * @version $Id: PAThreadMap.java,v 1.5 2004/02/08 03:20:03 cananian Exp $
 33 salcianu 1.1.2.1   */
 34 salcianu 1.1.2.15 public class PAThreadMap implements java.io.Serializable {
 35 salcianu 1.1.2.1  
 36 salcianu 1.1.2.1      static private final Integer ONE  = new Integer(1);
 37 salcianu 1.1.2.1      static private final Integer TWO  = new Integer(2);
 38 salcianu 1.1.2.1  
 39 salcianu 1.1.2.1      private Hashtable hash;
 40 salcianu 1.1.2.1      
 41 salcianu 1.1.2.1      /** Creates a <code>PAThreadMap</code>. */
 42 salcianu 1.1.2.1      public PAThreadMap() {
 43 salcianu 1.1.2.1          hash = new Hashtable();
 44 salcianu 1.1.2.1      }
 45 salcianu 1.1.2.1  
 46 salcianu 1.1.2.1      // Look at the value attached to the thread node n
 47 salcianu 1.1.2.1      // (i.e. tau(n)
 48 salcianu 1.1.2.1      public int getValue(PANode n){
 49 salcianu 1.1.2.1          Integer v = (Integer)hash.get(n);
 50 salcianu 1.1.2.1  
 51 salcianu 1.1.2.1          if(v != null){
 52 salcianu 1.1.2.1              return ((Integer) hash.get(n)).intValue();
 53 salcianu 1.1.2.1          }
 54 salcianu 1.1.2.1          else return 0;
 55 salcianu 1.1.2.1      }
 56 salcianu 1.1.2.1  
 57 salcianu 1.1.2.2      /** Increments the value attached to <code>n</code> */
 58 salcianu 1.1.2.1      public void inc(PANode n){
 59 salcianu 1.1.2.1          Integer v = (Integer)hash.get(n);
 60 salcianu 1.1.2.1  
 61 salcianu 1.1.2.1          if(v == null) hash.put(n,ONE);
 62 salcianu 1.1.2.1          if(v == ONE) hash.put(n,TWO);
 63 salcianu 1.1.2.1      }
 64 salcianu 1.1.2.5  
 65 salcianu 1.1.2.5  
 66 salcianu 1.1.2.5      /** Convenient function that calls <code>inc</code> for all the
 67 salcianu 1.1.2.5          nodes from <code>set</code> */
 68 salcianu 1.1.2.5      public void incAll(Set nodes){
 69 cananian 1.5              for (Object nodeO : nodes){
 70 cananian 1.5                  PANode node = (PANode) nodeO;
 71 salcianu 1.1.2.5              inc(node);
 72 salcianu 1.1.2.5          }
 73 salcianu 1.1.2.5      }
 74 salcianu 1.1.2.1      
 75 salcianu 1.1.2.2      /** Decrements the value attached to <code>n</code> */
 76 salcianu 1.1.2.1      public void dec(PANode n){
 77 salcianu 1.1.2.1          Integer v = (Integer)hash.get(n);
 78 salcianu 1.1.2.1  
 79 salcianu 1.1.2.1          if(v==null){
 80 salcianu 1.1.2.1              System.err.println("Error in PAThreadMap: cannot do 0--\n");
 81 salcianu 1.1.2.1              System.exit(1);
 82 salcianu 1.1.2.1          }
 83 salcianu 1.1.2.1  
 84 salcianu 1.1.2.1          // another alternative would be to attach to n a special object
 85 salcianu 1.1.2.1          // ZERO. However, I decided to remove the mapping for n - in this
 86 salcianu 1.1.2.1          // way, we don't create two values for expressing tau(n)=0 (null
 87 salcianu 1.1.2.1          // and ZERO) and decrease the number of keys from the map.
 88 salcianu 1.1.2.1          if(v==ONE) hash.remove(n);
 89 salcianu 1.1.2.1          if(v==TWO) hash.put(n,TWO);
 90 salcianu 1.1.2.12     }
 91 salcianu 1.1.2.12 
 92 salcianu 1.1.2.12     /** Checks whether the thread "nt" is started or not. */
 93 salcianu 1.1.2.12     public boolean isStarted(PANode nt){
 94 salcianu 1.1.2.12         return hash.containsKey(nt);
 95 salcianu 1.1.2.1      }
 96 salcianu 1.1.2.7  
 97 salcianu 1.1.2.7      /** Add a positive <code>delta</code> to the value attached to a node. */
 98 salcianu 1.1.2.7      public void add(PANode n, int delta){
 99 cananian 1.3.2.1          assert delta>0 : ("PAThreadMap.add: delta should be > 0");
100 salcianu 1.1.2.7          int new_tau = getValue(n) + delta;
101 salcianu 1.1.2.7          if( new_tau > 1 )
102 salcianu 1.1.2.7              hash.put(n,TWO);
103 salcianu 1.1.2.7          else
104 salcianu 1.1.2.7              hash.put(n,ONE);
105 salcianu 1.1.2.7      }
106 salcianu 1.1.2.7  
107 salcianu 1.1.2.1  
108 salcianu 1.1.2.5      /** Set to zero the value attached to the node <code>n</code>. */
109 salcianu 1.1.2.5      public void setToZero(PANode n){
110 salcianu 1.1.2.5          hash.remove(n);
111 salcianu 1.1.2.5      }
112 salcianu 1.1.2.5  
113 salcianu 1.1.2.4      /** Returns all the thread nodes <code>nT</code> that have assigned
114 salcianu 1.1.2.4       * a non-zero count (i.e. tau(nT) > 0 in the algorithm) */ 
115 salcianu 1.1.2.1      public Enumeration activeThreads(){
116 salcianu 1.1.2.1          return hash.keys();
117 salcianu 1.1.2.1      }
118 salcianu 1.1.2.1  
119 salcianu 1.1.2.4      /** Returns all the thread nodes <code>nT</code> that have assigned
120 salcianu 1.1.2.4       * a non-zero count (i.e. tau(nT) > 0 in the algorithm) */ 
121 salcianu 1.1.2.4      public Set activeThreadSet(){
122 salcianu 1.1.2.4          return hash.keySet();
123 salcianu 1.1.2.4      }
124 salcianu 1.1.2.11 
125 salcianu 1.1.2.11 
126 salcianu 1.1.2.11     /** Remove all the <code>PANode</code>s that appear in <code>set</code>
127 salcianu 1.1.2.11         from <code>this</code> thread map. */
128 salcianu 1.1.2.11     public void remove(Set set){
129 cananian 1.5              for (Object nodeO : set){
130 cananian 1.5                  PANode node = (PANode) nodeO;
131 salcianu 1.1.2.11             hash.remove(node);
132 salcianu 1.1.2.11         }
133 salcianu 1.1.2.11     }
134 salcianu 1.1.2.11 
135 salcianu 1.1.2.4  
136 salcianu 1.1.2.1      /** <code>join</code> combines two <code>PAThreadMap</code>s in
137 salcianu 1.1.2.1       *  a control-flow join poin */
138 salcianu 1.1.2.1      public void join(PAThreadMap tau2){
139 salcianu 1.1.2.1          Enumeration e = tau2.activeThreads();
140 salcianu 1.1.2.1          while(e.hasMoreElements()){
141 salcianu 1.1.2.1              PANode n = (PANode) e.nextElement();
142 salcianu 1.1.2.9              int count1 = getValue(n);
143 salcianu 1.1.2.9              int count2 = tau2.getValue(n);
144 salcianu 1.1.2.9              if(count2 > count1)
145 salcianu 1.1.2.9                  switch(count2){
146 salcianu 1.1.2.9                  case 1: 
147 salcianu 1.1.2.9                      hash.put(n,ONE);
148 salcianu 1.1.2.9                      break;
149 salcianu 1.1.2.9                  case 2:
150 salcianu 1.1.2.9                      hash.put(n,TWO);
151 salcianu 1.1.2.9                      break;
152 salcianu 1.1.2.9                  default:
153 salcianu 1.1.2.9                      System.err.println("PAThreadMap.join: Strange value!");
154 salcianu 1.1.2.9                  }
155 salcianu 1.1.2.10         }
156 salcianu 1.1.2.10     }
157 salcianu 1.1.2.10 
158 salcianu 1.1.2.10     /** Inserts the image of <code>tau2</code> through the <code>mu</code>
159 salcianu 1.1.2.10         mapping into <code>this</code> object.
160 salcianu 1.1.2.10         Forall <code>node</code> in <code>tau2.activeThreads</code>,
161 salcianu 1.1.2.10         forall <code>node2</code> in <code>mu(node)</code>,
162 salcianu 1.1.2.10         <code>tau(node2) += tau2(node)</code>. */
163 salcianu 1.1.2.10     public void insert(PAThreadMap tau2, Relation mu){
164 salcianu 1.1.2.10         Enumeration e = tau2.activeThreads();
165 salcianu 1.1.2.10         while(e.hasMoreElements()){
166 salcianu 1.1.2.10             PANode node = (PANode) e.nextElement();
167 salcianu 1.1.2.10             int tau_node = tau2.getValue(node);
168 cananian 1.5                  for (Object new_nodeO : mu.getValues(node)){
169 cananian 1.5                      PANode new_node = (PANode) new_nodeO;
170 salcianu 1.1.2.10                 add(new_node,tau_node);
171 salcianu 1.1.2.10             }
172 salcianu 1.1.2.1          }
173 salcianu 1.1.2.13     }
174 salcianu 1.1.2.13 
175 salcianu 1.1.2.13     /* Specializes <code>this</code> <code>PAThreadMap</code> according to
176 salcianu 1.1.2.13        <code>map</code>, a mapping from <code>PANode<code> to
177 salcianu 1.1.2.13        <code>PANode</code>. Each node which is not explicitly mapped is
178 salcianu 1.1.2.13        considered to be mapped to itself. */
179 salcianu 1.1.2.13     public PAThreadMap specialize(final Map map){
180 salcianu 1.1.2.13         final PAThreadMap tau2 = new PAThreadMap();
181 salcianu 1.1.2.13 
182 cananian 1.5              for(Object entryO : hash.entrySet()){
183 cananian 1.5                  Map.Entry entry = (Map.Entry) entryO;
184 salcianu 1.1.2.13             PANode node2 = PANode.translate((PANode) entry.getKey(), map);
185 salcianu 1.1.2.13 
186 salcianu 1.1.2.13             tau2.hash.put(node2, (Integer) entry.getValue());
187 salcianu 1.1.2.13         }
188 salcianu 1.1.2.13         
189 salcianu 1.1.2.13         return tau2;
190 salcianu 1.1.2.1      }
191 salcianu 1.1.2.1  
192 salcianu 1.1.2.2      /** Private constructor used by <code>clone</code> and  
193 salcianu 1.1.2.2       * <code>keepTheEssential</code> */
194 salcianu 1.1.2.1      private PAThreadMap(Hashtable _hash){
195 salcianu 1.1.2.1          hash = _hash;
196 salcianu 1.1.2.1      }
197 salcianu 1.1.2.1      
198 salcianu 1.1.2.1      /** <code>clone</code> creates a copy of <code>this</code> thread map;
199 salcianu 1.1.2.2       *  by doing a simple shallow copy of the <code>hash<code> field. 
200 salcianu 1.1.2.1       */
201 salcianu 1.1.2.1      public Object clone(){
202 salcianu 1.1.2.1          return new PAThreadMap((Hashtable)hash.clone());
203 salcianu 1.1.2.1      }
204 salcianu 1.1.2.1  
205 salcianu 1.1.2.2      /** Produces a new <code>PAThreadMap</code> containing only the thread
206 salcianu 1.1.2.8       * nodes that appear in <code>essential_nodes</code>. */
207 salcianu 1.1.2.2      public PAThreadMap keepTheEssential(Set essential_nodes){
208 salcianu 1.1.2.2          Hashtable _hash = new Hashtable();
209 cananian 1.5              for (Object entryO : hash.entrySet()){
210 cananian 1.5                  Map.Entry entry = (Map.Entry) entryO;
211 salcianu 1.1.2.2              PANode node = (PANode)entry.getKey();    
212 salcianu 1.1.2.2              if(essential_nodes.contains(node))
213 salcianu 1.1.2.2                  _hash.put(node,entry.getValue());
214 salcianu 1.1.2.2          }
215 salcianu 1.1.2.2          return new PAThreadMap(_hash);
216 salcianu 1.1.2.4      }
217 salcianu 1.1.2.4  
218 salcianu 1.1.2.4      /** Checks the equality of two <code>PAThreadMap</code>s */
219 salcianu 1.1.2.4      public boolean equals(Object o){
220 salcianu 1.1.2.4          if(o==null) return false;
221 salcianu 1.1.2.4          PAThreadMap tau2 = (PAThreadMap) o;
222 salcianu 1.1.2.4          Set set1 = activeThreadSet();
223 salcianu 1.1.2.4          Set set2 = tau2.activeThreadSet();
224 salcianu 1.1.2.4          // two PAThreadMap's are equal if they contain the same keys
225 salcianu 1.1.2.4          if(!set1.equals(set2)){
226 salcianu 1.1.2.5              ///System.out.println("PAThreadMap.equals(): different keySet's");
227 salcianu 1.1.2.5              ///System.out.print("Old " + tau2);
228 salcianu 1.1.2.5              ///System.out.print("New " + this);
229 salcianu 1.1.2.4              return false;
230 salcianu 1.1.2.4          }
231 cananian 1.5              for (Object nodeO : set1){
232 cananian 1.5                  PANode node = (PANode) nodeO;
233 salcianu 1.1.2.4              // and assign the same values to them
234 salcianu 1.1.2.4              if(getValue(node)!=tau2.getValue(node)){
235 salcianu 1.1.2.5                  ///System.out.println("PAThreadMap.equals(): " + 
236 salcianu 1.1.2.5                  ///                "different values assigned to " + node +
237 salcianu 1.1.2.5                  ///                " v1=" + tau2.getValue(node) + 
238 salcianu 1.1.2.5                  ///                " v2=" + getValue(node));
239 salcianu 1.1.2.4                  return false;
240 salcianu 1.1.2.4              }
241 salcianu 1.1.2.4          }
242 salcianu 1.1.2.4          return true;
243 salcianu 1.1.2.2      }
244 salcianu 1.1.2.2  
245 salcianu 1.1.2.8      /** Pretty print function for debug purposes.
246 salcianu 1.1.2.8       <code>tau1.equals(tau2) <==> tau1.toString().equals(tau2.toString()).</code> */
247 salcianu 1.1.2.1      public String toString(){
248 salcianu 1.1.2.1          StringBuffer buffer = new StringBuffer("Parallel Thread Map:\n");
249 salcianu 1.1.2.8  
250 salcianu 1.1.2.8          Object[] active_threads = Debug.sortedSet(hash.keySet());
251 salcianu 1.1.2.8          
252 salcianu 1.1.2.8          for(int i = 0 ; i < active_threads.length ; i++){
253 salcianu 1.1.2.8              Object thread = active_threads[i];
254 salcianu 1.1.2.8              Object value  = hash.get(thread);
255 salcianu 1.1.2.8              buffer.append("  " + thread + " -> " + value + "\n");
256 salcianu 1.1.2.1          }
257 salcianu 1.1.2.8          
258 salcianu 1.1.2.8          return buffer.toString();    
259 salcianu 1.1.2.1      }
260 salcianu 1.1.2.1  
261 salcianu 1.1.2.1  }
262 cananian 1.2