001: // Copyright (c) 1997, 2000, 2003, 2004, 2006 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: import java.util.*;
007:
008: public abstract class Type {
009: String signature;
010: // Fully-qualified name (in external format, i.e. using '.' to separate).
011: String this _name;
012: /**
013: * Nominal unpromoted size in bytes.
014: */
015: int size;
016:
017: ArrayType array_type;
018:
019: protected Type() {
020: }
021:
022: /** The type used to implement types not natively understood by the JVM.
023:
024: * Usually, the identity function. However, a language might handle
025: * union types or template types or type expressions calculated at
026: * run time. In that case return the type used at the JVM level,
027: * and known at compile time.
028: */
029: public Type getImplementationType() {
030: return this ;
031: }
032:
033: // Maps java.lang.Class to corresponding Type.
034: /* #ifdef JAVA2 */
035: /* #ifdef JAVA5 */
036: // static WeakHashMap<Class,Type> mapClassToType;
037: /* #else */
038: static WeakHashMap mapClassToType;
039: /* #endif */
040: /* #else */
041: // static Hashtable mapClassToType;
042: /* #endif */
043:
044: /** Maps Java type name (e.g. "java.lang.String[]") to corresponding Type. */
045: /* #ifdef JAVA5 */
046: // static java.util.HashMap<String,Type> mapNameToType;
047: /* #else */
048: static java.util.Hashtable mapNameToType;
049:
050: /* #endif */
051:
052: public static Type lookupType(String name) {
053: /* #ifdef JAVA5 */
054: // java.util.HashMap<String,Type> map = mapNameToType;
055: // synchronized (map) { return map.get(name); }
056: /* #else */
057: return (Type) mapNameToType.get(name);
058: /* #endif */
059: }
060:
061: /** Find an Type with the given name, or create a new one.
062: * Use this for "library classes", where you need the field/method types,
063: * but not one where you are about to generate code for.
064: * @param name the name of the class (e..g. "java.lang.String").
065: */
066: public static Type getType(String name) {
067: /* #ifdef JAVA5 */
068: // java.util.HashMap<String,Type> map = mapNameToType;
069: /* #else */
070: java.util.Hashtable map = mapNameToType;
071: /* #endif */
072: synchronized (map) {
073: Type type = (Type) map.get(name);
074: if (type == null) {
075: if (name.endsWith("[]"))
076: type = ArrayType.make(name);
077: else {
078: ClassType cl = new ClassType(name);
079: cl.flags |= ClassType.EXISTING_CLASS;
080: type = cl;
081: }
082: map.put(name, type);
083: }
084: return type;
085: }
086: }
087:
088: /** Register that the Type for class is type. */
089: public synchronized static void registerTypeForClass(Class clas,
090: Type type) {
091: /* #ifdef JAVA2 */
092: /* #ifdef JAVA5 */
093: // WeakHashMap<Class,Type> map = mapClassToType;
094: // if (map == null)
095: // mapClassToType = map = new WeakHashMap<Class,Type>(100);
096: /* #else */
097: WeakHashMap map = mapClassToType;
098: if (map == null)
099: mapClassToType = map = new WeakHashMap(100);
100: /* #endif */
101: /* #else */
102: // Hashtable map = mapClassToType;
103: // if (map == null)
104: // mapClassToType = map = new Hashtable(100);
105: /* #endif */
106: map.put(clas, type);
107: type.reflectClass = clas;
108: }
109:
110: public synchronized static Type make(Class reflectClass) {
111: Type type;
112:
113: if (mapClassToType != null) {
114: Object t = mapClassToType.get(reflectClass);
115: if (t != null)
116: return (Type) t;
117: }
118: if (reflectClass.isArray())
119: type = ArrayType.make(Type.make(reflectClass
120: .getComponentType()));
121: else if (reflectClass.isPrimitive())
122: throw new Error("internal error - primitive type not found");
123: else {
124: String name = reflectClass.getName();
125: /* #ifdef JAVA5 */
126: // java.util.HashMap<String,Type> map = mapNameToType;
127: /* #else */
128: java.util.Hashtable map = mapNameToType;
129: /* #endif */
130: synchronized (map) {
131: type = (Type) map.get(name);
132: if (type == null
133: || (type.reflectClass != reflectClass && type.reflectClass != null)) {
134: ClassType cl = new ClassType(name);
135: cl.flags |= ClassType.EXISTING_CLASS;
136: type = cl;
137: mapNameToType.put(name, type);
138: }
139: }
140: }
141: registerTypeForClass(reflectClass, type);
142: return type;
143: }
144:
145: public final String getSignature() {
146: return signature;
147: }
148:
149: protected void setSignature(String sig) {
150: this .signature = sig;
151: }
152:
153: Type(String nam, String sig) {
154: this _name = nam;
155: signature = sig;
156: }
157:
158: public Type(Type type) {
159: this _name = type.this _name;
160: signature = type.signature;
161: size = type.size;
162: reflectClass = type.reflectClass;
163: }
164:
165: public Type promote() {
166: return size < 4 ? int_type : this ;
167: }
168:
169: public final int getSize() {
170: return size;
171: }
172:
173: public int getSizeInWords() {
174: return size > 4 ? 2 : 1;
175: }
176:
177: public final boolean isVoid() {
178: return size == 0;
179: }
180:
181: /** Returns the primitive type corresponding to a signature character.
182: * @return a primitive type, or null if there is no such type. */
183: public static PrimType signatureToPrimitive(char sig) {
184: switch (sig) {
185: case 'B':
186: return Type.byte_type;
187: case 'C':
188: return Type.char_type;
189: case 'D':
190: return Type.double_type;
191: case 'F':
192: return Type.float_type;
193: case 'S':
194: return Type.short_type;
195: case 'I':
196: return Type.int_type;
197: case 'J':
198: return Type.long_type;
199: case 'Z':
200: return Type.boolean_type;
201: case 'V':
202: return Type.void_type;
203: }
204: return null;
205: }
206:
207: /** Get a Type corresponding to the given signature string. */
208: public static Type signatureToType(String sig, int off, int len) {
209: if (len == 0)
210: return null;
211: char c = sig.charAt(off);
212: Type type;
213: if (len == 1) {
214: type = signatureToPrimitive(c);
215: if (type != null)
216: return type;
217: }
218: if (c == '[') {
219: type = signatureToType(sig, off + 1, len - 1);
220: return type == null ? null : ArrayType.make(type);
221: }
222: if (c == 'L' && len > 2
223: && sig.indexOf(';', off) == len - 1 + off)
224: return ClassType.make(sig.substring(off + 1, len - 1 + off)
225: .replace('/', '.'));
226: return null;
227: }
228:
229: /** Get a Type corresponding to the given signature string. */
230: public static Type signatureToType(String sig) {
231: return signatureToType(sig, 0, sig.length());
232: }
233:
234: /** Return the length of the signature starting at a given string position.
235: * Returns -1 for an invalid signature. */
236: public static int signatureLength(String sig, int pos) {
237: int len = sig.length();
238: if (len <= pos)
239: return -1;
240: char c = sig.charAt(pos);
241: int arrays = 0;
242: while (c == '[') {
243: arrays++;
244: pos++;
245: c = sig.charAt(pos);
246: }
247: if (signatureToPrimitive(c) != null)
248: return arrays + 1;
249: if (c == 'L') {
250: int end = sig.indexOf(';', pos);
251: if (end > 0)
252: return arrays + end + 1 - pos;
253: }
254: return -1;
255: }
256:
257: public static int signatureLength(String sig) {
258: return signatureLength(sig, 0);
259: }
260:
261: /** Returns the Java-level type name from a given signature.
262: * Returns null for an invalid signature. */
263: public static String signatureToName(String sig) {
264: int len = sig.length();
265: if (len == 0)
266: return null;
267: char c = sig.charAt(0);
268: Type type;
269: if (len == 1) {
270: type = signatureToPrimitive(c);
271: if (type != null)
272: return type.getName();
273: }
274: if (c == '[') {
275: int arrays = 1;
276: if (arrays < len && sig.charAt(arrays) == '[')
277: arrays++;
278: sig = signatureToName(sig.substring(arrays));
279: if (sig == null)
280: return null;
281: StringBuffer buf = new StringBuffer(50);
282: buf.append(sig);
283: while (--arrays >= 0)
284: buf.append("[]");
285: return buf.toString();
286: }
287: if (c == 'L' && len > 2 && sig.indexOf(';') == len - 1)
288: return sig.substring(1, len - 1).replace('/', '.');
289: return null;
290: }
291:
292: public final String getName() {
293: return this _name;
294: }
295:
296: protected void setName(String name) {
297: this _name = name;
298: }
299:
300: public static boolean isValidJavaTypeName(String name) {
301: boolean in_name = false;
302: int i;
303: int len = name.length();
304: while (len > 2 && name.charAt(len - 1) == ']'
305: && name.charAt(len - 2) == '[')
306: len -= 2;
307: for (i = 0; i < len; i++) {
308: char ch = name.charAt(i);
309: if (ch == '.') {
310: if (in_name)
311: in_name = false;
312: else
313: return false;
314: } else if (in_name ? Character.isJavaIdentifierPart(ch)
315: : Character.isJavaIdentifierStart(ch))
316: in_name = true;
317: else
318: return false;
319: }
320: return i == len;
321: }
322:
323: public boolean isInstance(Object obj) {
324: return getReflectClass().isInstance(obj);
325: }
326:
327: /** Return true if this is a "subtype" of other. */
328: public final boolean isSubtype(Type other) {
329: int comp = compare(other);
330: return comp == -1 || comp == 0;
331: }
332:
333: /**
334: * Computes the common supertype
335: *
336: * Interfaces are not taken into account.
337: * This would be difficult, since interfaces allow multiple-inheritance.
338: * This means that there may exists multiple common supertypes
339: * to t1 and t2 that are not comparable.
340: *
341: * @return the lowest type that is both above t1 and t2,
342: * or null if t1 and t2 have no common supertype.
343: */
344: public static Type lowestCommonSuperType(Type t1, Type t2) {
345: if (t1 == neverReturnsType)
346: return t2;
347: if (t2 == neverReturnsType)
348: return t1;
349: if (t1 == null || t2 == null)
350: return null;
351:
352: if (t1.isSubtype(t2))
353: return t2;
354: else if (t2.isSubtype(t1))
355: return t1;
356: else {
357: // the only chance left is that t1 and t2 are ClassTypes.
358: if (!(t1 instanceof ClassType && t2 instanceof ClassType))
359: return null;
360: ClassType c1 = (ClassType) t1;
361: ClassType c2 = (ClassType) t2;
362: if (c1.isInterface())
363: return Type.pointer_type;
364: if (c2.isInterface())
365: return Type.pointer_type;
366:
367: return lowestCommonSuperType(c1.getSuperclass(), c2
368: .getSuperclass());
369: }
370: }
371:
372: /** Return a numeric code showing "subtype" relationship:
373: * 1: if other is a pure subtype of this;
374: * 0: if has the same values;
375: * -1: if this is a pure subtype of other;
376: * -2: if they have values in common but neither is a subtype of the other;
377: * -3: if the types have no values in common.
378: * "Same member" is rather loose; by "A is a subtype of B"
379: * we mean that all instance of A can be "widened" to B.
380: * More formally, A.compare(B) returns:
381: * 1: all B values can be converted to A without a coercion failure
382: * (i.e. a ClassCastException or overflow or major loss of information),
383: * but not vice versa.
384: * 0: all A values can be converted to B without a coercion failure
385: * and vice versa;
386: * -1: all A values can be converted to B without a coercion failure
387: * not not vice versa;
388: * -2: there are (potentially) some A values that can be converted to B,
389: * and some B values can be converted to A;
390: * -3: there are no A values that can be converted to B, and neither
391: * are there any B values that can be converted to A.
392: */
393: public abstract int compare(Type other);
394:
395: /** Change result from compare to compensate for argument swapping. */
396: protected static int swappedCompareResult(int code) {
397: return code == 1 ? -1 : code == -1 ? 1 : code;
398: }
399:
400: /** Return true iff t1[i].isSubtype(t2[i]) for all i. */
401: public static boolean isMoreSpecific(Type[] t1, Type[] t2) {
402: if (t1.length != t2.length)
403: return false;
404: for (int i = t1.length; --i >= 0;) {
405: if (!t1[i].isSubtype(t2[i]))
406: return false;
407: }
408: return true;
409: }
410:
411: public void emitIsInstance(CodeAttr code) {
412: code.emitInstanceof(this );
413: }
414:
415: /** Convert an object to a value of this Type.
416: * Throw a ClassCastException when this is not possible. */
417: public abstract Object coerceFromObject(Object obj);
418:
419: public Object coerceToObject(Object obj) {
420: return obj;
421: }
422:
423: /** Compile code to convert a object of this type on the stack to Object. */
424: public void emitCoerceToObject(CodeAttr code) {
425: }
426:
427: /** Compile code to coerce/convert from Object to this type. */
428: public void emitCoerceFromObject(CodeAttr code) {
429: throw new Error("unimplemented emitCoerceFromObject for "
430: + this );
431: }
432:
433: public static final PrimType byte_type = new PrimType("byte", "B",
434: 1, java.lang.Byte.TYPE);
435: public static final PrimType short_type = new PrimType("short",
436: "S", 2, java.lang.Short.TYPE);
437: public static final PrimType int_type = new PrimType("int", "I", 4,
438: java.lang.Integer.TYPE);
439: public static final PrimType long_type = new PrimType("long", "J",
440: 8, java.lang.Long.TYPE);
441: public static final PrimType float_type = new PrimType("float",
442: "F", 4, java.lang.Float.TYPE);
443: public static final PrimType double_type = new PrimType("double",
444: "D", 8, java.lang.Double.TYPE);
445: public static final PrimType boolean_type = new PrimType("boolean",
446: "Z", 1, java.lang.Boolean.TYPE);
447: public static final PrimType char_type = new PrimType("char", "C",
448: 2, java.lang.Character.TYPE);
449: public static final PrimType void_type = new PrimType("void", "V",
450: 0, java.lang.Void.TYPE);
451:
452: static {
453: /* #ifdef JAVA5 */
454: // mapNameToType = new java.util.HashMap<String,Type>();
455: /* #else */
456: mapNameToType = new java.util.Hashtable();
457: /* #endif */
458: mapNameToType.put("byte", byte_type);
459: mapNameToType.put("short", short_type);
460: mapNameToType.put("int", int_type);
461: mapNameToType.put("long", long_type);
462: mapNameToType.put("float", float_type);
463: mapNameToType.put("double", double_type);
464: mapNameToType.put("boolean", boolean_type);
465: mapNameToType.put("char", char_type);
466: mapNameToType.put("void", void_type);
467: }
468:
469: /** The "return type" of an expression that never returns, such as a throw. */
470: public static final PrimType neverReturnsType = new PrimType(
471: void_type);
472: static {
473: neverReturnsType.this _name = "(never-returns)";
474: }
475:
476: /** The magic type of null. */
477: public static final ObjectType nullType = new ObjectType(
478: "(type of null)");
479:
480: static public ClassType string_type = ClassType
481: .make("java.lang.String");
482: /* The String type. but coercion is handled by toString. */
483: public static final ClassType tostring_type = new ClassType(
484: "java.lang.String");
485:
486: public static final ClassType pointer_type = ClassType
487: .make("java.lang.Object");
488: public static final ClassType boolean_ctype = ClassType
489: .make("java.lang.Boolean");
490: public static final ClassType throwable_type = ClassType
491: .make("java.lang.Throwable");
492: public static final Type[] typeArray0 = new Type[0];
493: public static final Method toString_method = pointer_type
494: .getDeclaredMethod("toString", 0);
495: public static final ClassType number_type = ClassType
496: .make("java.lang.Number");
497: public static final Method clone_method = Method
498: .makeCloneMethod(pointer_type);
499: public static final Method intValue_method = number_type.addMethod(
500: "intValue", typeArray0, int_type, Access.PUBLIC);
501: public static final Method longValue_method = number_type
502: .addMethod("longValue", typeArray0, long_type,
503: Access.PUBLIC);
504: public static final Method floatValue_method = number_type
505: .addMethod("floatValue", typeArray0, float_type,
506: Access.PUBLIC);
507: public static final Method doubleValue_method = number_type
508: .addMethod("doubleValue", typeArray0, double_type,
509: Access.PUBLIC);
510: public static final Method booleanValue_method = boolean_ctype
511: .addMethod("booleanValue", typeArray0, boolean_type,
512: Access.PUBLIC);
513: public static final ClassType java_lang_Class_type = ClassType
514: .make("java.lang.Class");
515:
516: protected Class reflectClass;
517:
518: /** Get the java.lang.Class object for the representation type. */
519: public java.lang.Class getReflectClass() {
520: return reflectClass;
521: }
522:
523: public void setReflectClass(java.lang.Class rclass) {
524: reflectClass = rclass;
525: }
526:
527: public String toString() {
528: return "Type " + getName();
529: }
530:
531: public int hashCode() {
532: String name = toString();
533: return name == null ? 0 : name.hashCode();
534: }
535: }
|