View Javadoc

1   // jq_Array.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 joeq.Allocator.ObjectLayout;
7   import joeq.Main.jq;
8   import joeq.Memory.Address;
9   import joeq.Memory.HeapAddress;
10  import joeq.UTF.Utf8;
11  import jwutil.util.Assert;
12  
13  /***
14   * @author  John Whaley <jwhaley@alum.mit.edu>
15   * @version $Id: jq_Array.java 2465 2006-06-07 23:03:17Z joewhaley $
16   */
17  public class jq_Array extends jq_Reference implements jq_ClassFileConstants {
18  
19      public static /*final*/ boolean TRACE = false;
20      
21      public final boolean isClassType() { return false; }
22      public final boolean isArrayType() { return true; }
23      public final boolean isAddressType() { return false; }
24      public final String getName() {
25          return element_type.getName()+"[]";
26      }
27      public final String shortName() {
28          return element_type.shortName()+"[]";
29      }
30      public final String getJDKName() {
31          return desc.toString().replace('/','.');
32          //return "["+element_type.getJDKDesc();
33      }
34      public final String getJDKDesc() {
35          return getJDKName();
36      }
37      public final byte getLogElementSize() {
38          if (element_type == jq_Primitive.LONG ||
39              element_type == jq_Primitive.DOUBLE)
40              return 3;
41          if (element_type == jq_Primitive.CHAR ||
42              element_type == jq_Primitive.SHORT)
43              return 1;
44          if (element_type == jq_Primitive.BYTE)
45              return 0;
46          return 2;
47      }
48  
49      public final Object newInstance(int length) {
50          cls_initialize();
51          return _delegate.newInstance(this, length, vtable);
52      }
53      
54      public final int getDimensionality() {
55          if (element_type.isArrayType())
56              return 1+((jq_Array)element_type).getDimensionality();
57          else
58              return 1;
59      }
60      
61      public final boolean isFinal() { return element_type.isFinal(); }
62      
63      public static final jq_Class[] array_interfaces = new jq_Class[] {
64      (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljava/lang/Cloneable;"),
65      (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljava/io/Serializable;"),
66      };
67      public final jq_Class[] getInterfaces() {
68          return array_interfaces;
69      }
70      public final jq_Class getInterface(Utf8 desc) {
71          chkState(STATE_PREPARED);
72          for (int i=0; i<array_interfaces.length; ++i) {
73              jq_Class in = array_interfaces[i];
74              if (in.getDesc() == desc)
75                  return in;
76          }
77          return null;
78      }
79      public final boolean implementsInterface(jq_Class k) {
80          chkState(STATE_PREPARED);
81          return k == array_interfaces[0] || k == array_interfaces[1];
82      }
83      
84      public final jq_InstanceMethod getVirtualMethod(jq_NameAndDesc nd) {
85          chkState(STATE_PREPARED);
86          jq_Class jlo = PrimordialClassLoader.getJavaLangObject();
87          return jlo.getVirtualMethod(nd);
88      }
89      
90      public final jq_Type getElementType() { return element_type; }
91      
92      private jq_Array(Utf8 desc, ClassLoader class_loader, jq_Type element_type) {
93          super(desc, class_loader);
94          Assert._assert(desc.isDescriptor(TC_ARRAY));
95          Assert._assert(element_type != null);
96          this.element_type = element_type;
97      }
98      // ONLY TO BE CALLED BY ClassLoader!!!
99      public static jq_Array newArray(Utf8 descriptor, ClassLoader classLoader, jq_Type element_type) {
100         return new jq_Array(descriptor, classLoader, element_type);
101     }
102     
103     public static final jq_Array BYTE_ARRAY =
104     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_BYTE), PrimordialClassLoader.loader, jq_Primitive.BYTE);
105     public static final jq_Array CHAR_ARRAY =
106     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_CHAR), PrimordialClassLoader.loader, jq_Primitive.CHAR);
107     public static final jq_Array DOUBLE_ARRAY =
108     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_DOUBLE), PrimordialClassLoader.loader, jq_Primitive.DOUBLE);
109     public static final jq_Array FLOAT_ARRAY =
110     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_FLOAT), PrimordialClassLoader.loader, jq_Primitive.FLOAT);
111     public static final jq_Array INT_ARRAY =
112     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_INT), PrimordialClassLoader.loader, jq_Primitive.INT);
113     public static final jq_Array LONG_ARRAY =
114     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_LONG), PrimordialClassLoader.loader, jq_Primitive.LONG);
115     public static final jq_Array SHORT_ARRAY =
116     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_SHORT), PrimordialClassLoader.loader, jq_Primitive.SHORT);
117     public static final jq_Array BOOLEAN_ARRAY =
118     new jq_Array(Utf8.get(""+(char)TC_ARRAY+(char)TC_BOOLEAN), PrimordialClassLoader.loader, jq_Primitive.BOOLEAN);
119     public static final jq_Array OBJECT_ARRAY = (jq_Array) PrimordialClassLoader.loader.getOrCreateBSType("[Ljava/lang/Object;");
120     
121     public static jq_Array getPrimitiveArrayType(byte atype) {
122         switch(atype) {
123             case T_BOOLEAN:
124                 return BOOLEAN_ARRAY;
125             case T_CHAR:
126                 return CHAR_ARRAY;
127             case T_FLOAT:
128                 return FLOAT_ARRAY;
129             case T_DOUBLE:
130                 return DOUBLE_ARRAY;
131             case T_BYTE:
132                 return BYTE_ARRAY;
133             case T_SHORT:
134                 return SHORT_ARRAY;
135             case T_INT:
136                 return INT_ARRAY;
137             case T_LONG:
138                 return LONG_ARRAY;
139             default:
140                 throw new ClassFormatError();
141         }
142     }
143 
144     public static byte getTypecode(jq_Array array) {
145         if (array == BOOLEAN_ARRAY) return T_BOOLEAN;
146         if (array == CHAR_ARRAY) return T_CHAR;
147         if (array == FLOAT_ARRAY) return T_FLOAT;
148         if (array == DOUBLE_ARRAY) return T_DOUBLE;
149         if (array == BYTE_ARRAY) return T_BYTE;
150         if (array == SHORT_ARRAY) return T_SHORT;
151         if (array == INT_ARRAY) return T_INT;
152         if (array == LONG_ARRAY) return T_LONG;
153         throw new ClassFormatError();
154     }
155 
156     public final int getInstanceSize(int length) {
157         int size = ObjectLayout.ARRAY_HEADER_SIZE+(length<<getLogElementSize());
158         return (size+3) & ~3;
159     }
160     
161     public final jq_Type getInnermostElementType() {
162         if (element_type.isArrayType())
163             return ((jq_Array)element_type).getInnermostElementType();
164         else
165             return element_type;
166     }
167     
168     public final int getDepth() {
169         return 1+element_type.getDepth();
170     }
171     
172     public final jq_Reference getDirectPrimarySupertype() {
173         jq_Type innermost = getInnermostElementType();
174         if (innermost == PrimordialClassLoader.getJavaLangObject()) {
175             return (jq_Reference) element_type;
176         }
177         int dim = getDimensionality();
178         jq_Reference type;
179         if (innermost.isPrimitiveType()) {
180             type = PrimordialClassLoader.getJavaLangObject();
181             --dim;
182         } else {
183             innermost.load();
184             type = ((jq_Class) innermost).getDirectPrimarySupertype();
185         }
186         while (--dim >= 0) {
187             type = type.getArrayTypeForElementType();
188         }
189         return type;
190     }
191     
192     public static jq_Reference[] s_s_array_cache = array_interfaces;
193     
194     private static int getCacheIndexForDim(int dim) {
195         if (dim * 2 > s_s_array_cache.length) {
196             jq_Reference[] t = new jq_Reference[dim*2];
197             System.arraycopy(s_s_array_cache, 0, t, 0, s_s_array_cache.length);
198             t[dim*2-2] = t[dim*2-4].getArrayTypeForElementType();
199             t[dim*2-1] = t[dim*2-3].getArrayTypeForElementType();
200             s_s_array_cache = t;
201         }
202         return dim*2;
203     }
204     
205     public final void load() {
206         if (isLoaded()) return;
207         synchronized (this) {
208             if (TRACE) System.out.println("Loading "+this+"...");
209             state = STATE_LOADED;
210         }
211     }
212     public final void verify() {
213         if (isVerified()) return;
214         if (!isLoaded()) load();
215         synchronized (this) {
216             if (TRACE) System.out.println("Verifying "+this+"...");
217             state = STATE_VERIFIED;
218         }
219     }
220     public final void prepare() {
221         if (isPrepared()) return;
222         if (!isVerified()) verify();
223         synchronized (this) {
224             if (TRACE) System.out.println("Preparing "+this+"...");
225             state = STATE_PREPARING;
226             
227             jq_Type innermost = this.getInnermostElementType();
228             innermost.load();
229             this.display = new jq_Type[DISPLAY_SIZE+2];
230             if (!(innermost instanceof jq_Class) ||
231                 !((jq_Class) innermost).isInterface()) {
232                 jq_Reference dps = this.getDirectPrimarySupertype();
233                 dps.prepare();
234                 int num = dps.offset;
235                 if (num < 2) num = DISPLAY_SIZE+1;
236                 System.arraycopy(dps.display, 2, this.display, 2, num-1);
237                 this.offset = num + 1;
238                 if (this.offset >= DISPLAY_SIZE+2)
239                     this.offset = 0;
240                 this.display[this.offset] = this;
241                 // todo: if innermost element type implements some interfaces,
242                 // we need to add some more to s_s_array.
243             } else {
244                 jq_Reference r = PrimordialClassLoader.getJavaLangObject();
245                 this.display[2] = r;
246                 int dim = this.getDimensionality();
247                 for (int i=0; i<dim; ++i) {
248                     if (i >= DISPLAY_SIZE-1) break;
249                     r = r.getArrayTypeForElementType();
250                     this.display[i+3] = r;
251                 }
252             }
253             this.s_s_array_length = getCacheIndexForDim(this.getDimensionality());
254             // todo: when s_s_array_cache changes, previously prepared types still
255             // refer to the old copy.  this is a waste of memory.
256             this.s_s_array = s_s_array_cache;
257             if (innermost instanceof jq_Class) {
258                 jq_Class c = (jq_Class) innermost;
259                 c.prepare();
260                 jq_Class[] interfaces = c.getInterfaces();
261                 if (interfaces.length > 0) {
262                     jq_Reference[] a = new jq_Reference[this.s_s_array_length + interfaces.length];
263                     System.arraycopy(this.s_s_array, 0, a, 0, this.s_s_array_length);
264                     for (int i=0; i<interfaces.length; ++i) {
265                         jq_Reference c2 = interfaces[i];
266                         for (int j=0, n=this.getDimensionality(); j<n; ++j)
267                             c2 = c2.getArrayTypeForElementType();
268                         a[i+this.s_s_array_length] = c2;
269                     }
270                     this.s_s_array_length = a.length;
271                     this.s_s_array = a;
272                 }
273             }
274             
275             if (TRACE) {
276                 System.out.println(this+" offset="+this.offset);
277                 if (this.offset != 0) {
278                     for (int i=0; i<this.display.length; ++i) {
279                         System.out.println(this+" display["+i+"] = "+this.display[i]);
280                     }
281                 }
282                 for (int i=0; i<this.s_s_array_length; ++i) {
283                     System.out.println(this+" s_s_array["+i+"] = "+this.s_s_array[i]);
284                 }
285             }
286             
287             // vtable is a copy of Ljava/lang/Object;
288             jq_Class jlo = PrimordialClassLoader.getJavaLangObject();
289             jlo.prepare();
290             Address[] jlovtable = (Address[])jlo.getVTable();
291             vtable = new Address[jlovtable.length];
292             state = STATE_PREPARED;
293         }
294     }
295     public final void sf_initialize() {
296         if (isSFInitialized()) return;
297         if (!isPrepared()) prepare();
298         synchronized (this) {
299             if (TRACE) System.out.println("SF init "+this+"...");
300             state = STATE_SFINITIALIZED;
301         }
302     }
303     public final void compile() {
304         if (isCompiled()) return;
305         if (!isSFInitialized()) sf_initialize();
306         synchronized (this) {
307             if (TRACE) System.out.println("Compile "+this+"...");
308             state = STATE_COMPILING;
309             jq_Class jlo = PrimordialClassLoader.getJavaLangObject();
310             jlo.compile();
311             Address[] jlovtable = (Address[])jlo.getVTable();
312             Address[] vt = (Address[])this.vtable;
313             vt[0] = HeapAddress.addressOf(this);
314             System.arraycopy(jlovtable, 1, vt, 1, jlovtable.length-1);
315             if (TRACE) System.out.println(this+": "+vt[0].stringRep()+" vtable "+HeapAddress.addressOf(vt).stringRep());
316             state = STATE_COMPILED;
317         }
318     }
319     public final void cls_initialize() {
320         if (isClsInitialized()) return;
321         if (!isCompiled()) compile();
322         synchronized (this) {
323             if (TRACE) System.out.println("Class init "+this+"...");
324             state = STATE_CLSINITIALIZING;
325             jq_Class jlo = PrimordialClassLoader.getJavaLangObject();
326             jlo.cls_initialize();
327             state = STATE_CLSINITIALIZED;
328         }
329     }
330     
331     public void accept(jq_TypeVisitor tv) {
332         tv.visitArray(this);
333         super.accept(tv);
334     }
335     
336     private final jq_Type element_type;
337 
338     public static final jq_Class _class;
339     static interface Delegate {
340         Object newInstance(jq_Array a, int length, Object vtable);
341     }
342 
343     private static Delegate _delegate;
344 
345     static {
346         _class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Class/jq_Array;");
347         /* Set up delegates. */
348         _delegate = null;
349         boolean nullVM = jq.nullVM;
350         if (!nullVM) {
351             _delegate = attemptDelegate("joeq.Class.Delegates$Array");
352         }
353         if (_delegate == null) {
354             _delegate = new NullDelegates.Array();
355         }
356     }
357 
358     private static Delegate attemptDelegate(String s) {
359         //String type = "array delegate";
360         try {
361             Class c = Class.forName(s);
362             return (Delegate)c.newInstance();
363         } catch (java.lang.ClassNotFoundException x) {
364             //System.err.println("Cannot find "+type+" "+s+": "+x);
365         } catch (java.lang.InstantiationException x) {
366             //System.err.println("Cannot instantiate "+type+" "+s+": "+x);
367         } catch (java.lang.IllegalAccessException x) {
368             //System.err.println("Cannot access "+type+" "+s+": "+x);
369         }
370         return null;
371     }
372 }