001: // Copyright (c) 1997, 2000 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.io.*;
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: Type() {
018: }
019:
020: /** The type used to implement types not natively understood by the JVM.
021:
022: * Usually, the identity function. However, a language might handle
023: * union types or template types or type expression scalculated at
024: * run time. In that case return the type used at the JVM level,
025: * and known at compile time.
026: */
027: public Type getImplementationType() {
028: return this ;
029: }
030:
031: public static void free(java.util.Map t) {
032: for (java.util.Iterator e = t.entrySet().iterator(); e
033: .hasNext();) {
034: java.util.Map.Entry k = (java.util.Map.Entry) e.next();
035: if (((Type) k.getValue()).collectable)
036: e.remove();
037: }
038: }
039:
040: public boolean collectable;
041:
042: public static void reset() {
043: mapClassToType.clear();
044: free(mapNameToType);
045: }
046:
047: // Maps java.lang.Class to corresponding Type.
048: private static java.util.Map mapClassToType;
049:
050: /** Maps Java type name (e.g. "java.lang.String[]") to corresponding Type. */
051: static java.util.Hashtable mapNameToType;
052:
053: static java.util.Hashtable getMapNameToType() {
054: if (mapNameToType == null) {
055: mapNameToType = new java.util.Hashtable();
056: mapNameToType.put("byte", byte_type);
057: mapNameToType.put("short", short_type);
058: mapNameToType.put("int", int_type);
059: mapNameToType.put("long", long_type);
060: mapNameToType.put("float", float_type);
061: mapNameToType.put("double", double_type);
062: mapNameToType.put("boolean", boolean_type);
063: mapNameToType.put("char", char_type);
064: mapNameToType.put("void", void_type);
065: }
066: return mapNameToType;
067: }
068:
069: public static Type lookupType(String name) {
070: return (Type) getMapNameToType().get(name);
071: }
072:
073: /** Find an Type with the given name, or create a new one.
074: * Use this for "library classes", where you need the field/method types,
075: * but not one where you are about to generate code for.
076: * @param name the name of the class (e..g. "java.lang.String").
077: */
078: public static Type getType(String name) {
079: Type type = lookupType(name);
080: if (type == null) {
081: if (name.endsWith("[]")) {
082: type = getType(name.substring(0, name.length() - 2));
083: type = nice.tools.code.SpecialArray.create(type);
084: } else {
085: type = new ClassType(name, ClassType.EXISTING_CLASS);
086: }
087: mapNameToType.put(name, type);
088: }
089: return type;
090: }
091:
092: /** Register that the Type for class is type. */
093: public static void registerTypeForName(String name, Type type) {
094: mapNameToType.put(name, type);
095: }
096:
097: /** Register that the Type for class is type. */
098: public static void registerTypeForClass(Class clas, Type type) {
099: if (mapClassToType == null)
100: mapClassToType = new java.util.HashMap(100);
101: mapClassToType.put(clas, type);
102: type.reflectClass = clas;
103: }
104:
105: public static void flushTypeChanges() {
106: java.util.Enumeration types = mapNameToType.elements();
107: while (types.hasMoreElements()) {
108: // types.nextElement() should be of type Type
109: Object t = types.nextElement();
110: if (t instanceof ClassType) {
111: ClassType type = (ClassType) t;
112: if ((type.flags & ObjectType.ADD_METHODS_DONE) == 0)
113: continue;
114:
115: type.methods = type.last_method = null;
116: type.methods_count = 0;
117: type.addMethods(type.getReflectClass());
118: }
119: }
120: }
121:
122: public static Type make(Class reflectClass) {
123: Type type;
124: if (mapClassToType != null) {
125: Object t = mapClassToType.get(reflectClass);
126: if (t != null)
127: return (Type) t;
128: }
129:
130: type = lookupType(reflectClass.getName());
131: if (type != null)
132: return type;
133:
134: if (reflectClass.isArray())
135: type = nice.tools.code.SpecialArray.create(Type
136: .make(reflectClass.getComponentType()));
137: else if (reflectClass.isPrimitive())
138: throw new Error("internal error - primitive type not found");
139: else {
140: String name = reflectClass.getName();
141: type = lookupType(name);
142: if (type == null
143: || (type.reflectClass != reflectClass && type.reflectClass != null)) {
144: ClassType cl = new ClassType(name);
145: cl.flags |= ClassType.EXISTING_CLASS;
146: type = cl;
147: mapNameToType.put(name, type);
148: }
149: if (reflectClass.isInterface())
150: ((ClassType) type).access_flags |= Access.INTERFACE;
151: }
152: type.reflectClass = reflectClass;
153: registerTypeForClass(reflectClass, type);
154: return type;
155: }
156:
157: public final String getSignature() {
158: return signature;
159: }
160:
161: protected void setSignature(String sig) {
162: this .signature = sig.intern();
163: }
164:
165: Type(String nam, String sig) {
166: this _name = nam;
167: signature = sig.intern();
168: }
169:
170: public Type promote() {
171: return size < 4 ? int_type : this ;
172: }
173:
174: public final int getSize() {
175: return size;
176: }
177:
178: public final boolean isVoid() {
179: return size == 0;
180: }
181:
182: public boolean isArray() {
183: return false;
184: }
185:
186: /** Returns the primitive type corresponding to a signature character.
187: * @return a primitive type, or null if there is no such type. */
188: public static PrimType signatureToPrimitive(char sig) {
189: switch (sig) {
190: case 'B':
191: return Type.byte_type;
192: case 'C':
193: return Type.char_type;
194: case 'D':
195: return Type.double_type;
196: case 'F':
197: return Type.float_type;
198: case 'S':
199: return Type.short_type;
200: case 'I':
201: return Type.int_type;
202: case 'J':
203: return Type.long_type;
204: case 'Z':
205: return Type.boolean_type;
206: case 'V':
207: return Type.void_type;
208: }
209: return null;
210: }
211:
212: /** Get a Type corresponding to the given signature string. */
213: public static Type signatureToType(String sig, int off, int len) {
214: if (len == 0)
215: return null;
216: char c = sig.charAt(off);
217: Type type;
218: if (len == 1) {
219: type = signatureToPrimitive(c);
220: if (type != null)
221: return type;
222: }
223: if (c == '[') {
224: type = signatureToType(sig, off + 1, len - 1);
225: return type == null ? null : nice.tools.code.SpecialArray
226: .create(type);
227: }
228: if (c == 'L' && len > 2
229: && sig.indexOf(';', off) == len - 1 + off)
230: return getType(sig.substring(off + 1, len - 1 + off)
231: .replace('/', '.'));
232: return null;
233: }
234:
235: /** Get a Type corresponding to the given signature string. */
236: public static Type signatureToType(String sig) {
237: return signatureToType(sig, 0, sig.length());
238: }
239:
240: /** Return the length of the signature starting at a given string position.
241: * Returns -1 for an invalid signature. */
242: public static int signatureLength(String sig, int pos) {
243: int len = sig.length();
244: if (len <= pos)
245: return -1;
246: char c = sig.charAt(pos);
247: int arrays = 0;
248: while (c == '[') {
249: arrays++;
250: pos++;
251: c = sig.charAt(pos);
252: }
253: if (signatureToPrimitive(c) != null)
254: return arrays + 1;
255: if (c == 'L') {
256: int end = sig.indexOf(';', pos);
257: if (end > 0)
258: return arrays + end + 1 - pos;
259: }
260: return -1;
261: }
262:
263: public static int signatureLength(String sig) {
264: return signatureLength(sig, 0);
265: }
266:
267: /** Get a Type corresponding to the given full signature string
268: starting from offset[0].
269: Set offset[0] to the end index of the signature.
270: */
271: public static Type fullSignatureToType(String sig, int[] offset) {
272: char c = sig.charAt(offset[0]++);
273: Type type = signatureToPrimitive(c);
274: if (type != null)
275: return type;
276:
277: if (c == '[') {
278: type = fullSignatureToType(sig, offset);
279: return type == null ? null : nice.tools.code.SpecialArray
280: .create(type);
281: }
282:
283: if (c == 'L') {
284: int colon = sig.indexOf(';', offset[0]);
285: int angle = sig.indexOf('<', offset[0]);
286: int end = colon < angle || angle == -1 ? colon : angle;
287: type = getType(sig.substring(offset[0], end).replace('/',
288: '.'));
289: offset[0] = end + 1;
290:
291: if (end == colon)
292: return type;
293:
294: type = new ParameterizedType((ClassType) type, parseArgs(
295: sig, offset));
296: // Skip ';'
297: offset[0]++;
298: return type;
299: }
300:
301: if (c == 'T') {
302: int end = sig.indexOf(';', offset[0]);
303: type = TypeVariable.lookup(sig.substring(offset[0], end));
304:
305: /* This happens for F-bounded types. For instance
306: java.util.Collections.reverse:
307: <T:Ljava/lang/Object;:Ljava/lang/Comparable<TT;>;>(Ljava/util/List<TT;>;TT;)I
308:
309: Ignore for now. This give a smaller (less restrictive) type.
310:
311: if (type == null)
312: throw new Error("Could not look up " +
313: sig.substring(offset[0], end));
314: */
315:
316: offset[0] = end + 1;
317: return type;
318: }
319:
320: offset[0]--;
321: return null;
322: }
323:
324: /** Get a Type[] corresponding to the given full signature string
325: starting from offset[0].
326: Set offset[0] to the end index of the signature.
327: */
328: private static Type[] parseArgs(String sig, int[] offset) {
329: java.util.Stack args = new java.util.Stack();
330: do {
331: args.push(fullSignatureToType(sig, offset));
332: } while (sig.charAt(offset[0]) != '>');
333: // Skip the '>'
334: offset[0]++;
335:
336: Type[] res = new Type[args.size()];
337: for (int i = args.size(); --i >= 0;)
338: res[i] = (Type) args.pop();
339:
340: return res;
341:
342: }
343:
344: /** Returns the Java-level type name from a given signature.
345: * Returns null for an invalid signature. */
346: public static String signatureToName(String sig) {
347: int len = sig.length();
348: if (len == 0)
349: return null;
350: char c = sig.charAt(0);
351: Type type;
352: if (len == 1) {
353: type = signatureToPrimitive(c);
354: if (type != null)
355: return type.getName();
356: }
357: if (c == '[') {
358: int arrays = 1;
359: if (arrays < len && sig.charAt(arrays) == '[')
360: arrays++;
361: sig = signatureToName(sig.substring(arrays));
362: if (sig == null)
363: return null;
364: StringBuffer buf = new StringBuffer(50);
365: buf.append(sig);
366: while (--arrays >= 0)
367: buf.append("[]");
368: return buf.toString();
369: }
370: if (c == 'L' && len > 2 && sig.indexOf(';') == len - 1)
371: return sig.substring(1, len - 1).replace('/', '.');
372: return null;
373: }
374:
375: public String getName() {
376: return this _name;
377: }
378:
379: public static boolean isValidJavaTypeName(String name) {
380: boolean in_name = false;
381: int i;
382: int len = name.length();
383: while (len > 2 && name.charAt(len - 1) == ']'
384: && name.charAt(len - 2) == '[')
385: len -= 2;
386: for (i = 0; i < len; i++) {
387: char ch = name.charAt(i);
388: if (ch == '.') {
389: if (in_name)
390: in_name = false;
391: else
392: return false;
393: } else if (in_name ? Character.isJavaIdentifierPart(ch)
394: : Character.isJavaIdentifierStart(ch))
395: in_name = true;
396: else
397: return false;
398: }
399: return i == len;
400: }
401:
402: public boolean isInstance(Object obj) {
403: return getReflectClass().isInstance(obj);
404: }
405:
406: /** Return true if this is a "subtype" of other. */
407: public boolean isSubtype(Type other) {
408: int comp = compare(other);
409: return comp == -1 || comp == 0;
410: }
411:
412: /** @return true if values of this type can be assigned to other
413: <b>without widening nor conversion</b>.
414: */
415: public abstract boolean isAssignableTo(Type other);
416:
417: /**
418: * Computes the common supertype
419: *
420: * Interfaces are not taken into account.
421: * This would be difficult, since interfaces allow multiple-inheritance.
422: * This means that there may exists multiple common supertypes
423: * to t1 and t2 that are not comparable.
424: *
425: * @return the lowest type that is both above t1 and t2,
426: * or null if t1 and t2 have no common supertype.
427: */
428: public static Type lowestCommonSuperType(Type t1, Type t2) {
429: if (t1 == neverReturnsType)
430: return t2;
431: if (t2 == neverReturnsType)
432: return t1;
433: if (t1 == null || t2 == null)
434: return null;
435:
436: // Optimization
437: if (t1 == t2)
438: return t1;
439:
440: if (t1.isSubtype(t2))
441: return t2;
442: else if (t2.isSubtype(t1))
443: return t1;
444: else if (t1 == char_type && t2.isSubtype(int_type))
445: return int_type;
446: else if (t2 == char_type && t1.isSubtype(int_type))
447: return int_type;
448: else {
449: // the only chance left is that t1 and t2 are ClassTypes.
450: if (!(t1 instanceof ClassType && t2 instanceof ClassType))
451: return null;
452: ClassType c1 = (ClassType) t1;
453: ClassType c2 = (ClassType) t2;
454: if (c1.isInterface())
455: return Type.pointer_type;
456: if (c2.isInterface())
457: return Type.pointer_type;
458:
459: return lowestCommonSuperType(c1.getSuperclass(), c2
460: .getSuperclass());
461: }
462: }
463:
464: /** Return a numeric code showing "subtype" relationship:
465: * 1: if other is a pure subtype of this;
466: * 0: if has the same values;
467: * -1: if this is a pure subtype of other;
468: * -2: if they have values in common but neither is a subtype of the other;
469: * -3: if the types have no values in common.
470: * "Same member" is rather loose; by "A is a subtype of B"
471: * we mean that all instance of A can be "widened" to B.
472: * More formally, A.compare(B) returns:
473: * 1: all B values can be converted to A without a coercion failure
474: * (i.e. a ClassCastException or overflow or major loss of information),
475: * but not vice versa.
476: * 0: all A values can be converted to B without a coercion failure
477: * and vice versa;
478: * -1: all A values can be converted to B without a coercion failure
479: * not not vice versa;
480: * -2: there are (potentially) some A values that can be converted to B,
481: * and some B values can be converted to A;
482: * -3: there are no A values that can be converted to B, and neither
483: * are there any B values that can be converted to A.
484: */
485: public abstract int compare(Type other);
486:
487: /** Change result from compare to compensate for argument swapping. */
488: protected static int swappedCompareResult(int code) {
489: return code == 1 ? -1 : code == -1 ? 1 : code;
490: }
491:
492: /** Return true iff t1[i].isSubtype(t2[i]) for all i. */
493: public static boolean isMoreSpecific(Type[] t1, Type[] t2) {
494: if (t1.length != t2.length)
495: return false;
496: for (int i = t1.length; --i >= 0;) {
497: if (!t1[i].isSubtype(t2[i]))
498: return false;
499: }
500: return true;
501: }
502:
503: public void emitIsInstance(CodeAttr code) {
504: code.emitInstanceof(this );
505: }
506:
507: /** Convert an object to a value of this Type.
508: * Throw a ClassCastException when this is not possible. */
509: public abstract Object coerceFromObject(Object obj);
510:
511: public Object coerceToObject(Object obj) {
512: return obj;
513: }
514:
515: /** Compile code to convert a object of this type on the stack to Object. */
516: public void emitCoerceToObject(CodeAttr code) {
517: }
518:
519: /** Compile code to convert an object (on the stack) of this Type
520: to toType. */
521: public void emitCoerceTo(Type toType, CodeAttr code) {
522: // Default implementation.
523: emitCoerceToObject(code);
524: }
525:
526: /** Compile code to convert an object (on the stack) of that Type
527: to this Type. */
528: public void emitCoerceFrom(Type fromType, CodeAttr code) {
529: // Default implementation: do nothing.
530: }
531:
532: /** Compile code to coerce/convert from Object to this type. */
533: public void emitCoerceFromObject(CodeAttr code) {
534: throw new Error("unimplemented emitCoerceFromObject for "
535: + this );
536: }
537:
538: /**
539: Return an equivalent method when the receiver is of this type.
540: Return null if no more precise method exists.
541: */
542: Method refineMethod(Method method) {
543: return null;
544: }
545:
546: public static final PrimType byte_type = new PrimType("byte", "B",
547: 1, java.lang.Byte.TYPE);
548: public static final PrimType short_type = new PrimType("short",
549: "S", 2, java.lang.Short.TYPE);
550: public static final PrimType int_type = new PrimType("int", "I", 4,
551: java.lang.Integer.TYPE);
552: public static final PrimType long_type = new PrimType("long", "J",
553: 8, java.lang.Long.TYPE);
554: public static final PrimType float_type = new PrimType("float",
555: "F", 4, java.lang.Float.TYPE);
556: public static final PrimType double_type = new PrimType("double",
557: "D", 8, java.lang.Double.TYPE);
558: public static final PrimType boolean_type = new PrimType("boolean",
559: "Z", 1, java.lang.Boolean.TYPE);
560: public static final PrimType char_type = new PrimType("char", "C",
561: 2, java.lang.Character.TYPE);
562: // place never-returns first, so that void is registered for Void.TYPE
563: /** The "return type" of an expression that never returns, e.g. a throw. */
564: public static final PrimType neverReturnsType = new PrimType(
565: "(never-returns)", "V", 0, java.lang.Void.TYPE);
566: public static final PrimType void_type = new PrimType("void", "V",
567: 0, java.lang.Void.TYPE);
568:
569: public static ClassType int_ctype = ClassType
570: .make("java.lang.Integer");
571: public static ClassType long_ctype = ClassType
572: .make("java.lang.Long");
573: public static ClassType char_ctype = ClassType
574: .make("java.lang.Character");
575: public static ClassType float_ctype = ClassType
576: .make("java.lang.Float");
577: public static ClassType double_ctype = ClassType
578: .make("java.lang.Double");
579:
580: /** The magic type of null. */
581: public static final ObjectType nullType = new ObjectType(
582: "(type of null)");
583:
584: static public ClassType string_type = ClassType
585: .make("java.lang.String");
586: /* The String type. but coercion is handled by toString. */
587: static public ClassType tostring_type = new ClassType(
588: "java.lang.String");
589:
590: static public ClassType pointer_type = ClassType
591: .make("java.lang.Object");
592: static public ClassType boolean_ctype = ClassType
593: .make("java.lang.Boolean");
594: static public ClassType throwable_type = ClassType
595: .make("java.lang.Throwable");
596:
597: static public ClassType short_ctype = ClassType
598: .make("java.lang.Short");
599: static public ClassType byte_ctype = ClassType
600: .make("java.lang.Byte");
601:
602: static public Type[] typeArray0 = new Type[0];
603: static public Method toString_method = pointer_type
604: .getDeclaredMethod("toString", 0);
605: static public ClassType number_type = ClassType
606: .make("java.lang.Number");
607: static public Method intValue_method = number_type.addMethod(
608: "intValue", typeArray0, int_type, Access.PUBLIC);
609: static public Method longValue_method = number_type.addMethod(
610: "longValue", typeArray0, long_type, Access.PUBLIC);
611: static public Method floatValue_method = number_type.addMethod(
612: "floatValue", typeArray0, float_type, Access.PUBLIC);
613: static public Method doubleValue_method = number_type.addMethod(
614: "doubleValue", typeArray0, double_type, Access.PUBLIC);
615: static public Method booleanValue_method = boolean_ctype.addMethod(
616: "booleanValue", typeArray0, boolean_type, Access.PUBLIC);
617:
618: static public ClassType character_type = ClassType
619: .make("java.lang.Character");
620: static public Method charValue_method = character_type.addMethod(
621: "charValue", typeArray0, char_type, Access.PUBLIC);
622:
623: protected Class reflectClass;
624:
625: /** Get the java.lang.Class object for the representation type. */
626: public java.lang.Class getReflectClass() {
627: return reflectClass;
628: }
629:
630: public String toString() {
631: return "Type " + getName();
632: }
633: }
|