blob: f7dfd0d3bd6a4daacba2af1165661ea819d1eff4 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.java;
27
28import java.util.Hashtable;
29
30/**
31 * This class represents an Java Type.<p>
32 *
33 * It encapsulates an Java type signature and it provides
34 * quick access to the components of the type. Note that
35 * all types are hashed into a hashtable (typeHash), that
36 * means that each distinct type is only allocated once,
37 * saving space and making equality checks cheap.<p>
38 *
39 * For simple types use the constants defined in this class.
40 * (Type.tInt, Type.tShort, ...). To create complex types use
41 * the static methods Type.tArray, Type.tMethod or Type.tClass.
42 *
43 * For classes, arrays and method types a sub class of class
44 * type is created which defines the extra type components.
45 *
46 * WARNING: The contents of this source file are not part of any
47 * supported API. Code that depends on them does so at its own risk:
48 * they are subject to change or removal without notice.
49 *
50 * @see ArrayType
51 * @see ClassType
52 * @see MethodType
53 * @author Arthur van Hoff
54 */
55public
56class Type implements Constants {
57 /**
58 * This hashtable is used to cache types
59 */
60 private static final Hashtable typeHash = new Hashtable(231);
61
62 /**
63 * The TypeCode of this type. The value of this field is one
64 * of the TC_* contant values defined in Constants.
65 * @see Constants
66 */
67 protected int typeCode;
68
69 /**
70 * The TypeSignature of this type. This type signature is
71 * equivalent to the runtime type signatures used by the
72 * interpreter.
73 */
74 protected String typeSig;
75
76 /*
77 * Predefined types.
78 */
79 public static final Type noArgs[] = new Type[0];
80 public static final Type tError = new Type(TC_ERROR, "?");
81 public static final Type tPackage = new Type(TC_ERROR, ".");
82 public static final Type tNull = new Type(TC_NULL, "*");
83 public static final Type tVoid = new Type(TC_VOID, SIG_VOID);
84 public static final Type tBoolean = new Type(TC_BOOLEAN, SIG_BOOLEAN);
85 public static final Type tByte = new Type(TC_BYTE, SIG_BYTE);
86 public static final Type tChar = new Type(TC_CHAR, SIG_CHAR);
87 public static final Type tShort = new Type(TC_SHORT, SIG_SHORT);
88 public static final Type tInt = new Type(TC_INT, SIG_INT);
89 public static final Type tFloat = new Type(TC_FLOAT, SIG_FLOAT);
90 public static final Type tLong = new Type(TC_LONG, SIG_LONG);
91 public static final Type tDouble = new Type(TC_DOUBLE, SIG_DOUBLE);
92 public static final Type tObject = Type.tClass(idJavaLangObject);
93 public static final Type tClassDesc = Type.tClass(idJavaLangClass);
94 public static final Type tString = Type.tClass(idJavaLangString);
95 public static final Type tCloneable = Type.tClass(idJavaLangCloneable);
96 public static final Type tSerializable = Type.tClass(idJavaIoSerializable);
97
98 /**
99 * Create a type given a typecode and a type signature.
100 */
101 protected Type(int typeCode, String typeSig) {
102 this.typeCode = typeCode;
103 this.typeSig = typeSig;
104 typeHash.put(typeSig, this);
105 }
106
107 /**
108 * Return the Java type signature.
109 */
110 public final String getTypeSignature() {
111 return typeSig;
112 }
113
114 /**
115 * Return the type code.
116 */
117 public final int getTypeCode() {
118 return typeCode;
119 }
120
121 /**
122 * Return the type mask. The bits in this mask correspond
123 * to the TM_* constants defined in Constants. Only one bit
124 * is set at a type.
125 * @see Constants
126 */
127 public final int getTypeMask() {
128 return 1 << typeCode;
129 }
130
131 /**
132 * Check for a certain type.
133 */
134 public final boolean isType(int tc) {
135 return typeCode == tc;
136 }
137
138 /**
139 * Check to see if this is the bogus type "array of void"
140 *
141 * Although this highly degenerate "type" is not constructable from
142 * the grammar, the Parser accepts it. Rather than monkey with the
143 * Parser, we check for the bogus type at specific points and give
144 * a nice error.
145 */
146 public boolean isVoidArray() {
147 // a void type is not a void array.
148 if (!isType(TC_ARRAY)) {
149 return false;
150 }
151 // If this is an array, find out what its element type is.
152 Type type = this;
153 while (type.isType(TC_ARRAY))
154 type = type.getElementType();
155
156 return type.isType(TC_VOID);
157 }
158
159
160 /**
161 * Check for a certain set of types.
162 */
163 public final boolean inMask(int tm) {
164 return ((1 << typeCode) & tm) != 0;
165 }
166
167 /**
168 * Create an array type.
169 */
170 public static synchronized Type tArray(Type elem) {
171 String sig = new String(SIG_ARRAY + elem.getTypeSignature());
172 Type t = (Type)typeHash.get(sig);
173 if (t == null) {
174 t = new ArrayType(sig, elem);
175 }
176 return t;
177 }
178
179 /**
180 * Return the element type of an array type. Only works
181 * for array types.
182 */
183 public Type getElementType() {
184 throw new CompilerError("getElementType");
185 }
186
187 /**
188 * Return the array dimension. Only works for
189 * array types.
190 */
191 public int getArrayDimension() {
192 return 0;
193 }
194
195 /**
196 * Create a class type.
197 * @arg className the fully qualified class name
198 */
199 public static synchronized Type tClass(Identifier className) {
200 if (className.isInner()) {
201 Type t = tClass(mangleInnerType(className));
202 if (t.getClassName() != className)
203 // Somebody got here first with a mangled name.
204 // (Perhaps it came from a binary.)
205 changeClassName(t.getClassName(), className);
206 return t;
207 }
208 // see if we've cached the object in the Identifier
209 if (className.typeObject != null) {
210 return className.typeObject;
211 }
212 String sig =
213 new String(SIG_CLASS +
214 className.toString().replace('.', SIGC_PACKAGE) +
215 SIG_ENDCLASS);
216 Type t = (Type)typeHash.get(sig);
217 if (t == null) {
218 t = new ClassType(sig, className);
219 }
220
221 className.typeObject = t; // cache the Type object in the Identifier
222 return t;
223 }
224
225 /**
226 * Return the ClassName. Only works on class types.
227 */
228 public Identifier getClassName() {
229 throw new CompilerError("getClassName:" + this);
230 }
231
232 /**
233 * Given an inner identifier, return the non-inner, mangled
234 * representation used to manage signatures.
235 *
236 * Note: It is changed to 'public' for Jcov file generation.
237 * (see Assembler.java)
238 */
239
240 public static Identifier mangleInnerType(Identifier className) {
241 // Map "pkg.Foo. Bar" to "pkg.Foo$Bar".
242 if (!className.isInner()) return className;
243 Identifier mname = Identifier.lookup(
244 className.getFlatName().toString().
245 replace('.', SIGC_INNERCLASS) );
246 if (mname.isInner()) throw new CompilerError("mangle "+mname);
247 return Identifier.lookup(className.getQualifier(), mname);
248 }
249
250 /**
251 * We have learned that a signature means something other
252 * that what we thought it meant. Live with it: Change all
253 * affected data structures to reflect the new name of the old type.
254 * <p>
255 * (This is necessary because of an ambiguity between the
256 * low-level signatures of inner types and their manglings.
257 * Note that the latter are also valid class names.)
258 */
259 static void changeClassName(Identifier oldName, Identifier newName) {
260 // Note: If we are upgrading "pkg.Foo$Bar" to "pkg.Foo. Bar",
261 // we assume someone else will come along and deal with any types
262 // inner within Bar. So, there's only one change to make.
263 ((ClassType)Type.tClass(oldName)).className = newName;
264 }
265
266 /**
267 * Create a method type with no arguments.
268 */
269 public static synchronized Type tMethod(Type ret) {
270 return tMethod(ret, noArgs);
271 }
272
273 /**
274 * Create a method type with arguments.
275 */
276 public static synchronized Type tMethod(Type returnType, Type argTypes[]) {
277 StringBuffer buf = new StringBuffer();
278 buf.append(SIG_METHOD);
279 for (int i = 0 ; i < argTypes.length ; i++) {
280 buf.append(argTypes[i].getTypeSignature());
281 }
282 buf.append(SIG_ENDMETHOD);
283 buf.append(returnType.getTypeSignature());
284
285 String sig = buf.toString();
286 Type t = (Type)typeHash.get(sig);
287 if (t == null) {
288 t = new MethodType(sig, returnType, argTypes);
289 }
290 return t;
291 }
292
293 /**
294 * Return the return type. Only works for method types.
295 */
296 public Type getReturnType() {
297 throw new CompilerError("getReturnType");
298 }
299
300 /**
301 * Return the argument types. Only works for method types.
302 */
303 public Type getArgumentTypes()[] {
304 throw new CompilerError("getArgumentTypes");
305 }
306
307 /**
308 * Create a Type from an Java type signature.
309 * @exception CompilerError invalid type signature.
310 */
311 public static synchronized Type tType(String sig) {
312 Type t = (Type)typeHash.get(sig);
313 if (t != null) {
314 return t;
315 }
316
317 switch (sig.charAt(0)) {
318 case SIGC_ARRAY:
319 return Type.tArray(tType(sig.substring(1)));
320
321 case SIGC_CLASS:
322 return Type.tClass(Identifier.lookup(sig.substring(1, sig.length() - 1).replace(SIGC_PACKAGE, '.')));
323
324 case SIGC_METHOD: {
325 Type argv[] = new Type[8];
326 int argc = 0;
327 int i, j;
328
329 for (i = 1 ; sig.charAt(i) != SIGC_ENDMETHOD ; i = j) {
330 for (j = i ; sig.charAt(j) == SIGC_ARRAY ; j++);
331 if (sig.charAt(j++) == SIGC_CLASS) {
332 while (sig.charAt(j++) != SIGC_ENDCLASS);
333 }
334 if (argc == argv.length) {
335 Type newargv[] = new Type[argc * 2];
336 System.arraycopy(argv, 0, newargv, 0, argc);
337 argv = newargv;
338 }
339 argv[argc++] = tType(sig.substring(i, j));
340 }
341
342 Type argtypes[] = new Type[argc];
343 System.arraycopy(argv, 0, argtypes, 0, argc);
344 return Type.tMethod(tType(sig.substring(i + 1)), argtypes);
345 }
346 }
347
348 throw new CompilerError("invalid TypeSignature:" + sig);
349 }
350
351 /**
352 * Check if the type arguments are the same.
353 * @return true if both types are method types and the
354 * argument types are identical.
355 */
356 public boolean equalArguments(Type t) {
357 return false;
358 }
359
360 /**
361 * Return the amount of space this type takes up on the
362 * Java operand stack. For a method this is equal to the
363 * total space taken up by the arguments.
364 */
365 public int stackSize() {
366 switch (typeCode) {
367 case TC_ERROR:
368 case TC_VOID:
369 return 0;
370 case TC_BOOLEAN:
371 case TC_BYTE:
372 case TC_SHORT:
373 case TC_CHAR:
374 case TC_INT:
375 case TC_FLOAT:
376 case TC_ARRAY:
377 case TC_CLASS:
378 return 1;
379 case TC_LONG:
380 case TC_DOUBLE:
381 return 2;
382 }
383 throw new CompilerError("stackSize " + toString());
384 }
385
386 /**
387 * Return the type code offset. This offset can be added to
388 * an opcode to get the right opcode type. Most opcodes
389 * are ordered: int, long, float, double, array. For
390 * example: iload, lload fload, dload, aload. So the
391 * appropriate opcode is iadd + type.getTypeCodeOffset().
392 */
393 public int getTypeCodeOffset() {
394 switch (typeCode) {
395 case TC_BOOLEAN:
396 case TC_BYTE:
397 case TC_SHORT:
398 case TC_CHAR:
399 case TC_INT:
400 return 0;
401 case TC_LONG:
402 return 1;
403 case TC_FLOAT:
404 return 2;
405 case TC_DOUBLE:
406 return 3;
407 case TC_NULL:
408 case TC_ARRAY:
409 case TC_CLASS:
410 return 4;
411 }
412 throw new CompilerError("invalid typecode: " + typeCode);
413 }
414
415 /**
416 * Convert a Type to a string, if abbrev is true class names are
417 * not fully qualified, if ret is true the return type is included.
418 */
419 public String typeString(String id, boolean abbrev, boolean ret) {
420 String s = null;
421
422 switch (typeCode) {
423 case TC_NULL: s = "null"; break;
424 case TC_VOID: s = "void"; break;
425 case TC_BOOLEAN: s = "boolean"; break;
426 case TC_BYTE: s = "byte"; break;
427 case TC_CHAR: s = "char"; break;
428 case TC_SHORT: s = "short"; break;
429 case TC_INT: s = "int"; break;
430 case TC_LONG: s = "long"; break;
431 case TC_FLOAT: s = "float"; break;
432 case TC_DOUBLE: s = "double"; break;
433 case TC_ERROR: s = "<error>";
434 if (this==tPackage) s = "<package>";
435 break;
436 default: s = "unknown";
437 }
438
439 return (id.length() > 0) ? s + " " + id : s;
440 }
441
442 /**
443 * Create a type string, given an identifier.
444 */
445 public String typeString(String id) {
446 return typeString(id, false, true);
447 }
448
449 /**
450 * Convert to a String
451 */
452 public String toString() {
453 return typeString("", false, true);
454 }
455}