001: // Copyright (c) 1997, 2000 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: /**
007: * Semi-abstract class object reference types.
008: * <p>
009: * Extended by ClassType and ArrayType. */
010:
011: public class ObjectType extends Type {
012: protected ObjectType() {
013: size = 4;
014: }
015:
016: ObjectType(String name) {
017: this _name = name;
018: size = 4;
019: }
020:
021: // Miscellaneous bits:
022: final static int ADD_FIELDS_DONE = 1;
023: final static int ADD_METHODS_DONE = 2;
024: // A ClassType that we can expect to have a corresponding reflectClass.
025: final static int EXISTING_CLASS = 4;
026: int flags;
027:
028: /**
029: * Asserts wether we expect this class to already exist.
030: *
031: * @param existing true iff there must be a corresponding bytecode class.
032: * false otherwise.
033: */
034: public final void setExisting(boolean existing) {
035: if (existing)
036: flags |= EXISTING_CLASS;
037: else
038: flags &= ~EXISTING_CLASS;
039: }
040:
041: /** Returns class name if a class type, signature if an array type.
042: * In both cases, uses '/' rather than '.' after packages prefixes.
043: * Seems rather arbitrary - but that is how classes are represented
044: * in the constant pool (CONSTANT_Class constants).
045: * Also, Class.forName is the same, except using '.'.
046: */
047: public String getInternalName() {
048: return getName().replace('.', '/');
049: }
050:
051: /** Get the java.lang.Class object for the representation type. */
052: public Class getReflectClass() {
053: if (reflectClass == null && (flags & EXISTING_CLASS) != 0)
054: reflectClass = nice.tools.code.TypeImport
055: .lookupQualifiedJavaClass(getInternalName()
056: .replace('/', '.'));
057:
058: if (reflectClass == null && (flags & EXISTING_CLASS) != 0)
059: throw new NoClassDefFoundError(getName());
060:
061: return reflectClass;
062: }
063:
064: public Type getImplementationType() {
065: return this == nullType ? pointer_type
066: : this == tostring_type ? string_type : this ;
067: }
068:
069: public Type promote() {
070: return this == nullType ? pointer_type : this ;
071: }
072:
073: public int compare(Type other) {
074: // Assume this == nullType.
075: return other == nullType ? 0 : -1;
076: }
077:
078: public boolean isAssignableTo(Type other) {
079: // Assume this == nullType.
080: return other instanceof ObjectType;
081: }
082:
083: /** Convert an object to a value of this Type.
084: * Throw a ClassCastException when this is not possible. */
085: public Object coerceFromObject(Object obj) {
086: if (obj != null) {
087: if (this == Type.tostring_type)
088: return obj.toString();
089: Class clas = getReflectClass();
090: Class objClass = obj.getClass();
091: if (!clas.isAssignableFrom(objClass))
092: throw new ClassCastException(
093: "don't know how to coerce "
094: + objClass.getName() + " to "
095: + getName());
096: }
097: return obj;
098: }
099:
100: /** Compile (in given method) cast from Object to this Type. */
101: public void emitCoerceFromObject(CodeAttr code) {
102: if (this == Type.tostring_type) {
103: // This would be nice but it doesn't verify, alas!
104: // code.reserve(4);
105: // code.emitDup();
106: // code.put1(198); // ifnull
107: // code.put2(6); // skip after emitInvokeVirtual.
108: // code.emitInvokeVirtual(Type.toString_method);
109: code.emitDup();
110: code.emitIfNull();
111: code.emitPop(1);
112: code.emitPushNull();
113: code.emitElse();
114: code.emitInvokeVirtual(Type.toString_method);
115: code.emitFi();
116: } else if (this != Type.pointer_type)
117: code.emitCheckcast(this);
118: }
119: }
|