/*
 * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.tools.java;

import java.util.Hashtable;

This class represents an Java Type.

It encapsulates an Java type signature and it provides quick access to the components of the type. Note that all types are hashed into a hashtable (typeHash), that means that each distinct type is only allocated once, saving space and making equality checks cheap.

For simple types use the constants defined in this class. (Type.tInt, Type.tShort, ...). To create complex types use the static methods Type.tArray, Type.tMethod or Type.tClass. For classes, arrays and method types a sub class of class type is created which defines the extra type components. WARNING: The contents of this source file are not part of any supported API. Code that depends on them does so at its own risk: they are subject to change or removal without notice.

Author: Arthur van Hoff
See Also:
/** * This class represents an Java Type.<p> * * It encapsulates an Java type signature and it provides * quick access to the components of the type. Note that * all types are hashed into a hashtable (typeHash), that * means that each distinct type is only allocated once, * saving space and making equality checks cheap.<p> * * For simple types use the constants defined in this class. * (Type.tInt, Type.tShort, ...). To create complex types use * the static methods Type.tArray, Type.tMethod or Type.tClass. * * For classes, arrays and method types a sub class of class * type is created which defines the extra type components. * * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. * * @see ArrayType * @see ClassType * @see MethodType * @author Arthur van Hoff */
public class Type implements Constants {
This hashtable is used to cache types
/** * This hashtable is used to cache types */
private static final Hashtable typeHash = new Hashtable(231);
The TypeCode of this type. The value of this field is one of the TC_* contant values defined in Constants.
See Also:
  • Constants
/** * The TypeCode of this type. The value of this field is one * of the TC_* contant values defined in Constants. * @see Constants */
protected int typeCode;
The TypeSignature of this type. This type signature is equivalent to the runtime type signatures used by the interpreter.
/** * The TypeSignature of this type. This type signature is * equivalent to the runtime type signatures used by the * interpreter. */
protected String typeSig; /* * Predefined types. */ public static final Type noArgs[] = new Type[0]; public static final Type tError = new Type(TC_ERROR, "?"); public static final Type tPackage = new Type(TC_ERROR, "."); public static final Type tNull = new Type(TC_NULL, "*"); public static final Type tVoid = new Type(TC_VOID, SIG_VOID); public static final Type tBoolean = new Type(TC_BOOLEAN, SIG_BOOLEAN); public static final Type tByte = new Type(TC_BYTE, SIG_BYTE); public static final Type tChar = new Type(TC_CHAR, SIG_CHAR); public static final Type tShort = new Type(TC_SHORT, SIG_SHORT); public static final Type tInt = new Type(TC_INT, SIG_INT); public static final Type tFloat = new Type(TC_FLOAT, SIG_FLOAT); public static final Type tLong = new Type(TC_LONG, SIG_LONG); public static final Type tDouble = new Type(TC_DOUBLE, SIG_DOUBLE); public static final Type tObject = Type.tClass(idJavaLangObject); public static final Type tClassDesc = Type.tClass(idJavaLangClass); public static final Type tString = Type.tClass(idJavaLangString); public static final Type tCloneable = Type.tClass(idJavaLangCloneable); public static final Type tSerializable = Type.tClass(idJavaIoSerializable);
Create a type given a typecode and a type signature.
/** * Create a type given a typecode and a type signature. */
protected Type(int typeCode, String typeSig) { this.typeCode = typeCode; this.typeSig = typeSig; typeHash.put(typeSig, this); }
Return the Java type signature.
/** * Return the Java type signature. */
public final String getTypeSignature() { return typeSig; }
Return the type code.
/** * Return the type code. */
public final int getTypeCode() { return typeCode; }
Return the type mask. The bits in this mask correspond to the TM_* constants defined in Constants. Only one bit is set at a type.
See Also:
  • Constants
/** * Return the type mask. The bits in this mask correspond * to the TM_* constants defined in Constants. Only one bit * is set at a type. * @see Constants */
public final int getTypeMask() { return 1 << typeCode; }
Check for a certain type.
/** * Check for a certain type. */
public final boolean isType(int tc) { return typeCode == tc; }
Check to see if this is the bogus type "array of void" Although this highly degenerate "type" is not constructable from the grammar, the Parser accepts it. Rather than monkey with the Parser, we check for the bogus type at specific points and give a nice error.
/** * Check to see if this is the bogus type "array of void" * * Although this highly degenerate "type" is not constructable from * the grammar, the Parser accepts it. Rather than monkey with the * Parser, we check for the bogus type at specific points and give * a nice error. */
public boolean isVoidArray() { // a void type is not a void array. if (!isType(TC_ARRAY)) { return false; } // If this is an array, find out what its element type is. Type type = this; while (type.isType(TC_ARRAY)) type = type.getElementType(); return type.isType(TC_VOID); }
Check for a certain set of types.
/** * Check for a certain set of types. */
public final boolean inMask(int tm) { return ((1 << typeCode) & tm) != 0; }
Create an array type.
/** * Create an array type. */
public static synchronized Type tArray(Type elem) { String sig = new String(SIG_ARRAY + elem.getTypeSignature()); Type t = (Type)typeHash.get(sig); if (t == null) { t = new ArrayType(sig, elem); } return t; }
Return the element type of an array type. Only works for array types.
/** * Return the element type of an array type. Only works * for array types. */
public Type getElementType() { throw new CompilerError("getElementType"); }
Return the array dimension. Only works for array types.
/** * Return the array dimension. Only works for * array types. */
public int getArrayDimension() { return 0; }
Create a class type.
@argclassName the fully qualified class name
/** * Create a class type. * @arg className the fully qualified class name */
public static synchronized Type tClass(Identifier className) { if (className.isInner()) { Type t = tClass(mangleInnerType(className)); if (t.getClassName() != className) // Somebody got here first with a mangled name. // (Perhaps it came from a binary.) changeClassName(t.getClassName(), className); return t; } // see if we've cached the object in the Identifier if (className.typeObject != null) { return className.typeObject; } String sig = new String(SIG_CLASS + className.toString().replace('.', SIGC_PACKAGE) + SIG_ENDCLASS); Type t = (Type)typeHash.get(sig); if (t == null) { t = new ClassType(sig, className); } className.typeObject = t; // cache the Type object in the Identifier return t; }
Return the ClassName. Only works on class types.
/** * Return the ClassName. Only works on class types. */
public Identifier getClassName() { throw new CompilerError("getClassName:" + this); }
Given an inner identifier, return the non-inner, mangled representation used to manage signatures. Note: It is changed to 'public' for Jcov file generation. (see Assembler.java)
/** * Given an inner identifier, return the non-inner, mangled * representation used to manage signatures. * * Note: It is changed to 'public' for Jcov file generation. * (see Assembler.java) */
public static Identifier mangleInnerType(Identifier className) { // Map "pkg.Foo. Bar" to "pkg.Foo$Bar". if (!className.isInner()) return className; Identifier mname = Identifier.lookup( className.getFlatName().toString(). replace('.', SIGC_INNERCLASS) ); if (mname.isInner()) throw new CompilerError("mangle "+mname); return Identifier.lookup(className.getQualifier(), mname); }
We have learned that a signature means something other that what we thought it meant. Live with it: Change all affected data structures to reflect the new name of the old type.

(This is necessary because of an ambiguity between the low-level signatures of inner types and their manglings. Note that the latter are also valid class names.)

/** * We have learned that a signature means something other * that what we thought it meant. Live with it: Change all * affected data structures to reflect the new name of the old type. * <p> * (This is necessary because of an ambiguity between the * low-level signatures of inner types and their manglings. * Note that the latter are also valid class names.) */
static void changeClassName(Identifier oldName, Identifier newName) { // Note: If we are upgrading "pkg.Foo$Bar" to "pkg.Foo. Bar", // we assume someone else will come along and deal with any types // inner within Bar. So, there's only one change to make. ((ClassType)Type.tClass(oldName)).className = newName; }
Create a method type with no arguments.
/** * Create a method type with no arguments. */
public static synchronized Type tMethod(Type ret) { return tMethod(ret, noArgs); }
Create a method type with arguments.
/** * Create a method type with arguments. */
public static synchronized Type tMethod(Type returnType, Type argTypes[]) { StringBuffer buf = new StringBuffer(); buf.append(SIG_METHOD); for (int i = 0 ; i < argTypes.length ; i++) { buf.append(argTypes[i].getTypeSignature()); } buf.append(SIG_ENDMETHOD); buf.append(returnType.getTypeSignature()); String sig = buf.toString(); Type t = (Type)typeHash.get(sig); if (t == null) { t = new MethodType(sig, returnType, argTypes); } return t; }
Return the return type. Only works for method types.
/** * Return the return type. Only works for method types. */
public Type getReturnType() { throw new CompilerError("getReturnType"); }
Return the argument types. Only works for method types.
/** * Return the argument types. Only works for method types. */
public Type getArgumentTypes()[] { throw new CompilerError("getArgumentTypes"); }
Create a Type from an Java type signature.
Throws:
  • CompilerError – invalid type signature.
/** * Create a Type from an Java type signature. * @exception CompilerError invalid type signature. */
public static synchronized Type tType(String sig) { Type t = (Type)typeHash.get(sig); if (t != null) { return t; } switch (sig.charAt(0)) { case SIGC_ARRAY: return Type.tArray(tType(sig.substring(1))); case SIGC_CLASS: return Type.tClass(Identifier.lookup(sig.substring(1, sig.length() - 1).replace(SIGC_PACKAGE, '.'))); case SIGC_METHOD: { Type argv[] = new Type[8]; int argc = 0; int i, j; for (i = 1 ; sig.charAt(i) != SIGC_ENDMETHOD ; i = j) { for (j = i ; sig.charAt(j) == SIGC_ARRAY ; j++); if (sig.charAt(j++) == SIGC_CLASS) { while (sig.charAt(j++) != SIGC_ENDCLASS); } if (argc == argv.length) { Type newargv[] = new Type[argc * 2]; System.arraycopy(argv, 0, newargv, 0, argc); argv = newargv; } argv[argc++] = tType(sig.substring(i, j)); } Type argtypes[] = new Type[argc]; System.arraycopy(argv, 0, argtypes, 0, argc); return Type.tMethod(tType(sig.substring(i + 1)), argtypes); } } throw new CompilerError("invalid TypeSignature:" + sig); }
Check if the type arguments are the same.
Returns:true if both types are method types and the argument types are identical.
/** * Check if the type arguments are the same. * @return true if both types are method types and the * argument types are identical. */
public boolean equalArguments(Type t) { return false; }
Return the amount of space this type takes up on the Java operand stack. For a method this is equal to the total space taken up by the arguments.
/** * Return the amount of space this type takes up on the * Java operand stack. For a method this is equal to the * total space taken up by the arguments. */
public int stackSize() { switch (typeCode) { case TC_ERROR: case TC_VOID: return 0; case TC_BOOLEAN: case TC_BYTE: case TC_SHORT: case TC_CHAR: case TC_INT: case TC_FLOAT: case TC_ARRAY: case TC_CLASS: return 1; case TC_LONG: case TC_DOUBLE: return 2; } throw new CompilerError("stackSize " + toString()); }
Return the type code offset. This offset can be added to an opcode to get the right opcode type. Most opcodes are ordered: int, long, float, double, array. For example: iload, lload fload, dload, aload. So the appropriate opcode is iadd + type.getTypeCodeOffset().
/** * Return the type code offset. This offset can be added to * an opcode to get the right opcode type. Most opcodes * are ordered: int, long, float, double, array. For * example: iload, lload fload, dload, aload. So the * appropriate opcode is iadd + type.getTypeCodeOffset(). */
public int getTypeCodeOffset() { switch (typeCode) { case TC_BOOLEAN: case TC_BYTE: case TC_SHORT: case TC_CHAR: case TC_INT: return 0; case TC_LONG: return 1; case TC_FLOAT: return 2; case TC_DOUBLE: return 3; case TC_NULL: case TC_ARRAY: case TC_CLASS: return 4; } throw new CompilerError("invalid typecode: " + typeCode); }
Convert a Type to a string, if abbrev is true class names are not fully qualified, if ret is true the return type is included.
/** * Convert a Type to a string, if abbrev is true class names are * not fully qualified, if ret is true the return type is included. */
public String typeString(String id, boolean abbrev, boolean ret) { String s = null; switch (typeCode) { case TC_NULL: s = "null"; break; case TC_VOID: s = "void"; break; case TC_BOOLEAN: s = "boolean"; break; case TC_BYTE: s = "byte"; break; case TC_CHAR: s = "char"; break; case TC_SHORT: s = "short"; break; case TC_INT: s = "int"; break; case TC_LONG: s = "long"; break; case TC_FLOAT: s = "float"; break; case TC_DOUBLE: s = "double"; break; case TC_ERROR: s = "<error>"; if (this==tPackage) s = "<package>"; break; default: s = "unknown"; } return (id.length() > 0) ? s + " " + id : s; }
Create a type string, given an identifier.
/** * Create a type string, given an identifier. */
public String typeString(String id) { return typeString(id, false, true); }
Convert to a String
/** * Convert to a String */
public String toString() { return typeString("", false, true); } }