001: /*
002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.java;
027:
028: import java.util.Hashtable;
029:
030: /**
031: * This class represents an Java Type.<p>
032: *
033: * It encapsulates an Java type signature and it provides
034: * quick access to the components of the type. Note that
035: * all types are hashed into a hashtable (typeHash), that
036: * means that each distinct type is only allocated once,
037: * saving space and making equality checks cheap.<p>
038: *
039: * For simple types use the constants defined in this class.
040: * (Type.tInt, Type.tShort, ...). To create complex types use
041: * the static methods Type.tArray, Type.tMethod or Type.tClass.
042: *
043: * For classes, arrays and method types a sub class of class
044: * type is created which defines the extra type components.
045: *
046: * WARNING: The contents of this source file are not part of any
047: * supported API. Code that depends on them does so at its own risk:
048: * they are subject to change or removal without notice.
049: *
050: * @see ArrayType
051: * @see ClassType
052: * @see MethodType
053: * @author Arthur van Hoff
054: * @version 1.41, 05/05/07
055: */
056: public class Type implements Constants {
057: /**
058: * This hashtable is used to cache types
059: */
060: private static final Hashtable typeHash = new Hashtable(231);
061:
062: /**
063: * The TypeCode of this type. The value of this field is one
064: * of the TC_* contant values defined in Constants.
065: * @see Constants
066: */
067: protected int typeCode;
068:
069: /**
070: * The TypeSignature of this type. This type signature is
071: * equivalent to the runtime type signatures used by the
072: * interpreter.
073: */
074: protected String typeSig;
075:
076: /*
077: * Predefined types.
078: */
079: public static final Type noArgs[] = new Type[0];
080: public static final Type tError = new Type(TC_ERROR, "?");
081: public static final Type tPackage = new Type(TC_ERROR, ".");
082: public static final Type tNull = new Type(TC_NULL, "*");
083: public static final Type tVoid = new Type(TC_VOID, SIG_VOID);
084: public static final Type tBoolean = new Type(TC_BOOLEAN,
085: SIG_BOOLEAN);
086: public static final Type tByte = new Type(TC_BYTE, SIG_BYTE);
087: public static final Type tChar = new Type(TC_CHAR, SIG_CHAR);
088: public static final Type tShort = new Type(TC_SHORT, SIG_SHORT);
089: public static final Type tInt = new Type(TC_INT, SIG_INT);
090: public static final Type tFloat = new Type(TC_FLOAT, SIG_FLOAT);
091: public static final Type tLong = new Type(TC_LONG, SIG_LONG);
092: public static final Type tDouble = new Type(TC_DOUBLE, SIG_DOUBLE);
093: public static final Type tObject = Type.tClass(idJavaLangObject);
094: public static final Type tClassDesc = Type.tClass(idJavaLangClass);
095: public static final Type tString = Type.tClass(idJavaLangString);
096: public static final Type tCloneable = Type
097: .tClass(idJavaLangCloneable);
098: public static final Type tSerializable = Type
099: .tClass(idJavaIoSerializable);
100:
101: /**
102: * Create a type given a typecode and a type signature.
103: */
104: protected Type(int typeCode, String typeSig) {
105: this .typeCode = typeCode;
106: this .typeSig = typeSig;
107: typeHash.put(typeSig, this );
108: }
109:
110: /**
111: * Return the Java type signature.
112: */
113: public final String getTypeSignature() {
114: return typeSig;
115: }
116:
117: /**
118: * Return the type code.
119: */
120: public final int getTypeCode() {
121: return typeCode;
122: }
123:
124: /**
125: * Return the type mask. The bits in this mask correspond
126: * to the TM_* constants defined in Constants. Only one bit
127: * is set at a type.
128: * @see Constants
129: */
130: public final int getTypeMask() {
131: return 1 << typeCode;
132: }
133:
134: /**
135: * Check for a certain type.
136: */
137: public final boolean isType(int tc) {
138: return typeCode == tc;
139: }
140:
141: /**
142: * Check to see if this is the bogus type "array of void"
143: *
144: * Although this highly degenerate "type" is not constructable from
145: * the grammar, the Parser accepts it. Rather than monkey with the
146: * Parser, we check for the bogus type at specific points and give
147: * a nice error.
148: */
149: public boolean isVoidArray() {
150: // a void type is not a void array.
151: if (!isType(TC_ARRAY)) {
152: return false;
153: }
154: // If this is an array, find out what its element type is.
155: Type type = this ;
156: while (type.isType(TC_ARRAY))
157: type = type.getElementType();
158:
159: return type.isType(TC_VOID);
160: }
161:
162: /**
163: * Check for a certain set of types.
164: */
165: public final boolean inMask(int tm) {
166: return ((1 << typeCode) & tm) != 0;
167: }
168:
169: /**
170: * Create an array type.
171: */
172: public static synchronized Type tArray(Type elem) {
173: String sig = new String(SIG_ARRAY + elem.getTypeSignature());
174: Type t = (Type) typeHash.get(sig);
175: if (t == null) {
176: t = new ArrayType(sig, elem);
177: }
178: return t;
179: }
180:
181: /**
182: * Return the element type of an array type. Only works
183: * for array types.
184: */
185: public Type getElementType() {
186: throw new CompilerError("getElementType");
187: }
188:
189: /**
190: * Return the array dimension. Only works for
191: * array types.
192: */
193: public int getArrayDimension() {
194: return 0;
195: }
196:
197: /**
198: * Create a class type.
199: * @arg className the fully qualified class name
200: */
201: public static synchronized Type tClass(Identifier className) {
202: if (className.isInner()) {
203: Type t = tClass(mangleInnerType(className));
204: if (t.getClassName() != className)
205: // Somebody got here first with a mangled name.
206: // (Perhaps it came from a binary.)
207: changeClassName(t.getClassName(), className);
208: return t;
209: }
210: // see if we've cached the object in the Identifier
211: if (className.typeObject != null) {
212: return className.typeObject;
213: }
214: String sig = new String(SIG_CLASS
215: + className.toString().replace('.', SIGC_PACKAGE)
216: + SIG_ENDCLASS);
217: Type t = (Type) typeHash.get(sig);
218: if (t == null) {
219: t = new ClassType(sig, className);
220: }
221:
222: className.typeObject = t; // cache the Type object in the Identifier
223: return t;
224: }
225:
226: /**
227: * Return the ClassName. Only works on class types.
228: */
229: public Identifier getClassName() {
230: throw new CompilerError("getClassName:" + this );
231: }
232:
233: /**
234: * Given an inner identifier, return the non-inner, mangled
235: * representation used to manage signatures.
236: *
237: * Note: It is changed to 'public' for Jcov file generation.
238: * (see Assembler.java)
239: */
240:
241: public static Identifier mangleInnerType(Identifier className) {
242: // Map "pkg.Foo. Bar" to "pkg.Foo$Bar".
243: if (!className.isInner())
244: return className;
245: Identifier mname = Identifier.lookup(className.getFlatName()
246: .toString().replace('.', SIGC_INNERCLASS));
247: if (mname.isInner())
248: throw new CompilerError("mangle " + mname);
249: return Identifier.lookup(className.getQualifier(), mname);
250: }
251:
252: /**
253: * We have learned that a signature means something other
254: * that what we thought it meant. Live with it: Change all
255: * affected data structures to reflect the new name of the old type.
256: * <p>
257: * (This is necessary because of an ambiguity between the
258: * low-level signatures of inner types and their manglings.
259: * Note that the latter are also valid class names.)
260: */
261: static void changeClassName(Identifier oldName, Identifier newName) {
262: // Note: If we are upgrading "pkg.Foo$Bar" to "pkg.Foo. Bar",
263: // we assume someone else will come along and deal with any types
264: // inner within Bar. So, there's only one change to make.
265: ((ClassType) Type.tClass(oldName)).className = newName;
266: }
267:
268: /**
269: * Create a method type with no arguments.
270: */
271: public static synchronized Type tMethod(Type ret) {
272: return tMethod(ret, noArgs);
273: }
274:
275: /**
276: * Create a method type with arguments.
277: */
278: public static synchronized Type tMethod(Type returnType,
279: Type argTypes[]) {
280: StringBuffer buf = new StringBuffer();
281: buf.append(SIG_METHOD);
282: for (int i = 0; i < argTypes.length; i++) {
283: buf.append(argTypes[i].getTypeSignature());
284: }
285: buf.append(SIG_ENDMETHOD);
286: buf.append(returnType.getTypeSignature());
287:
288: String sig = buf.toString();
289: Type t = (Type) typeHash.get(sig);
290: if (t == null) {
291: t = new MethodType(sig, returnType, argTypes);
292: }
293: return t;
294: }
295:
296: /**
297: * Return the return type. Only works for method types.
298: */
299: public Type getReturnType() {
300: throw new CompilerError("getReturnType");
301: }
302:
303: /**
304: * Return the argument types. Only works for method types.
305: */
306: public Type getArgumentTypes()[] {
307: throw new CompilerError("getArgumentTypes");
308: }
309:
310: /**
311: * Create a Type from an Java type signature.
312: * @exception CompilerError invalid type signature.
313: */
314: public static synchronized Type tType(String sig) {
315: Type t = (Type) typeHash.get(sig);
316: if (t != null) {
317: return t;
318: }
319:
320: switch (sig.charAt(0)) {
321: case SIGC_ARRAY:
322: return Type.tArray(tType(sig.substring(1)));
323:
324: case SIGC_CLASS:
325: return Type.tClass(Identifier.lookup(sig.substring(1,
326: sig.length() - 1).replace(SIGC_PACKAGE, '.')));
327:
328: case SIGC_METHOD: {
329: Type argv[] = new Type[8];
330: int argc = 0;
331: int i, j;
332:
333: for (i = 1; sig.charAt(i) != SIGC_ENDMETHOD; i = j) {
334: for (j = i; sig.charAt(j) == SIGC_ARRAY; j++)
335: ;
336: if (sig.charAt(j++) == SIGC_CLASS) {
337: while (sig.charAt(j++) != SIGC_ENDCLASS)
338: ;
339: }
340: if (argc == argv.length) {
341: Type newargv[] = new Type[argc * 2];
342: System.arraycopy(argv, 0, newargv, 0, argc);
343: argv = newargv;
344: }
345: argv[argc++] = tType(sig.substring(i, j));
346: }
347:
348: Type argtypes[] = new Type[argc];
349: System.arraycopy(argv, 0, argtypes, 0, argc);
350: return Type.tMethod(tType(sig.substring(i + 1)), argtypes);
351: }
352: }
353:
354: throw new CompilerError("invalid TypeSignature:" + sig);
355: }
356:
357: /**
358: * Check if the type arguments are the same.
359: * @return true if both types are method types and the
360: * argument types are identical.
361: */
362: public boolean equalArguments(Type t) {
363: return false;
364: }
365:
366: /**
367: * Return the amount of space this type takes up on the
368: * Java operand stack. For a method this is equal to the
369: * total space taken up by the arguments.
370: */
371: public int stackSize() {
372: switch (typeCode) {
373: case TC_ERROR:
374: case TC_VOID:
375: return 0;
376: case TC_BOOLEAN:
377: case TC_BYTE:
378: case TC_SHORT:
379: case TC_CHAR:
380: case TC_INT:
381: case TC_FLOAT:
382: case TC_ARRAY:
383: case TC_CLASS:
384: return 1;
385: case TC_LONG:
386: case TC_DOUBLE:
387: return 2;
388: }
389: throw new CompilerError("stackSize " + toString());
390: }
391:
392: /**
393: * Return the type code offset. This offset can be added to
394: * an opcode to get the right opcode type. Most opcodes
395: * are ordered: int, long, float, double, array. For
396: * example: iload, lload fload, dload, aload. So the
397: * appropriate opcode is iadd + type.getTypeCodeOffset().
398: */
399: public int getTypeCodeOffset() {
400: switch (typeCode) {
401: case TC_BOOLEAN:
402: case TC_BYTE:
403: case TC_SHORT:
404: case TC_CHAR:
405: case TC_INT:
406: return 0;
407: case TC_LONG:
408: return 1;
409: case TC_FLOAT:
410: return 2;
411: case TC_DOUBLE:
412: return 3;
413: case TC_NULL:
414: case TC_ARRAY:
415: case TC_CLASS:
416: return 4;
417: }
418: throw new CompilerError("invalid typecode: " + typeCode);
419: }
420:
421: /**
422: * Convert a Type to a string, if abbrev is true class names are
423: * not fully qualified, if ret is true the return type is included.
424: */
425: public String typeString(String id, boolean abbrev, boolean ret) {
426: String s = null;
427:
428: switch (typeCode) {
429: case TC_NULL:
430: s = "null";
431: break;
432: case TC_VOID:
433: s = "void";
434: break;
435: case TC_BOOLEAN:
436: s = "boolean";
437: break;
438: case TC_BYTE:
439: s = "byte";
440: break;
441: case TC_CHAR:
442: s = "char";
443: break;
444: case TC_SHORT:
445: s = "short";
446: break;
447: case TC_INT:
448: s = "int";
449: break;
450: case TC_LONG:
451: s = "long";
452: break;
453: case TC_FLOAT:
454: s = "float";
455: break;
456: case TC_DOUBLE:
457: s = "double";
458: break;
459: case TC_ERROR:
460: s = "<error>";
461: if (this == tPackage)
462: s = "<package>";
463: break;
464: default:
465: s = "unknown";
466: }
467:
468: return (id.length() > 0) ? s + " " + id : s;
469: }
470:
471: /**
472: * Create a type string, given an identifier.
473: */
474: public String typeString(String id) {
475: return typeString(id, false, true);
476: }
477:
478: /**
479: * Convert to a String
480: */
481: public String toString() {
482: return typeString("", false, true);
483: }
484: }
|