View Javadoc

1   // jq_Type.java, created Mon Feb  5 23:23:20 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Class;
5   
6   import java.util.StringTokenizer;
7   import java.io.IOException;
8   import joeq.ClassLib.ClassLibInterface;
9   import joeq.Main.jq;
10  import joeq.Runtime.Debug;
11  import joeq.Runtime.Reflection;
12  import joeq.UTF.Utf8;
13  import jwutil.io.Textualizable;
14  import jwutil.io.Textualizer;
15  import jwutil.util.Assert;
16  
17  /*
18   * @author  John Whaley <jwhaley@alum.mit.edu>
19   * @version $Id: jq_Type.java 1931 2004-09-22 22:17:47Z joewhaley $
20   */
21  public abstract class jq_Type implements Textualizable {
22      
23      protected final Utf8 desc;
24      private /*final*/ Class class_object;  // pointer to our associated java.lang.Class object
25  
26      public static final boolean USE_CLASS_OBJECT_FIELD = true;
27  
28      protected jq_Type(Utf8 desc, ClassLoader class_loader) {
29          this.desc = desc;
30          initializeClassObject();
31      }
32      
33      private void initializeClassObject() {
34          if (jq.RunningNative)
35              this.class_object = ClassLibInterface.DEFAULT.createNewClass(this);
36          else if (USE_CLASS_OBJECT_FIELD)
37              this.class_object = Reflection.getJDKType(this);
38      }
39      
40      public abstract String getName();
41      public abstract String shortName();
42      public final Utf8 getDesc() { return desc; }
43      public abstract String getJDKDesc();
44      public abstract boolean isClassType();
45      public abstract boolean isArrayType();
46      public abstract boolean isPrimitiveType();
47      public abstract boolean isAddressType();
48      public abstract boolean isIntLike();
49      public final boolean isReferenceType() { return !isPrimitiveType(); }
50      public abstract ClassLoader getClassLoader();
51      public abstract int getReferenceSize();
52      public final jq_Array getArrayTypeForElementType() {
53          return (jq_Array)PrimordialClassLoader.getOrCreateType(getClassLoader(), desc.getAsArrayDescriptor());
54      }
55      public boolean needsDynamicLink(jq_Method method) { return false; }
56      public abstract boolean isInstance(Object o);
57      public abstract int getDepth();
58      public final Class getJavaLangClassObject() {
59          if (jq.RunningNative && this.class_object == null)
60              initializeClassObject();
61          return class_object;
62      }
63  
64      public static final int DISPLAY_SIZE = 8;
65      
66      /*** 
67       * The first two elements are the positive and negative cache,
68       * respectively.  The remainder are the primary supertypes of this type
69       * ordered by the tree relation.  This array should be inlined into the
70       * jq_Type object, hopefully.
71       * 
72       * See paper "Fast subtype checking in the HotSpot JVM".
73       */
74      protected jq_Type[] display;
75      
76      /*** 
77       * The offset of our type in the display array if this is a primary type, or
78       * 0 or 1 if this is a secondary type.
79       * 
80       * See paper "Fast subtype checking in the HotSpot JVM".
81       */
82      protected int offset;
83      
84      /***
85       * A reference to the secondary subtype array for this type.
86       * 
87       * See paper "Fast subtype checking in the HotSpot JVM".
88       */
89      protected jq_Reference[] s_s_array;
90      
91      /***
92       * The maximum index used in the secondary subtype array.
93       * 
94       * See paper "Fast subtype checking in the HotSpot JVM".
95       */
96      protected int s_s_array_length;
97      
98      //// useful functions for parsing class and method names
99      
100     public static String convertPrimitive(String s) {
101         if (s.equals("byte")) return "B";
102         if (s.equals("char")) return "C";
103         if (s.equals("double")) return "D";
104         if (s.equals("float")) return "F";
105         if (s.equals("int")) return "I";
106         if (s.equals("long")) return "J";
107         if (s.equals("short")) return "S";
108         if (s.equals("void")) return "V";
109         if (s.equals("boolean")) return "Z";
110         return s;
111     }
112     
113     public static jq_Type parseType(String s) {
114         s = convertPrimitive (s);
115         if (s.length() == 1) {
116             jq_Primitive t = (jq_Primitive) PrimordialClassLoader.loader.getBSType(s);
117             if (t != null) return t;
118             s = "L" + s + ";";
119         } else {
120             s = s.replace('.', '/');
121             int arrayDepth = 0;
122             while (s.endsWith("[]")) {
123                 ++arrayDepth;
124                 s = s.substring(0, s.length() - 2);
125             }
126             s = convertPrimitive (s);
127             if (s.length() == 1) {
128                 jq_Primitive t = (jq_Primitive) PrimordialClassLoader.loader.getBSType(s);
129                 if (t == null)
130                     s = "L" + s + ";";
131             } else if (!s.startsWith("[") && !s.endsWith(";"))
132                 s = "L" + s + ";";
133             while (--arrayDepth >= 0)
134                 s = "[" + s;
135         }
136         return (jq_Reference) PrimordialClassLoader.loader.getOrCreateBSType(s);
137     }
138 
139     public static final boolean TRACE = false;
140 
141     public final boolean isSubtypeOf(jq_Type that) {
142         Assert._assert(this.isPrepared());
143         Assert._assert(that.isPrepared());
144         
145         int off = that.offset;
146         if (that == this.display[off]) {
147             // matches cache or depth
148             if (TRACE) {
149                 Debug.write(this.getDesc());
150                 Debug.write(" matches ");
151                 Debug.write(that.getDesc());
152                 Debug.write(" offset=");
153                 Debug.writeln(off);
154             }
155             return off != 1;
156         }
157         if (this == jq_Reference.jq_NullType.NULL_TYPE) {
158             return that.isReferenceType();
159         }
160         if (off > 1) {
161             // other class is a primary type that isn't a superclass.
162             if (TRACE) {
163                 Debug.write(this.getDesc());
164                 Debug.write(" doesn't match ");
165                 Debug.write(that.getDesc());
166                 Debug.write(", offset ");
167                 Debug.write(off);
168                 Debug.write(" is ");
169                 if (this.display[off] == null)
170                     Debug.writeln("null");
171                 else
172                     Debug.writeln(this.display[off].getDesc());
173             }
174             return false;
175         }
176         if (this == that) {
177             // classes are exactly the same.
178             return true;
179         }
180         int n = this.s_s_array_length;
181         for (int i=0; i<n; ++i) {
182             if (this.s_s_array[i] == that) {
183                 this.display[0] = that;
184                 that.offset = 0;
185                 if (TRACE) {
186                     Debug.write(this.getDesc());
187                     Debug.write(" matches ");
188                     Debug.write(that.getDesc());
189                     Debug.writeln(" in s_s_array");
190                 }
191                 return true;
192             }
193         }
194         this.display[1] = that;
195         that.offset = 1;
196         if (TRACE) {
197             Debug.write(this.getDesc());
198             Debug.write(" doesn't match ");
199             Debug.write(that.getDesc());
200             Debug.writeln(" in s_s_array");
201         }
202         return false;
203     }
204     
205     /*
206     public boolean isBootType() {
207         return jq.boot_types.contains(this);
208     }
209     */
210 
211     public abstract boolean isLoaded();
212     public abstract boolean isVerified();
213     public abstract boolean isPrepared();
214     public abstract boolean isSFInitialized();
215     public abstract boolean isCompiled();
216     public abstract boolean isClsInitRunning();
217     public abstract boolean isClsInitialized();
218     
219     public abstract boolean isFinal();
220     
221     public abstract void load();
222     public abstract void verify();
223     public abstract void prepare();
224     public abstract void sf_initialize();
225     public abstract void compile();
226     public abstract void cls_initialize();
227 
228     public void accept(jq_TypeVisitor tv) { tv.visitType(this); }
229     
230     public String toString() { return getName(); }
231     
232     public void write(Textualizer t) throws IOException {
233         t.writeString(getDesc().toString());
234     }
235     public void writeEdges(Textualizer t) throws IOException { }
236     public void addEdge(String edgeName, Textualizable t) { }
237     public static jq_Type read(StringTokenizer st) {
238         String desc = st.nextToken();
239         if (desc.equals("null")) return null;
240         jq_Type r = PrimordialClassLoader.loader.getOrCreateBSType(desc);
241         return r;
242     }
243     public static final jq_Class _class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Class/jq_Type;");
244 }