1
2
3
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
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
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
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
242
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
255
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
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
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
360 try {
361 Class c = Class.forName(s);
362 return (Delegate)c.newInstance();
363 } catch (java.lang.ClassNotFoundException x) {
364
365 } catch (java.lang.InstantiationException x) {
366
367 } catch (java.lang.IllegalAccessException x) {
368
369 }
370 return null;
371 }
372 }