1 cananian 1.1.2.1  // TypeInfo.java, created Thu Sep 10 14:58:21 1998 by cananian
  2 cananian 1.1.2.1  // Copyright (C) 1998 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.Analysis.Quads;
  5 cananian 1.1.2.1  
  6 cananian 1.1.2.1  import harpoon.Analysis.UseDef;
  7 cananian 1.1.2.1  import harpoon.Analysis.Maps.UseDefMap;
  8 cananian 1.1.2.3  import harpoon.ClassFile.HClass;
  9 cananian 1.1.2.3  import harpoon.ClassFile.HCodeElement;
 10 cananian 1.1.2.3  import harpoon.ClassFile.HMethod;
 11 cananian 1.1.2.7  import harpoon.ClassFile.Linker;
 12 cananian 1.1.2.3  import harpoon.IR.Quads.Qop;
 13 cananian 1.1.2.3  import harpoon.IR.Quads.Quad;
 14 cananian 1.1.2.3  import harpoon.IR.Quads.QuadVisitor;
 15 cananian 1.1.2.3  import harpoon.IR.Quads.AGET;
 16 cananian 1.1.2.3  import harpoon.IR.Quads.ALENGTH;
 17 cananian 1.1.2.3  import harpoon.IR.Quads.ANEW;
 18 cananian 1.1.2.3  import harpoon.IR.Quads.ASET;
 19 cananian 1.1.2.3  import harpoon.IR.Quads.CALL;
 20 cananian 1.1.2.3  import harpoon.IR.Quads.CJMP;
 21 cananian 1.1.2.3  import harpoon.IR.Quads.COMPONENTOF;
 22 cananian 1.1.2.3  import harpoon.IR.Quads.CONST;
 23 cananian 1.1.2.3  import harpoon.IR.Quads.GET;
 24 cananian 1.1.2.3  import harpoon.IR.Quads.INSTANCEOF;
 25 cananian 1.1.2.3  import harpoon.IR.Quads.METHOD;
 26 cananian 1.1.2.3  import harpoon.IR.Quads.MOVE;
 27 cananian 1.1.2.3  import harpoon.IR.Quads.NEW;
 28 cananian 1.1.2.3  import harpoon.IR.Quads.OPER;
 29 cananian 1.1.2.3  import harpoon.IR.Quads.PHI;
 30 cananian 1.1.2.3  import harpoon.IR.Quads.RETURN;
 31 cananian 1.1.2.3  import harpoon.IR.Quads.SET;
 32 cananian 1.1.2.3  import harpoon.IR.Quads.SIGMA;
 33 cananian 1.1.2.3  import harpoon.IR.Quads.SWITCH;
 34 cananian 1.1.2.3  import harpoon.IR.Quads.THROW;
 35 cananian 1.1.2.10 import harpoon.IR.Quads.TYPESWITCH;
 36 cananian 1.1.2.3  import harpoon.Temp.Temp;
 37 cananian 1.1.2.1  import harpoon.Util.Util;
 38 cananian 1.1.2.1  import harpoon.Util.Worklist;
 39 cananian 1.1.2.11 import harpoon.Util.Collections.WorkSet;
 40 cananian 1.1.2.1  import harpoon.Util.HClassUtil;
 41 cananian 1.1.2.1  
 42 cananian 1.1.2.1  import java.util.Vector;
 43 cananian 1.1.2.8  import java.util.HashMap;
 44 cananian 1.1.2.8  import java.util.Map;
 45 cananian 1.1.2.1  /**
 46 cananian 1.1.2.1   * <code>TypeInfo</code> is a simple type analysis tool for quad-ssi form.
 47 cananian 1.1.2.1   * 
 48 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 49 cananian 1.5       * @version $Id: TypeInfo.java,v 1.5 2003/07/11 09:38:35 cananian Exp $
 50 cananian 1.1.2.1   */
 51 cananian 1.1.2.1  
 52 cananian 1.5      public class TypeInfo implements harpoon.Analysis.Maps.ExactTypeMap<Quad> {
 53 cananian 1.5          UseDefMap<Quad> usedef;
 54 bdemsky  1.1.2.4      boolean verifierBehavior;
 55 cananian 1.1.2.1  
 56 cananian 1.5          Map<Temp,ExactType> map = new HashMap<Temp,ExactType>();
 57 cananian 1.1.2.1  
 58 cananian 1.1.2.1      /** Creates a <code>TypeInfo</code> analyzer for the specified
 59 cananian 1.1.2.12      *  <code>HCode</code>, which must be in quad-ssi form.
 60 cananian 1.1.2.1       */
 61 cananian 1.5          public TypeInfo(harpoon.IR.Quads.Code hc, UseDefMap<Quad> usedef) { 
 62 cananian 1.1.2.9          this(hc, usedef, false);
 63 bdemsky  1.1.2.4      }
 64 bdemsky  1.1.2.4  
 65 bdemsky  1.1.2.4      /** Creates a <code>TypeInfo</code> analyzer for the specified
 66 cananian 1.1.2.12      *  <code>HCode</code>, which must be in quad-ssi form.
 67 cananian 1.1.2.5       *  If <code>vBehavior</code> is true, the TypeInfo pass's IQ drops
 68 cananian 1.1.2.5       *  to the same level as a typical bytecode verifier; i.e. it gathers
 69 cananian 1.1.2.5       *  no information from instanceof's and such.  Because of the IQ
 70 cananian 1.1.2.5       *  drop, the verifier sometimes can't determine that the operand
 71 cananian 1.1.2.5       *  of an AGET is really an array; with <code>vBehaviour</code> true
 72 cananian 1.1.2.5       *  the <code>TypeInfo</code> handles this case gracefully, rather than
 73 cananian 1.1.2.5       *  failing an assertion.
 74 bdemsky  1.1.2.4       */
 75 cananian 1.5          public TypeInfo(harpoon.IR.Quads.Code hc, UseDefMap<Quad> usedef, boolean vBehavior) { 
 76 bdemsky  1.1.2.4          this.usedef = usedef; 
 77 bdemsky  1.1.2.4          this.verifierBehavior=vBehavior;
 78 cananian 1.3.2.1          assert hc.getName().equals(harpoon.IR.Quads.QuadSSI.codename);
 79 cananian 1.1.2.1          analyze(hc);
 80 cananian 1.1.2.1      }
 81 cananian 1.1.2.1  
 82 cananian 1.1.2.1      /** Creates a <code>TypeInfo</code> analyzer for the specified
 83 cananian 1.1.2.12      *  <code>HCode</code>, which must be in quad-ssi form.
 84 cananian 1.1.2.1       */
 85 cananian 1.5          public TypeInfo(harpoon.IR.Quads.Code hc) { this(hc, new UseDef<Quad>()); }
 86 cananian 1.1.2.1      
 87 cananian 1.5          public HClass typeMap(Quad hce, Temp t)
 88 cananian 1.1.2.9          throws TypeNotKnownException { return exactType(hce, t).type; }
 89 cananian 1.5          public boolean isExactType(Quad hce, Temp t)
 90 cananian 1.1.2.9          throws TypeNotKnownException { return exactType(hce, t).isExact; }
 91 cananian 1.5          private ExactType exactType(Quad hce, Temp t)
 92 cananian 1.1.2.9          throws TypeNotKnownException {
 93 cananian 1.5              assert hce!=null : "HCE is null! "+hce+"/"+t;
 94 cananian 1.5              assert t!=null : "t is null! "+hce+"/"+t;
 95 cananian 1.1.2.9          if (hce==null || t==null) throw new NullPointerException();
 96 cananian 1.1.2.9          if (!hasType(hce, t)) throw new TypeNotKnownException(hce, t);
 97 cananian 1.5              return map.get(t);
 98 cananian 1.1.2.9      }
 99 cananian 1.5          private boolean hasType(Quad hce, Temp t) {
100 cananian 1.1.2.9          return map.containsKey(t);
101 cananian 1.1.2.1      }
102 cananian 1.1.2.1  
103 cananian 1.1.2.12     private void analyze(harpoon.IR.Quads.Code hc) {
104 cananian 1.5              Quad ql[] = hc.getElements();
105 cananian 1.1.2.1          
106 cananian 1.5              WorkSet<Quad> worklist = new WorkSet<Quad>(); // use as FIFO
107 cananian 1.1.2.1          for (int i=0; i<ql.length; i++)
108 cananian 1.1.2.8              worklist.add(ql[i]);
109 cananian 1.1.2.1  
110 cananian 1.1.2.1          // hack to handle typecasting:
111 cananian 1.1.2.1          //  keep track of booleans defined by instanceof's and acmpeq's.
112 cananian 1.5              Map<Temp,Quad> checkcast = new HashMap<Temp,Quad>();
113 bdemsky  1.1.2.4          if (!verifierBehavior)
114 bdemsky  1.1.2.4              for (int i=0; i<ql.length; i++)
115 bdemsky  1.1.2.4                  if (ql[i] instanceof INSTANCEOF ||
116 bdemsky  1.1.2.4                      ql[i] instanceof OPER)
117 bdemsky  1.1.2.4                      checkcast.put(ql[i].def()[0], ql[i]);
118 cananian 1.1.2.1          
119 bdemsky  1.1.2.4          TypeInfoVisitor tiv = new TypeInfoVisitor(hc, checkcast, verifierBehavior);
120 cananian 1.1.2.1          while(!worklist.isEmpty()) {
121 cananian 1.5                  Quad q = worklist.removeFirst(); // use as FIFO
122 cananian 1.1.2.1              tiv.modified = false;
123 cananian 1.1.2.2              q.accept(tiv);
124 cananian 1.1.2.1              if (tiv.modified) {
125 cananian 1.1.2.1                  Temp[] d = q.def();
126 cananian 1.1.2.1                  for (int i=0; i<d.length; i++) {
127 cananian 1.5                          Quad[] u = usedef.useMap(hc, d[i]);
128 cananian 1.1.2.1                      for (int j=0; j<u.length; j++) {
129 cananian 1.5                              worklist.add(u[j]); // only pushes unique quads.
130 cananian 1.1.2.1                      }
131 cananian 1.1.2.1                  }
132 cananian 1.1.2.1              }
133 cananian 1.1.2.1          }
134 cananian 1.1.2.1      }
135 cananian 1.1.2.1  
136 cananian 1.1.2.1      class TypeInfoVisitor extends QuadVisitor {
137 cananian 1.1.2.12         harpoon.IR.Quads.Code hc;
138 cananian 1.1.2.1          boolean modified = false;
139 cananian 1.5              Map<Temp,Quad> checkcast;
140 bdemsky  1.1.2.4          HClass hclassObj;
141 bdemsky  1.1.2.4          boolean verifierBehavior;
142 cananian 1.1.2.7          Linker linker;
143 bdemsky  1.1.2.4  
144 cananian 1.5              TypeInfoVisitor(harpoon.IR.Quads.Code hc, Map<Temp,Quad> checkcast, boolean verifierBehavior) { 
145 bdemsky  1.1.2.4              this.hc = hc; this.checkcast = checkcast;
146 bdemsky  1.1.2.4              this.verifierBehavior=verifierBehavior;
147 cananian 1.1.2.7              this.linker = hc.getMethod().getDeclaringClass().getLinker();
148 bdemsky  1.1.2.4              if (verifierBehavior)
149 cananian 1.1.2.7                  this.hclassObj=linker.forName("java.lang.Object");
150 bdemsky  1.1.2.4          }
151 cananian 1.1.2.1  
152 cananian 1.1.2.1          public void visit(Quad q) { modified = false; }
153 cananian 1.1.2.1  
154 cananian 1.1.2.1          public void visit(AGET q) {
155 cananian 1.1.2.9              if (!hasType(q, q.objectref())) { modified=false; return; }
156 cananian 1.1.2.1              HClass ty = typeMap(q, q.objectref());
157 cananian 1.1.2.9              if (ty==HClass.Void) { modified=false; return; }
158 bdemsky  1.1.2.4              if (!verifierBehavior) {
159 cananian 1.3.2.1                  assert ty.isArray();
160 cananian 1.1.2.9                  modified = merge(q, q.dst(),
161 cananian 1.1.2.9                                   inexact(toInternal(ty.getComponentType())));
162 bdemsky  1.1.2.4              }
163 bdemsky  1.1.2.4              else
164 cananian 1.1.2.9                  modified = merge(q, q.dst(),
165 cananian 1.1.2.9                                   inexact(toInternal(ty.isArray() ?
166 cananian 1.1.2.9                                                      ty.getComponentType() :
167 cananian 1.1.2.9                                                      hclassObj)));
168 cananian 1.1.2.1          }
169 cananian 1.1.2.1          public void visit(ALENGTH q) {
170 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(HClass.Int));
171 cananian 1.1.2.1          }
172 cananian 1.1.2.1          public void visit(ANEW q) {
173 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(q.hclass()));
174 cananian 1.1.2.1          }
175 cananian 1.1.2.1          public void visit(CALL q) {
176 cananian 1.1.2.1              boolean r1 = (q.retval()==null) ? false:
177 cananian 1.1.2.9                  merge(q, q.retval(),
178 cananian 1.1.2.9                        inexact(toInternal(q.method().getReturnType())));
179 cananian 1.1.2.1              // XXX specify class of exception better.
180 cananian 1.1.2.9              boolean r2 = merge(q,q.retex(),
181 cananian 1.1.2.9                                 inexact(linker.forName("java.lang.Throwable")));
182 cananian 1.1.2.1              modified = r1 || r2;
183 cananian 1.1.2.3  
184 cananian 1.1.2.3              // deal with SIGMA functions in CALL
185 cananian 1.1.2.3              for (int i=0; i<q.numSigmas(); i++) {
186 cananian 1.1.2.3                  if (q.src(i)==null) continue;
187 cananian 1.1.2.9                  if (!hasType(q, q.src(i))) continue;
188 cananian 1.1.2.9                  ExactType ty = exactType(q, q.src(i));
189 cananian 1.1.2.3                  for (int j=0; j<q.arity(); j++)
190 cananian 1.1.2.3                      if (merge(q, q.dst(i,j), ty))
191 cananian 1.1.2.3                          modified = true;
192 cananian 1.1.2.3              }
193 cananian 1.1.2.1          }
194 cananian 1.1.2.1          public void visit(COMPONENTOF q) {
195 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(toInternal(HClass.Boolean)));
196 cananian 1.1.2.1          }
197 cananian 1.1.2.1          public void visit(CONST q) {
198 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(toInternal(q.type())));
199 cananian 1.1.2.1          }
200 cananian 1.1.2.1          public void visit(GET q) {
201 cananian 1.1.2.9              modified = merge(q, q.dst(),
202 cananian 1.1.2.9                               inexact(toInternal(q.field().getType())));
203 cananian 1.1.2.1          }
204 cananian 1.1.2.1          public void visit(INSTANCEOF q) {
205 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(toInternal(HClass.Boolean)));
206 cananian 1.1.2.1          }
207 cananian 1.1.2.1          public void visit(METHOD q) {
208 cananian 1.1.2.1              boolean r = false;
209 cananian 1.1.2.1              HMethod m = hc.getMethod();
210 cananian 1.1.2.1              HClass[] pt = m.getParameterTypes();
211 cananian 1.1.2.1              int offset = m.isStatic()?0:1;
212 cananian 1.1.2.1              for (int i=offset; i<q.paramsLength(); i++)
213 cananian 1.1.2.9                  if (merge(q, q.params(i), inexact(toInternal(pt[i-offset])))) 
214 cananian 1.1.2.1                      r = true;
215 cananian 1.1.2.1              if (!m.isStatic())
216 cananian 1.1.2.9                  r = merge(q, q.params(0), inexact(m.getDeclaringClass())) || r;
217 cananian 1.1.2.1              modified = r;
218 cananian 1.1.2.1          }
219 cananian 1.1.2.1          public void visit(MOVE q) {
220 cananian 1.1.2.9              if (!hasType(q, q.src())) { modified = false; return; }
221 cananian 1.1.2.9              modified = merge(q, q.dst(), exactType(q, q.src()));
222 cananian 1.1.2.1          }
223 cananian 1.1.2.1          public void visit(NEW q) {
224 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(q.hclass()));
225 cananian 1.1.2.1          }
226 cananian 1.1.2.1          public void visit(OPER q) {
227 cananian 1.1.2.9              modified = merge(q, q.dst(), exact(toInternal(q.evalType())));
228 cananian 1.1.2.1          }
229 cananian 1.1.2.1          public void visit(PHI q) {
230 cananian 1.1.2.1              boolean r = false;
231 cananian 1.1.2.1              for (int i=0; i<q.numPhis(); i++)
232 cananian 1.1.2.1                  for (int j=0; j<q.arity(); j++) {
233 cananian 1.1.2.1                      if (q.src(i,j)==null) continue;
234 cananian 1.1.2.9                      if (!hasType(q, q.src(i,j))) continue;
235 cananian 1.1.2.9                      if (merge(q, q.dst(i), exactType(q, q.src(i,j))))
236 cananian 1.1.2.1                          r = true;
237 cananian 1.1.2.1                  }
238 cananian 1.1.2.1              modified = r;
239 cananian 1.1.2.1          }
240 cananian 1.1.2.1          public void visit(SIGMA q) {
241 cananian 1.1.2.1              boolean r = false;
242 cananian 1.1.2.1              for (int i=0; i<q.numSigmas(); i++) {
243 cananian 1.1.2.1                  if (q.src(i)==null) continue;
244 cananian 1.1.2.9                  if (!hasType(q, q.src(i))) continue;
245 cananian 1.1.2.9                  ExactType ty = exactType(q, q.src(i));
246 cananian 1.1.2.1                  for (int j=0; j<q.arity(); j++)
247 cananian 1.1.2.1                      if (merge(q, q.dst(i,j), ty))
248 cananian 1.1.2.1                          r = true;
249 cananian 1.1.2.10             }
250 cananian 1.1.2.10             modified = r;
251 cananian 1.1.2.10         }
252 cananian 1.1.2.10         /* TYPESWITCH: we know the type of the index exactly */
253 cananian 1.1.2.10         public void visit(TYPESWITCH q) {
254 cananian 1.1.2.10             boolean r = false;
255 cananian 1.1.2.10             for (int i=0; i<q.numSigmas(); i++) {
256 cananian 1.1.2.10                 if (q.src(i)==null) continue;
257 cananian 1.1.2.10                 if (!hasType(q, q.src(i))) continue;
258 cananian 1.1.2.10                 ExactType ty = exactType(q, q.src(i));
259 cananian 1.1.2.10                 for (int j=0; j<q.arity(); j++)
260 cananian 1.1.2.10                     if (q.src(i) == q.index() && j<q.keysLength())
261 cananian 1.1.2.10                         // we know narrower type.
262 cananian 1.1.2.10                         r= merge(q, q.dst(i, j),inexact(q.keys(j))) || r;
263 cananian 1.1.2.10                     else
264 cananian 1.1.2.10                         r= merge(q, q.dst(i,j), ty) || r;
265 cananian 1.1.2.1              }
266 cananian 1.1.2.1              modified = r;
267 cananian 1.1.2.1          }
268 cananian 1.1.2.1          /* CJMP should actually somehow split and not merge types,
269 cananian 1.1.2.1             i.e. use the information at branch site to find narrower types? */
270 cananian 1.1.2.1          public void visit(CJMP q) {
271 cananian 1.1.2.1              // special case typecasting. (CHECKCAST in bytecode)
272 cananian 1.1.2.1              // special case comparisons against NULL.
273 cananian 1.1.2.1              INSTANCEOF idef = null; // CJMP test is from this INSTANCEOF
274 cananian 1.1.2.1              OPER       odef = null; // CJMP test is from this OPER
275 cananian 1.5                  Quad def = checkcast.get(q.test());
276 cananian 1.1.2.1              if (def instanceof INSTANCEOF) idef = (INSTANCEOF)def;
277 cananian 1.1.2.1              if (def instanceof OPER)       odef = (OPER)def;
278 cananian 1.1.2.1  
279 cananian 1.1.2.1              boolean r = false;
280 cananian 1.1.2.1              for (int i=0; i<q.numSigmas(); i++) {
281 cananian 1.1.2.1                  if (q.src(i)==null) continue;
282 cananian 1.1.2.9                  if (!hasType(q, q.src(i))) continue;
283 cananian 1.1.2.9                  ExactType ty = exactType(q, q.src(i));
284 cananian 1.1.2.1                  for (int j=0; j<q.arity(); j++) {
285 cananian 1.1.2.1                      if (j==1) { // sometimes we gain info on true side of cjmp
286 cananian 1.1.2.1                          if (idef != null && idef.src() == q.src(i)) {
287 cananian 1.1.2.1                              // test from INSTANCEOF.  we know class if true.
288 cananian 1.1.2.9                              r= merge(q,q.dst(i,j),inexact(idef.hclass())) || r;
289 cananian 1.1.2.1                              continue;
290 cananian 1.1.2.1                          }
291 cananian 1.1.2.1                          if (odef != null && odef.opcode()==Qop.ACMPEQ) {
292 cananian 1.1.2.9                            try { // check to be sure we've got enough info:
293 cananian 1.1.2.1                              HClass left = typeMap(odef, odef.operands(0));
294 cananian 1.1.2.1                              HClass right= typeMap(odef, odef.operands(1));
295 cananian 1.1.2.1                              // ACMPEQ.  Types are identical if true.
296 cananian 1.1.2.1                              if (odef.operands(0) == q.src(i) &&
297 cananian 1.1.2.1                                  right == HClass.Void) {
298 cananian 1.1.2.9                                  r = merge(q, q.dst(i,j), exact(right)) || r;
299 cananian 1.1.2.1                                  continue;
300 cananian 1.1.2.1                              }
301 cananian 1.1.2.1                              if (odef.operands(1) == q.src(i) &&
302 cananian 1.1.2.1                                  left == HClass.Void) {
303 cananian 1.1.2.9                                  r = merge(q, q.dst(i,j), exact(left)) || r;
304 cananian 1.1.2.1                                  continue;
305 cananian 1.1.2.1                              }
306 cananian 1.1.2.9                            } catch (TypeNotKnownException tnke) { continue; }
307 cananian 1.1.2.1                          }
308 cananian 1.1.2.1                      }
309 cananian 1.1.2.1                      // fall back
310 cananian 1.1.2.1                      r = merge(q, q.dst(i,j), ty) || r;
311 cananian 1.1.2.1                  }
312 cananian 1.1.2.1              }
313 cananian 1.1.2.1              modified = r;
314 cananian 1.1.2.1          }
315 cananian 1.1.2.1      }
316 cananian 1.1.2.1  
317 cananian 1.1.2.1      HClass toInternal(HClass c) {
318 cananian 1.1.2.1          if (c.equals(HClass.Byte) || c.equals(HClass.Short) ||
319 cananian 1.1.2.1              c.equals(HClass.Char) || c.equals(HClass.Boolean))
320 cananian 1.1.2.1              return HClass.Int;
321 cananian 1.1.2.1          return c;
322 cananian 1.1.2.1      }
323 cananian 1.1.2.9      /* utility */
324 cananian 1.1.2.9      ExactType exact(HClass c) { return new ExactType(c, true); }
325 cananian 1.1.2.9      ExactType inexact(HClass c) { return new ExactType(c, false); }
326 cananian 1.1.2.9  
327 cananian 1.5          boolean merge(Quad hce, Temp t, ExactType newType) {
328 cananian 1.1.2.9          if (!hasType(hce, t)) { map.put(t, newType); return true; }
329 cananian 1.5              ExactType oldType = map.get(t);
330 cananian 1.1.2.9          if (oldType.equals(newType)) return false;
331 cananian 1.1.2.1          // special case 'Void' HClass, which is used for null constants.
332 cananian 1.1.2.9          if (oldType.type==HClass.Void && newType.type != HClass.Void) {
333 cananian 1.1.2.1              map.put(t, newType); return true;
334 cananian 1.1.2.9          } else if (newType.type == HClass.Void)
335 cananian 1.1.2.1              return false;
336 cananian 1.1.2.1          
337 cananian 1.1.2.1          // handle object types (possibly arrays)
338 cananian 1.1.2.9          HClass merged = HClassUtil.commonParent(oldType.type, newType.type);
339 cananian 1.1.2.1          // if the merged value is different from the old value, update...
340 cananian 1.1.2.9          if (merged==oldType.type) return false;
341 cananian 1.1.2.9          map.put(t, new ExactType(merged, false/* merged type is not exact*/));
342 cananian 1.1.2.1          return true;
343 cananian 1.1.2.1      }
344 cananian 1.1.2.1  }
345 bdemsky  1.1.2.4  
346 cananian 1.2