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 }