001: // Copyright (c) 1997, 2000, 2007 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: import java.util.Vector;
007:
008: /**
009: * Semi-abstract class object reference types.
010: * <p>
011: * Extended by ClassType and ArrayType. */
012:
013: public class ObjectType extends Type {
014: protected ObjectType() {
015: size = 4;
016: }
017:
018: public ObjectType(String name) {
019: this _name = name;
020: size = 4;
021: }
022:
023: // Miscellaneous bits:
024: final static int ADD_FIELDS_DONE = 1;
025: final static int ADD_METHODS_DONE = 2;
026: // A ClassType that we can expect to have a corresponding reflectClass.
027: final static int EXISTING_CLASS = 4;
028:
029: final static int HAS_OUTER_LINK = 8;
030:
031: /* */public int flags;
032:
033: public final boolean isExisting() {
034: return (flags & EXISTING_CLASS) != 0;
035: }
036:
037: public final void setExisting(boolean existing) {
038: if (existing)
039: flags |= EXISTING_CLASS;
040: else
041: flags &= ~EXISTING_CLASS;
042: }
043:
044: /** Returns class name if a class type, signature if an array type.
045: * In both cases, uses '/' rather than '.' after packages prefixes.
046: * Seems rather arbitrary - but that is how classes are represented
047: * in the constant pool (CONSTANT_Class constants).
048: * Also, Class.forName is the same, except using '.'.
049: */
050: public String getInternalName() {
051: return getName().replace('.', '/');
052: }
053:
054: /* #ifdef JAVA2 */
055: /* #ifndef JAVA5 */
056: static ClassLoader this ClassLoader;
057: static {
058: try {
059: this ClassLoader = Class.forName("gnu.mapping.ObjectType")
060: .getClassLoader();
061: } catch (Throwable ex) {
062: }
063: }
064:
065: /* #endif */
066: /* #endif */
067:
068: /** Get named class using context class loader.
069: * If the security policy prohibits that, fall back to this class's loader.
070: */
071: public static Class getContextClass(String cname)
072: throws java.lang.ClassNotFoundException {
073: /* #ifdef JAVA2 */
074: ClassLoader loader;
075: try {
076: loader = Thread.currentThread().getContextClassLoader();
077: } catch (java.lang.SecurityException ex) {
078: /* The .class syntax below also works for JDK 1.4, but it's just
079: syntactic sugar, so no benefit it using it. */
080: /* #ifdef JAVA5 */
081: // loader = ObjectType.class.getClassLoader();
082: /* #else */
083: loader = this ClassLoader;
084: /* #endif */
085: }
086: /* Specifies optional 'initialize' argument. */
087: return Class.forName(cname, false, loader);
088: /* #else */
089: // return Class.forName(cname);
090: /* #endif */
091: }
092:
093: /** Get the java.lang.Class object for the representation type. */
094: public Class getReflectClass() {
095: try {
096: if (reflectClass == null)
097: reflectClass = getContextClass(getInternalName()
098: .replace('/', '.'));
099: flags |= EXISTING_CLASS;
100: } catch (java.lang.ClassNotFoundException ex) {
101: if ((flags & EXISTING_CLASS) != 0) {
102: RuntimeException rex = new RuntimeException(
103: "no such class: " + getName());
104: /* #ifdef use:java.lang.Throwable.getCause */
105: rex.initCause(ex);
106: /* #endif */
107: throw rex;
108: }
109: }
110: return reflectClass;
111: }
112:
113: public Type getImplementationType() {
114: return this == nullType ? pointer_type
115: : this == tostring_type ? string_type : this ;
116: }
117:
118: public Type promote() {
119: return this == nullType ? pointer_type : this ;
120: }
121:
122: public boolean isInstance(Object obj) {
123: if (this == nullType)
124: return obj == null;
125: return super .isInstance(obj);
126: }
127:
128: public int getMethods(Filter filter, int searchSupers,
129: Vector result, String context) {
130: return 0;
131: }
132:
133: public int compare(Type other) {
134: // Assume this == nullType.
135: return other == nullType ? 0 : -1;
136: }
137:
138: /* #ifdef JAVA5 */
139: // @SuppressWarnings("unchecked")
140: /* #endif */
141: /** Convert an object to a value of this Type.
142: * Throw a ClassCastException when this is not possible. */
143: public Object coerceFromObject(Object obj) {
144: if (obj != null) {
145: if (this == Type.tostring_type)
146: return obj.toString();
147: Class clas = getReflectClass();
148: Class objClass = obj.getClass();
149: if (!clas.isAssignableFrom(objClass))
150: throw new ClassCastException(
151: "don't know how to coerce "
152: + objClass.getName() + " to "
153: + getName());
154: }
155: return obj;
156: }
157:
158: /** Compile (in given method) cast from Object to this Type. */
159: public void emitCoerceFromObject(CodeAttr code) {
160: if (this == Type.tostring_type) {
161: // This would be nice but it doesn't verify, alas!
162: // code.reserve(4);
163: // code.emitDup();
164: // code.put1(198); // ifnull
165: // code.put2(6); // skip after emitInvokeVirtual.
166: // code.emitInvokeVirtual(Type.toString_method);
167: code.emitDup();
168: code.emitIfNull();
169: code.emitPop(1);
170: code.emitPushNull();
171: code.emitElse();
172: code.emitInvokeVirtual(Type.toString_method);
173: code.emitFi();
174: } else if (this != Type.pointer_type)
175: code.emitCheckcast(this);
176: }
177: }
|