1 /*
2  * Copyright (c) 1994, 2019, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 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.
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<String, Type> 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      */
Type(int typeCode, String typeSig)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      */
getTypeSignature()110     public final String getTypeSignature() {
111         return typeSig;
112     }
113 
114     /**
115      * Return the type code.
116      */
getTypeCode()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      */
getTypeMask()127     public final int getTypeMask() {
128         return 1 << typeCode;
129     }
130 
131     /**
132      * Check for a certain type.
133      */
isType(int tc)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      */
isVoidArray()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      */
inMask(int tm)163     public final boolean inMask(int tm) {
164         return ((1 << typeCode) & tm) != 0;
165     }
166 
167     /**
168      * Create an array type.
169      */
tArray(Type elem)170     public static synchronized Type tArray(Type elem) {
171         String sig = new String(SIG_ARRAY + elem.getTypeSignature());
172         Type t = 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      */
getElementType()183     public Type getElementType() {
184         throw new CompilerError("getElementType");
185     }
186 
187     /**
188      * Return the array dimension. Only works for
189      * array types.
190      */
getArrayDimension()191     public int getArrayDimension() {
192         return 0;
193     }
194 
195     /**
196      * Create a class type.
197      * @arg className the fully qualified class name
198      */
tClass(Identifier className)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 = 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      */
getClassName()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 
mangleInnerType(Identifier className)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      */
changeClassName(Identifier oldName, Identifier newName)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      */
tMethod(Type ret)269     public static synchronized Type tMethod(Type ret) {
270         return tMethod(ret, noArgs);
271     }
272 
273     /**
274      * Create a method type with arguments.
275      */
tMethod(Type returnType, Type argTypes[])276     public static synchronized Type tMethod(Type returnType, Type argTypes[]) {
277         StringBuilder sb = new StringBuilder();
278         sb.append(SIG_METHOD);
279         for (int i = 0 ; i < argTypes.length ; i++) {
280             sb.append(argTypes[i].getTypeSignature());
281         }
282         sb.append(SIG_ENDMETHOD);
283         sb.append(returnType.getTypeSignature());
284 
285         String sig = sb.toString();
286         Type t = 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      */
getReturnType()296     public Type getReturnType() {
297         throw new CompilerError("getReturnType");
298     }
299 
300     /**
301      * Return the argument types. Only works for method types.
302      */
getArgumentTypes()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      */
tType(String sig)311     public static synchronized Type tType(String sig) {
312         Type t = 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      */
equalArguments(Type t)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      */
stackSize()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      */
getTypeCodeOffset()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      */
typeString(String id, boolean abbrev, boolean ret)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      */
typeString(String id)445     public String typeString(String id) {
446         return typeString(id, false, true);
447     }
448 
449     /**
450      * Convert to a String
451      */
toString()452     public String toString() {
453         return typeString("", false, true);
454     }
455 }
456