KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > bytecode > Type


1 // Copyright (c) 1997, 2000, 2003, 2004, 2006 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.bytecode;
5 import java.util.*;
6
7 public abstract class Type {
8   String JavaDoc signature;
9   // Fully-qualified name (in external format, i.e. using '.' to separate).
10
String JavaDoc this_name;
11   /**
12    * Nominal unpromoted size in bytes.
13    */

14   int size;
15
16   ArrayType array_type;
17
18   protected Type () { }
19
20   /** The type used to implement types not natively understood by the JVM.
21
22    * Usually, the identity function. However, a language might handle
23    * union types or template types or type expressions calculated at
24    * run time. In that case return the type used at the JVM level,
25    * and known at compile time.
26    */

27   public Type getImplementationType()
28   {
29     return this;
30   }
31
32   // Maps java.lang.Class to corresponding Type.
33
/* #ifdef JAVA2 */
34   /* #ifdef JAVA5 */
35   // static WeakHashMap<Class,Type> mapClassToType;
36
/* #else */
37   static WeakHashMap mapClassToType;
38   /* #endif */
39   /* #else */
40   // static Hashtable mapClassToType;
41
/* #endif */
42
43   /** Maps Java type name (e.g. "java.lang.String[]") to corresponding Type. */
44   /* #ifdef JAVA5 */
45   // static java.util.HashMap<String,Type> mapNameToType;
46
/* #else */
47   static java.util.Hashtable JavaDoc mapNameToType;
48   /* #endif */
49
50   public static Type lookupType (String JavaDoc name)
51   {
52     /* #ifdef JAVA5 */
53     // java.util.HashMap<String,Type> map = mapNameToType;
54
// synchronized (map) { return map.get(name); }
55
/* #else */
56     return (Type) mapNameToType.get(name);
57     /* #endif */
58   }
59
60   /** Find an Type with the given name, or create a new one.
61    * Use this for "library classes", where you need the field/method types,
62    * but not one where you are about to generate code for.
63    * @param name the name of the class (e..g. "java.lang.String").
64    */

65   public static Type getType (String JavaDoc name)
66   {
67     /* #ifdef JAVA5 */
68     // java.util.HashMap<String,Type> map = mapNameToType;
69
/* #else */
70     java.util.Hashtable JavaDoc map = mapNameToType;
71     /* #endif */
72     synchronized (map)
73       {
74         Type type = (Type) map.get(name);
75         if (type == null)
76           {
77             if (name.endsWith("[]"))
78               type = ArrayType.make(name);
79             else
80               {
81                 ClassType cl = new ClassType(name);
82                 cl.flags |= ClassType.EXISTING_CLASS;
83                 type = cl;
84               }
85             map.put(name, type);
86           }
87         return type;
88       }
89   }
90
91   /** Register that the Type for class is type. */
92   public synchronized static void registerTypeForClass(Class JavaDoc clas, Type type)
93   {
94     /* #ifdef JAVA2 */
95     /* #ifdef JAVA5 */
96     // WeakHashMap<Class,Type> map = mapClassToType;
97
// if (map == null)
98
// mapClassToType = map = new WeakHashMap<Class,Type>(100);
99
/* #else */
100     WeakHashMap map = mapClassToType;
101     if (map == null)
102       mapClassToType = map = new WeakHashMap(100);
103     /* #endif */
104     /* #else */
105     // Hashtable map = mapClassToType;
106
// if (map == null)
107
// mapClassToType = map = new Hashtable(100);
108
/* #endif */
109     map.put(clas, type);
110     type.reflectClass = clas;
111   }
112
113   public synchronized static Type make(Class JavaDoc reflectClass)
114   {
115     Type type;
116     
117     if (mapClassToType != null)
118       {
119     Object JavaDoc t = mapClassToType.get(reflectClass);
120     if (t != null)
121       return (Type) t;
122       }
123     if (reflectClass.isArray())
124       type = ArrayType.make(Type.make(reflectClass.getComponentType()));
125     else if (reflectClass.isPrimitive())
126       throw new Error JavaDoc("internal error - primitive type not found");
127     else
128       {
129     String JavaDoc name = reflectClass.getName();
130         /* #ifdef JAVA5 */
131         // java.util.HashMap<String,Type> map = mapNameToType;
132
/* #else */
133         java.util.Hashtable JavaDoc map = mapNameToType;
134         /* #endif */
135         synchronized (map)
136           {
137             type = (Type) map.get(name);
138             if (type == null
139                 || (type.reflectClass != reflectClass
140                     && type.reflectClass != null))
141               {
142                 ClassType cl = new ClassType(name);
143                 cl.flags |= ClassType.EXISTING_CLASS;
144                 type = cl;
145                 mapNameToType.put(name, type);
146               }
147           }
148       }
149     registerTypeForClass(reflectClass, type);
150     return type;
151   }
152
153   public final String JavaDoc getSignature () { return signature; }
154   protected void setSignature(String JavaDoc sig) { this.signature = sig; }
155
156   Type (String JavaDoc nam, String JavaDoc sig) {
157     this_name = nam;
158     signature = sig;
159   }
160
161   public Type (Type type)
162   {
163     this_name = type.this_name;
164     signature = type.signature;
165     size = type.size;
166     reflectClass = type.reflectClass;
167   }
168
169   public Type promote () {
170     return size < 4 ? int_type : this;
171   }
172
173   public final int getSize() { return size; }
174   public int getSizeInWords () { return size > 4 ? 2 : 1; }
175
176   public final boolean isVoid () { return size == 0; }
177
178   /** Returns the primitive type corresponding to a signature character.
179    * @return a primitive type, or null if there is no such type. */

180   public static PrimType signatureToPrimitive(char sig)
181   {
182     switch(sig)
183       {
184       case 'B': return Type.byte_type;
185       case 'C': return Type.char_type;
186       case 'D': return Type.double_type;
187       case 'F': return Type.float_type;
188       case 'S': return Type.short_type;
189       case 'I': return Type.int_type;
190       case 'J': return Type.long_type;
191       case 'Z': return Type.boolean_type;
192       case 'V': return Type.void_type;
193       }
194     return null;
195   }
196
197   /** Get a Type corresponding to the given signature string. */
198   public static Type signatureToType(String JavaDoc sig, int off, int len)
199   {
200     if (len == 0)
201       return null;
202     char c = sig.charAt(off);
203     Type type;
204     if (len == 1)
205       {
206     type = signatureToPrimitive(c);
207     if (type != null)
208       return type;
209       }
210     if (c == '[')
211       {
212     type = signatureToType(sig, off+1, len-1);
213     return type == null ? null : ArrayType.make(type);
214       }
215     if (c == 'L' && len > 2 && sig.indexOf(';', off) == len-1+off)
216       return ClassType.make(sig.substring(off+1,len-1+off).replace('/', '.'));
217     return null;
218   }
219
220   /** Get a Type corresponding to the given signature string. */
221   public static Type signatureToType(String JavaDoc sig)
222   {
223     return signatureToType(sig, 0, sig.length());
224   }
225
226   /** Return the length of the signature starting at a given string position.
227    * Returns -1 for an invalid signature. */

228   public static int signatureLength (String JavaDoc sig, int pos)
229   {
230     int len = sig.length();
231     if (len <= pos)
232       return -1;
233     char c = sig.charAt(pos);
234     int arrays = 0;
235     while (c == '[')
236       {
237     arrays++;
238     pos++;
239     c = sig.charAt(pos);
240       }
241     if (signatureToPrimitive(c) != null)
242       return arrays+1;
243     if (c == 'L')
244       {
245     int end = sig.indexOf(';', pos);
246     if (end > 0)
247       return arrays + end + 1 - pos;
248       }
249     return -1;
250   }
251
252   public static int signatureLength (String JavaDoc sig)
253   {
254     return signatureLength(sig, 0);
255   }
256
257   /** Returns the Java-level type name from a given signature.
258    * Returns null for an invalid signature. */

259   public static String JavaDoc signatureToName(String JavaDoc sig)
260   {
261     int len = sig.length();
262     if (len == 0)
263       return null;
264     char c = sig.charAt(0);
265     Type type;
266     if (len == 1)
267       {
268     type = signatureToPrimitive(c);
269     if (type != null)
270       return type.getName();
271       }
272     if (c == '[')
273       {
274     int arrays = 1;
275     if (arrays < len && sig.charAt(arrays) == '[')
276       arrays++;
277     sig = signatureToName(sig.substring(arrays));
278     if (sig == null)
279       return null;
280     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(50);
281     buf.append(sig);
282     while (--arrays >= 0)
283       buf.append("[]");
284     return buf.toString();
285       }
286     if (c == 'L' && len > 2 && sig.indexOf(';') == len-1)
287       return sig.substring(1,len-1).replace('/', '.');
288     return null;
289   }
290
291   public final String JavaDoc getName ()
292   {
293     return this_name;
294   }
295
296   protected void setName (String JavaDoc name)
297   {
298     this_name = name;
299   }
300
301   public static boolean isValidJavaTypeName (String JavaDoc name)
302   {
303     boolean in_name = false;
304     int i;
305     int len = name.length();
306     while (len > 2 && name.charAt(len-1) == ']'
307        && name.charAt(len-2) == '[')
308       len -= 2;
309     for (i = 0; i < len; i++)
310       {
311     char ch = name.charAt(i);
312     if (ch == '.')
313       {
314         if (in_name)
315           in_name = false;
316         else
317           return false;
318       }
319     else if (in_name ? Character.isJavaIdentifierPart(ch)
320          : Character.isJavaIdentifierStart(ch))
321       in_name = true;
322     else
323       return false;
324       }
325     return i == len;
326   }
327
328   public boolean isInstance (Object JavaDoc obj)
329   {
330     return getReflectClass().isInstance(obj);
331   }
332
333   /** Return true if this is a "subtype" of other. */
334   public final boolean isSubtype (Type other)
335   {
336     int comp = compare(other);
337     return comp == -1 || comp == 0;
338   }
339
340   /**
341    * Computes the common supertype
342    *
343    * Interfaces are not taken into account.
344    * This would be difficult, since interfaces allow multiple-inheritance.
345    * This means that there may exists multiple common supertypes
346    * to t1 and t2 that are not comparable.
347    *
348    * @return the lowest type that is both above t1 and t2,
349    * or null if t1 and t2 have no common supertype.
350    */

351   public static Type lowestCommonSuperType(Type t1, Type t2)
352   {
353     if (t1 == neverReturnsType)
354       return t2;
355     if (t2 == neverReturnsType)
356       return t1;
357     if (t1 == null || t2 == null)
358      return null;
359
360     if (t1.isSubtype(t2))
361       return t2;
362     else if (t2.isSubtype(t1))
363       return t1;
364     else
365       {
366        // the only chance left is that t1 and t2 are ClassTypes.
367
if (!(t1 instanceof ClassType && t2 instanceof ClassType))
368          return null;
369        ClassType c1 = (ClassType) t1;
370        ClassType c2 = (ClassType) t2;
371        if (c1.isInterface())
372          return Type.pointer_type;
373        if (c2.isInterface())
374          return Type.pointer_type;
375
376        return lowestCommonSuperType(c1.getSuperclass(), c2.getSuperclass());
377       }
378   }
379
380   /** Return a numeric code showing "subtype" relationship:
381    * 1: if other is a pure subtype of this;
382    * 0: if has the same values;
383    * -1: if this is a pure subtype of other;
384    * -2: if they have values in common but neither is a subtype of the other;
385    * -3: if the types have no values in common.
386    * "Same member" is rather loose; by "A is a subtype of B"
387    * we mean that all instance of A can be "widened" to B.
388    * More formally, A.compare(B) returns:
389    * 1: all B values can be converted to A without a coercion failure
390    * (i.e. a ClassCastException or overflow or major loss of information),
391    * but not vice versa.
392    * 0: all A values can be converted to B without a coercion failure
393    * and vice versa;
394    * -1: all A values can be converted to B without a coercion failure
395    * not not vice versa;
396    * -2: there are (potentially) some A values that can be converted to B,
397    * and some B values can be converted to A;
398    * -3: there are no A values that can be converted to B, and neither
399    * are there any B values that can be converted to A.
400    */

401   public abstract int compare(Type other);
402
403   /** Change result from compare to compensate for argument swapping. */
404   protected static int swappedCompareResult(int code)
405   {
406     return code == 1 ? -1 : code == -1 ? 1 : code;
407   }
408
409   /** Return true iff t1[i].isSubtype(t2[i]) for all i. */
410   public static boolean isMoreSpecific (Type[] t1, Type[] t2)
411   {
412     if (t1.length != t2.length)
413       return false;
414     for (int i = t1.length; --i >= 0; )
415       {
416     if (! t1[i].isSubtype(t2[i]))
417       return false;
418       }
419     return true;
420   }
421
422   public void emitIsInstance (CodeAttr code)
423   {
424     code.emitInstanceof(this);
425   }
426
427   /** Convert an object to a value of this Type.
428    * Throw a ClassCastException when this is not possible. */

429   public abstract Object JavaDoc coerceFromObject (Object JavaDoc obj);
430
431   public Object JavaDoc coerceToObject (Object JavaDoc obj)
432   {
433     return obj;
434   }
435
436   /** Compile code to convert a object of this type on the stack to Object. */
437   public void emitCoerceToObject (CodeAttr code)
438   {
439   }
440
441   /** Compile code to coerce/convert from Object to this type. */
442   public void emitCoerceFromObject (CodeAttr code)
443   {
444     throw new Error JavaDoc ("unimplemented emitCoerceFromObject for "+this);
445   }
446
447   public static final PrimType byte_type
448     = new PrimType ("byte", "B", 1, java.lang.Byte.TYPE);
449   public static final PrimType short_type
450     = new PrimType ("short", "S", 2, java.lang.Short.TYPE);
451   public static final PrimType int_type
452     = new PrimType ("int", "I", 4, java.lang.Integer.TYPE);
453   public static final PrimType long_type
454     = new PrimType ("long", "J", 8, java.lang.Long.TYPE);
455   public static final PrimType float_type
456     = new PrimType ("float", "F", 4, java.lang.Float.TYPE);
457   public static final PrimType double_type
458     = new PrimType ("double", "D", 8, java.lang.Double.TYPE);
459   public static final PrimType boolean_type
460     = new PrimType ("boolean", "Z", 1, java.lang.Boolean.TYPE);
461   public static final PrimType char_type
462     = new PrimType ("char", "C", 2, java.lang.Character.TYPE);
463   public static final PrimType void_type
464     = new PrimType ("void", "V", 0, java.lang.Void.TYPE);
465
466   static
467   {
468     /* #ifdef JAVA5 */
469     // mapNameToType = new java.util.HashMap<String,Type>();
470
/* #else */
471     mapNameToType = new java.util.Hashtable JavaDoc();
472     /* #endif */
473     mapNameToType.put("byte", byte_type);
474     mapNameToType.put("short", short_type);
475     mapNameToType.put("int", int_type);
476     mapNameToType.put("long", long_type);
477     mapNameToType.put("float", float_type);
478     mapNameToType.put("double", double_type);
479     mapNameToType.put("boolean", boolean_type);
480     mapNameToType.put("char", char_type);
481     mapNameToType.put("void", void_type);
482   }
483
484   /** The "return type" of an expression that never returns, such as a throw. */
485   public static final PrimType neverReturnsType = new PrimType (void_type);
486   static { neverReturnsType.this_name = "(never-returns)"; }
487
488   /** The magic type of null. */
489   public static final ObjectType nullType = new ObjectType("(type of null)");
490
491   static public ClassType string_type = ClassType.make("java.lang.String");
492   /* The String type. but coercion is handled by toString. */
493   public static final ClassType tostring_type
494     = new ClassType("java.lang.String");
495
496   public static final ClassType pointer_type
497     = ClassType.make("java.lang.Object");
498   public static final ClassType boolean_ctype
499     = ClassType.make("java.lang.Boolean");
500   public static final ClassType throwable_type
501     = ClassType.make("java.lang.Throwable");
502   public static final Type[] typeArray0 = new Type[0];
503   public static final Method toString_method
504     = pointer_type.getDeclaredMethod("toString", 0);
505   public static final ClassType number_type
506     = ClassType.make("java.lang.Number");
507   public static final Method intValue_method
508     = number_type.addMethod("intValue", typeArray0,
509                 int_type, Access.PUBLIC);
510   public static final Method longValue_method
511     = number_type.addMethod("longValue", typeArray0,
512                 long_type, Access.PUBLIC);
513   public static final Method floatValue_method
514     = number_type.addMethod("floatValue", typeArray0,
515                 float_type, Access.PUBLIC);
516   public static final Method doubleValue_method
517     = number_type.addMethod("doubleValue", typeArray0,
518                 double_type, Access.PUBLIC);
519   public static final Method booleanValue_method
520     = boolean_ctype.addMethod("booleanValue", typeArray0,
521                   boolean_type, Access.PUBLIC);
522   public static final ClassType java_lang_Class_type
523     = ClassType.make("java.lang.Class");
524
525   protected Class JavaDoc reflectClass;
526
527   /** Get the java.lang.Class object for the representation type. */
528   public java.lang.Class JavaDoc getReflectClass()
529   {
530     return reflectClass;
531   }
532
533   public void setReflectClass(java.lang.Class JavaDoc rclass)
534   {
535     reflectClass = rclass;
536   }
537
538   public String JavaDoc toString()
539   {
540     return "Type " + getName();
541   }
542
543   public int hashCode()
544   {
545     String JavaDoc name = toString();
546     return name == null ? 0 : name.hashCode ();
547   }
548 }
549
Popular Tags