1 /* 2 * Copyright (c) 1994, 2003, 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 */ 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 = 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 = 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 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 */ 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 = 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 }