author | psandoz |
Mon, 16 Jun 2014 17:45:26 +0100 | |
changeset 24969 | afa6934dd8e8 |
parent 5506 | 202f599c92aa |
child 25799 | 1afc4675dc75 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.tools.java; |
|
27 |
||
28 |
import 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 |
*/ |
|
55 |
public |
|
56 |
class 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[]) { |
|
24969
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
277 |
StringBuilder sb = new StringBuilder(); |
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
278 |
sb.append(SIG_METHOD); |
2 | 279 |
for (int i = 0 ; i < argTypes.length ; i++) { |
24969
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
280 |
sb.append(argTypes[i].getTypeSignature()); |
2 | 281 |
} |
24969
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
282 |
sb.append(SIG_ENDMETHOD); |
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
283 |
sb.append(returnType.getTypeSignature()); |
2 | 284 |
|
24969
afa6934dd8e8
8041679: Replace uses of StringBuffer with StringBuilder within core library classes
psandoz
parents:
5506
diff
changeset
|
285 |
String sig = sb.toString(); |
2 | 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 |
} |