]>
Commit | Line | Data |
---|---|---|
9a6624c4 | 1 | // natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. |
2 | ||
14772560 | 3 | /* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation |
9a6624c4 | 4 | |
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | /* Author: Kresten Krab Thorup <krab@gnu.org> */ | |
12 | ||
13 | #include <config.h> | |
14 | ||
15 | #include <stdlib.h> | |
720677cc | 16 | #include <stdio.h> |
9a6624c4 | 17 | #include <string.h> |
18 | ||
5e25b6c0 | 19 | #include <gcj/cni.h> |
9a6624c4 | 20 | #include <jvm.h> |
5e25b6c0 | 21 | |
22 | #include <java-threads.h> | |
23 | #include <java-interp.h> | |
24 | ||
9a6624c4 | 25 | #include <java/lang/Character.h> |
26 | #include <java/lang/Thread.h> | |
27 | #include <java/lang/ClassLoader.h> | |
009022b2 | 28 | #include <gnu/gcj/runtime/VMClassLoader.h> |
9a6624c4 | 29 | #include <java/lang/InternalError.h> |
009022b2 | 30 | #include <java/lang/IllegalAccessError.h> |
9a6624c4 | 31 | #include <java/lang/LinkageError.h> |
9a6624c4 | 32 | #include <java/lang/NoClassDefFoundError.h> |
33 | #include <java/lang/ClassNotFoundException.h> | |
34 | #include <java/lang/ClassCircularityError.h> | |
35 | #include <java/lang/IncompatibleClassChangeError.h> | |
681862de | 36 | #include <java/lang/VirtualMachineError.h> |
eabac05b | 37 | #include <java/lang/VMClassLoader.h> |
9a6624c4 | 38 | #include <java/lang/reflect/Modifier.h> |
b345481f | 39 | #include <java/lang/Runtime.h> |
312e7efe | 40 | #include <java/lang/StringBuffer.h> |
5d9a696e | 41 | #include <java/io/Serializable.h> |
42 | #include <java/lang/Cloneable.h> | |
43 | ||
9a6624c4 | 44 | void |
45 | _Jv_WaitForState (jclass klass, int state) | |
46 | { | |
47 | if (klass->state >= state) | |
48 | return; | |
49 | ||
50 | _Jv_MonitorEnter (klass) ; | |
51 | ||
d3dcef52 | 52 | if (klass->state == JV_STATE_COMPILED) |
53 | { | |
54 | klass->state = JV_STATE_LOADED; | |
55 | if (gcj::verbose_class_flag) | |
307719b9 | 56 | fprintf (stderr, "[Loaded (pre-compiled) %s]\n", klass->name->chars()); |
d3dcef52 | 57 | } |
9a6624c4 | 58 | if (state == JV_STATE_LINKED) |
59 | { | |
2b23cbcd | 60 | // Must call _Jv_PrepareCompiledClass while holding the class |
61 | // mutex. | |
2c8f9104 | 62 | #ifdef INTERPRETER |
63 | if (_Jv_IsInterpretedClass (klass)) | |
64 | _Jv_PrepareClass (klass); | |
65 | #endif | |
009022b2 | 66 | _Jv_PrepareCompiledClass (klass); |
2b23cbcd | 67 | _Jv_MonitorExit (klass); |
9a6624c4 | 68 | return; |
69 | } | |
70 | ||
71 | java::lang::Thread *self = java::lang::Thread::currentThread(); | |
72 | ||
73 | // this is similar to the strategy for class initialization. | |
74 | // if we already hold the lock, just leave. | |
75 | while (klass->state <= state | |
76 | && klass->thread | |
77 | && klass->thread != self) | |
78 | klass->wait (); | |
79 | ||
80 | _Jv_MonitorExit (klass); | |
81 | ||
82 | if (klass->state == JV_STATE_ERROR) | |
3139614a | 83 | throw new java::lang::LinkageError; |
9a6624c4 | 84 | } |
85 | ||
c1dccbcc | 86 | typedef unsigned int uaddr __attribute__ ((mode (pointer))); |
87 | ||
009022b2 | 88 | /** This function does class-preparation for compiled classes. |
89bd65ff | 89 | NOTE: It contains replicated functionality from |
009022b2 | 90 | _Jv_ResolvePoolEntry, and this is intentional, since that function |
89bd65ff | 91 | lives in resolve.cc which is entirely conditionally compiled. |
009022b2 | 92 | */ |
9a6624c4 | 93 | void |
29355b48 | 94 | _Jv_PrepareCompiledClass (jclass klass) |
9a6624c4 | 95 | { |
d3dcef52 | 96 | jint state = klass->state; |
97 | if (state >= JV_STATE_LINKED) | |
9a6624c4 | 98 | return; |
99 | ||
2b23cbcd | 100 | // Short-circuit, so that mutually dependent classes are ok. |
9a6624c4 | 101 | klass->state = JV_STATE_LINKED; |
102 | ||
103 | _Jv_Constants *pool = &klass->constants; | |
c1dccbcc | 104 | |
105 | // Resolve class constants first, since other constant pool | |
106 | // entries may rely on these. | |
009022b2 | 107 | for (int index = 1; index < pool->size; ++index) |
9a6624c4 | 108 | { |
009022b2 | 109 | if (pool->tags[index] == JV_CONSTANT_Class) |
110 | { | |
111 | _Jv_Utf8Const *name = pool->data[index].utf8; | |
112 | ||
113 | jclass found; | |
307719b9 | 114 | if (name->first() == '[') |
115 | found = _Jv_FindClassFromSignature (name->chars(), | |
009022b2 | 116 | klass->loader); |
117 | else | |
118 | found = _Jv_FindClass (name, klass->loader); | |
119 | ||
120 | if (! found) | |
121 | { | |
307719b9 | 122 | jstring str = name->toString(); |
31c89803 | 123 | throw new java::lang::NoClassDefFoundError (str); |
009022b2 | 124 | } |
125 | ||
89bd65ff | 126 | pool->data[index].clazz = found; |
127 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; | |
009022b2 | 128 | } |
c1dccbcc | 129 | } |
130 | ||
131 | // If superclass looks like a constant pool entry, | |
132 | // resolve it now. | |
133 | if ((uaddr) klass->superclass < pool->size) | |
5c725c80 | 134 | klass->superclass = pool->data[(uaddr) klass->superclass].clazz; |
c1dccbcc | 135 | |
136 | // Likewise for interfaces. | |
137 | for (int i = 0; i < klass->interface_count; i++) | |
138 | if ((uaddr) klass->interfaces[i] < pool->size) | |
5c725c80 | 139 | klass->interfaces[i] = pool->data[(uaddr) klass->interfaces[i]].clazz; |
c1dccbcc | 140 | |
141 | // Resolve the remaining constant pool entries. | |
142 | for (int index = 1; index < pool->size; ++index) | |
143 | { | |
144 | if (pool->tags[index] == JV_CONSTANT_String) | |
9a6624c4 | 145 | { |
146 | jstring str; | |
b1e50a25 | 147 | |
009022b2 | 148 | str = _Jv_NewStringUtf8Const (pool->data[index].utf8); |
149 | pool->data[index].o = str; | |
150 | pool->tags[index] |= JV_CONSTANT_ResolvedFlag; | |
9a6624c4 | 151 | } |
152 | } | |
153 | ||
29355b48 | 154 | #ifdef INTERPRETER |
155 | // FIXME: although the comment up top says that this function is | |
156 | // only called for compiled classes, it is actually called for every | |
157 | // class. | |
158 | if (! _Jv_IsInterpretedClass (klass)) | |
2b473af4 | 159 | { |
29355b48 | 160 | #endif /* INTERPRETER */ |
161 | jfieldID f = JvGetFirstStaticField (klass); | |
162 | for (int n = JvNumStaticFields (klass); n > 0; --n) | |
2b473af4 | 163 | { |
29355b48 | 164 | int mod = f->getModifiers (); |
cd33b73a | 165 | // If we have a static String field with a non-null initial |
166 | // value, we know it points to a Utf8Const. | |
5c813017 | 167 | _Jv_ResolveField(f, klass->loader); |
04722d4b | 168 | if (f->getClass () == &java::lang::String::class$ |
cd33b73a | 169 | && java::lang::reflect::Modifier::isStatic (mod)) |
29355b48 | 170 | { |
171 | jstring *strp = (jstring *) f->u.addr; | |
172 | if (*strp) | |
173 | *strp = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) *strp); | |
174 | } | |
175 | f = f->getNextField (); | |
2b473af4 | 176 | } |
29355b48 | 177 | #ifdef INTERPRETER |
2b473af4 | 178 | } |
29355b48 | 179 | #endif /* INTERPRETER */ |
2b473af4 | 180 | |
e7ae25ac | 181 | if (klass->isInterface ()) |
182 | _Jv_LayoutInterfaceMethods (klass); | |
183 | ||
d3dcef52 | 184 | if (state == JV_STATE_COMPILED && gcj::verbose_class_flag) |
185 | fprintf (stderr, "[Loaded (pre-compiled) %s]\n", | |
307719b9 | 186 | klass->name->chars()); |
d3dcef52 | 187 | |
9a6624c4 | 188 | klass->notifyAll (); |
56797587 | 189 | |
190 | _Jv_PushClass (klass); | |
9a6624c4 | 191 | } |
192 | ||
193 | ||
194 | // | |
195 | // A single class can have many "initiating" class loaders, | |
196 | // and a single "defining" class loader. The Defining | |
197 | // class loader is what is returned from Class.getClassLoader() | |
198 | // and is used when loading dependent classes during resolution. | |
199 | // The set of initiating class loaders are used to ensure | |
200 | // safety of linking, and is maintained in the hash table | |
201 | // "initiated_classes". A defining classloader is by definition also | |
9897d47f | 202 | // initiating, so we only store classes in this table if they have more |
9a6624c4 | 203 | // than one class loader associated. |
204 | // | |
205 | ||
206 | ||
207 | // Size of local hash table. | |
208 | #define HASH_LEN 1013 | |
209 | ||
210 | // Hash function for Utf8Consts. | |
307719b9 | 211 | #define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN) |
9a6624c4 | 212 | |
5b95f2fb | 213 | struct _Jv_LoaderInfo |
214 | { | |
215 | _Jv_LoaderInfo *next; | |
216 | java::lang::Class *klass; | |
217 | java::lang::ClassLoader *loader; | |
9a6624c4 | 218 | }; |
219 | ||
2e1ddfaa | 220 | static _Jv_LoaderInfo *initiated_classes[HASH_LEN]; |
221 | static jclass loaded_classes[HASH_LEN]; | |
222 | ||
223 | // This is the root of a linked list of classes | |
224 | ||
225 | \f | |
9a6624c4 | 226 | |
227 | jclass | |
228 | _Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) | |
229 | { | |
5b95f2fb | 230 | JvSynchronize sync (&java::lang::Class::class$); |
9a6624c4 | 231 | jint hash = HASH_UTF (name); |
232 | ||
5b95f2fb | 233 | if (loader && loader == java::lang::ClassLoader::getSystemClassLoader()) |
234 | loader = NULL; | |
235 | ||
9a6624c4 | 236 | // first, if LOADER is a defining loader, then it is also initiating |
237 | jclass klass; | |
238 | for (klass = loaded_classes[hash]; klass; klass = klass->next) | |
239 | { | |
240 | if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name)) | |
241 | break; | |
242 | } | |
243 | ||
244 | // otherwise, it may be that the class in question was defined | |
245 | // by some other loader, but that the loading was initiated by | |
246 | // the loader in question. | |
247 | if (!klass) | |
248 | { | |
249 | _Jv_LoaderInfo *info; | |
250 | for (info = initiated_classes[hash]; info; info = info->next) | |
251 | { | |
252 | if (loader == info->loader | |
253 | && _Jv_equalUtf8Consts (name, info->klass->name)) | |
254 | { | |
255 | klass = info->klass; | |
256 | break; | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
9a6624c4 | 261 | return klass; |
262 | } | |
263 | ||
264 | void | |
265 | _Jv_UnregisterClass (jclass the_class) | |
266 | { | |
5b95f2fb | 267 | JvSynchronize sync (&java::lang::Class::class$); |
9a6624c4 | 268 | jint hash = HASH_UTF(the_class->name); |
269 | ||
270 | jclass *klass = &(loaded_classes[hash]); | |
271 | for ( ; *klass; klass = &((*klass)->next)) | |
272 | { | |
273 | if (*klass == the_class) | |
274 | { | |
275 | *klass = (*klass)->next; | |
276 | break; | |
277 | } | |
278 | } | |
279 | ||
280 | _Jv_LoaderInfo **info = &(initiated_classes[hash]); | |
a13dc0d1 | 281 | for ( ; ; info = &((*info)->next)) |
9a6624c4 | 282 | { |
a13dc0d1 | 283 | while (*info && (*info)->klass == the_class) |
9a6624c4 | 284 | { |
5b95f2fb | 285 | _Jv_LoaderInfo *old = *info; |
9a6624c4 | 286 | *info = (*info)->next; |
5b95f2fb | 287 | _Jv_Free (old); |
9a6624c4 | 288 | } |
a13dc0d1 | 289 | |
290 | if (*info == NULL) | |
291 | break; | |
9a6624c4 | 292 | } |
9a6624c4 | 293 | } |
294 | ||
295 | void | |
296 | _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) | |
297 | { | |
5b95f2fb | 298 | if (loader && loader == java::lang::ClassLoader::getSystemClassLoader()) |
299 | loader = NULL; | |
300 | ||
301 | // This information can't be visible to the GC. | |
302 | _Jv_LoaderInfo *info | |
303 | = (_Jv_LoaderInfo *) _Jv_Malloc (sizeof(_Jv_LoaderInfo)); | |
9a6624c4 | 304 | jint hash = HASH_UTF(klass->name); |
305 | ||
5b95f2fb | 306 | JvSynchronize sync (&java::lang::Class::class$); |
9a6624c4 | 307 | info->loader = loader; |
308 | info->klass = klass; | |
309 | info->next = initiated_classes[hash]; | |
310 | initiated_classes[hash] = info; | |
9a6624c4 | 311 | } |
312 | ||
313 | // This function is called many times during startup, before main() is | |
380cddab | 314 | // run. At that point in time we know for certain we are running |
315 | // single-threaded, so we don't need to lock when adding classes to the | |
316 | // class chain. At all other times, the caller should synchronize on | |
317 | // Class::class$. | |
9a6624c4 | 318 | void |
1dc74225 | 319 | _Jv_RegisterClasses (const jclass *classes) |
9a6624c4 | 320 | { |
9a6624c4 | 321 | for (; *classes; ++classes) |
322 | { | |
323 | jclass klass = *classes; | |
ceb217a4 | 324 | |
325 | (*_Jv_RegisterClassHook) (klass); | |
9a6624c4 | 326 | |
327 | // registering a compiled class causes | |
328 | // it to be immediately "prepared". | |
95d0972a | 329 | if (klass->state == JV_STATE_NOTHING) |
9a6624c4 | 330 | klass->state = JV_STATE_COMPILED; |
331 | } | |
332 | } | |
333 | ||
1dc74225 | 334 | // This is a version of _Jv_RegisterClasses that takes a count. |
335 | void | |
336 | _Jv_RegisterClasses_Counted (const jclass * classes, size_t count) | |
337 | { | |
338 | size_t i; | |
339 | for (i = 0; i < count; i++) | |
340 | { | |
341 | jclass klass = classes[i]; | |
342 | ||
343 | (*_Jv_RegisterClassHook) (klass); | |
344 | ||
345 | // registering a compiled class causes | |
346 | // it to be immediately "prepared". | |
347 | if (klass->state == JV_STATE_NOTHING) | |
348 | klass->state = JV_STATE_COMPILED; | |
349 | } | |
350 | } | |
351 | ||
ceb217a4 | 352 | void |
353 | _Jv_RegisterClassHookDefault (jclass klass) | |
354 | { | |
355 | jint hash = HASH_UTF (klass->name); | |
681862de | 356 | |
357 | jclass check_class = loaded_classes[hash]; | |
358 | ||
359 | // If the class is already registered, don't re-register it. | |
360 | while (check_class != NULL) | |
361 | { | |
362 | if (check_class == klass) | |
363 | { | |
364 | // If you get this, it means you have the same class in two | |
365 | // different libraries. | |
ff65d698 | 366 | #define TEXT "Duplicate class registration: " |
367 | // We size-limit MESSAGE so that you can't trash the stack. | |
7a240ab7 | 368 | char message[200]; |
ff65d698 | 369 | strcpy (message, TEXT); |
307719b9 | 370 | strncpy (message + sizeof (TEXT) - 1, klass->name->chars(), |
ff65d698 | 371 | sizeof (message) - sizeof (TEXT)); |
372 | message[sizeof (message) - 1] = '\0'; | |
5bac6719 | 373 | if (! gcj::runtimeInitialized) |
374 | JvFail (message); | |
375 | else | |
376 | { | |
377 | java::lang::String *str = JvNewStringLatin1 (message); | |
5bac6719 | 378 | throw new java::lang::VirtualMachineError (str); |
379 | } | |
681862de | 380 | } |
381 | ||
382 | check_class = check_class->next; | |
383 | } | |
384 | ||
ceb217a4 | 385 | klass->next = loaded_classes[hash]; |
386 | loaded_classes[hash] = klass; | |
387 | } | |
388 | ||
389 | // A pointer to a function that actually registers a class. | |
390 | // Normally _Jv_RegisterClassHookDefault, but could be some other function | |
391 | // that registers the class in e.g. a ClassLoader-local table. | |
392 | // Should synchronize on Class:class$ while setting/restore this variable. | |
393 | ||
394 | void (*_Jv_RegisterClassHook) (jclass cl) = _Jv_RegisterClassHookDefault; | |
395 | ||
9a6624c4 | 396 | void |
397 | _Jv_RegisterClass (jclass klass) | |
398 | { | |
399 | jclass classes[2]; | |
400 | classes[0] = klass; | |
401 | classes[1] = NULL; | |
402 | _Jv_RegisterClasses (classes); | |
403 | } | |
404 | ||
9a6624c4 | 405 | jclass |
b345481f | 406 | _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) |
9a6624c4 | 407 | { |
408 | jclass klass = _Jv_FindClassInCache (name, loader); | |
409 | ||
9a6624c4 | 410 | if (! klass) |
411 | { | |
307719b9 | 412 | jstring sname = name->toString(); |
9a6624c4 | 413 | |
5b95f2fb | 414 | java::lang::ClassLoader *sys |
415 | = java::lang::ClassLoader::getSystemClassLoader (); | |
416 | ||
9a6624c4 | 417 | if (loader) |
418 | { | |
419 | // Load using a user-defined loader, jvmspec 5.3.2 | |
420 | klass = loader->loadClass(sname, false); | |
421 | ||
4cbc5296 | 422 | // If "loader" delegated the loadClass operation to another |
423 | // loader, explicitly register that it is also an initiating | |
424 | // loader of the given class. | |
5b95f2fb | 425 | java::lang::ClassLoader *delegate = (loader == sys |
426 | ? NULL | |
427 | : loader); | |
428 | if (klass && klass->getClassLoaderInternal () != delegate) | |
4cbc5296 | 429 | _Jv_RegisterInitiatingLoader (klass, loader); |
9a6624c4 | 430 | } |
431 | else | |
432 | { | |
4cbc5296 | 433 | // Load using the bootstrap loader jvmspec 5.3.1. |
4046fa64 | 434 | klass = sys->loadClass (sname, false); |
9a6624c4 | 435 | |
4046fa64 | 436 | // Register that we're an initiating loader. |
9a6624c4 | 437 | if (klass) |
4046fa64 | 438 | _Jv_RegisterInitiatingLoader (klass, 0); |
9a6624c4 | 439 | } |
440 | } | |
441 | else | |
442 | { | |
443 | // we need classes to be in the hash while | |
444 | // we're loading, so that they can refer to themselves. | |
445 | _Jv_WaitForState (klass, JV_STATE_LOADED); | |
446 | } | |
9a6624c4 | 447 | |
448 | return klass; | |
449 | } | |
450 | ||
d4652353 | 451 | jclass |
452 | _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, | |
453 | java::lang::ClassLoader *loader) | |
454 | { | |
0233d85f | 455 | jclass ret = (jclass) _Jv_AllocObject (&java::lang::Class::class$); |
d4652353 | 456 | ret->name = name; |
457 | ret->superclass = superclass; | |
458 | ret->loader = loader; | |
9a6624c4 | 459 | |
460 | _Jv_RegisterClass (ret); | |
461 | ||
462 | return ret; | |
463 | } | |
464 | ||
9007522b | 465 | static _Jv_IDispatchTable *array_idt = NULL; |
466 | static jshort array_depth = 0; | |
467 | static jclass *array_ancestors = NULL; | |
468 | ||
469 | // Create a class representing an array of ELEMENT and store a pointer to it | |
470 | // in element->arrayclass. LOADER is the ClassLoader which _initiated_ the | |
471 | // instantiation of this array. ARRAY_VTABLE is the vtable to use for the new | |
472 | // array class. This parameter is optional. | |
473 | void | |
474 | _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, | |
475 | _Jv_VTable *array_vtable) | |
9a6624c4 | 476 | { |
9007522b | 477 | JvSynchronize sync (element); |
478 | ||
9a6624c4 | 479 | _Jv_Utf8Const *array_name; |
480 | int len; | |
9007522b | 481 | |
482 | if (element->arrayclass) | |
483 | return; | |
484 | ||
9a6624c4 | 485 | if (element->isPrimitive()) |
3ba4fffb | 486 | { |
487 | if (element == JvPrimClass (void)) | |
488 | throw new java::lang::ClassNotFoundException (); | |
489 | len = 3; | |
490 | } | |
9a6624c4 | 491 | else |
307719b9 | 492 | len = element->name->len() + 5; |
9a6624c4 | 493 | |
494 | { | |
495 | char signature[len]; | |
496 | int index = 0; | |
497 | signature[index++] = '['; | |
9007522b | 498 | // Compute name of array class. |
9a6624c4 | 499 | if (element->isPrimitive()) |
500 | { | |
501 | signature[index++] = (char) element->method_count; | |
502 | } | |
503 | else | |
504 | { | |
307719b9 | 505 | size_t length = element->name->len(); |
506 | const char *const name = element->name->chars(); | |
9a6624c4 | 507 | if (name[0] != '[') |
508 | signature[index++] = 'L'; | |
509 | memcpy (&signature[index], name, length); | |
510 | index += length; | |
511 | if (name[0] != '[') | |
512 | signature[index++] = ';'; | |
513 | } | |
514 | array_name = _Jv_makeUtf8Const (signature, index); | |
515 | } | |
516 | ||
9007522b | 517 | // Create new array class. |
04722d4b | 518 | jclass array_class = _Jv_NewClass (array_name, &java::lang::Object::class$, |
9007522b | 519 | element->loader); |
520 | ||
521 | // Note that `vtable_method_count' doesn't include the initial | |
522 | // gc_descr slot. | |
04722d4b | 523 | JvAssert (java::lang::Object::class$.vtable_method_count |
524 | == NUM_OBJECT_METHODS); | |
525 | int dm_count = java::lang::Object::class$.vtable_method_count; | |
9007522b | 526 | |
67577e43 | 527 | // Create a new vtable by copying Object's vtable. |
9007522b | 528 | _Jv_VTable *vtable; |
529 | if (array_vtable) | |
530 | vtable = array_vtable; | |
531 | else | |
67577e43 | 532 | vtable = _Jv_VTable::new_vtable (dm_count); |
9007522b | 533 | vtable->clas = array_class; |
04722d4b | 534 | vtable->gc_descr = java::lang::Object::class$.vtable->gc_descr; |
67577e43 | 535 | for (int i = 0; i < dm_count; ++i) |
04722d4b | 536 | vtable->set_method (i, java::lang::Object::class$.vtable->get_method (i)); |
67577e43 | 537 | |
9007522b | 538 | array_class->vtable = vtable; |
04722d4b | 539 | array_class->vtable_method_count |
540 | = java::lang::Object::class$.vtable_method_count; | |
9007522b | 541 | |
542 | // Stash the pointer to the element type. | |
543 | array_class->methods = (_Jv_Method *) element; | |
544 | ||
545 | // Register our interfaces. | |
04722d4b | 546 | static jclass interfaces[] = |
547 | { | |
548 | &java::lang::Cloneable::class$, | |
549 | &java::io::Serializable::class$ | |
550 | }; | |
9007522b | 551 | array_class->interfaces = interfaces; |
552 | array_class->interface_count = sizeof interfaces / sizeof interfaces[0]; | |
553 | ||
554 | // Since all array classes have the same interface dispatch table, we can | |
daca25b8 | 555 | // cache one and reuse it. It is not necessary to synchronize this. |
9007522b | 556 | if (!array_idt) |
9a6624c4 | 557 | { |
49095183 | 558 | _Jv_PrepareConstantTimeTables (array_class); |
9007522b | 559 | array_idt = array_class->idt; |
560 | array_depth = array_class->depth; | |
561 | array_ancestors = array_class->ancestors; | |
562 | } | |
563 | else | |
564 | { | |
565 | array_class->idt = array_idt; | |
566 | array_class->depth = array_depth; | |
567 | array_class->ancestors = array_ancestors; | |
568 | } | |
49095183 | 569 | |
9007522b | 570 | using namespace java::lang::reflect; |
571 | { | |
572 | // Array classes are "abstract final"... | |
573 | _Jv_ushort accflags = Modifier::FINAL | Modifier::ABSTRACT; | |
574 | // ... and inherit accessibility from element type, per vmspec 5.3.3.2 | |
575 | accflags |= (element->accflags & Modifier::PUBLIC); | |
576 | accflags |= (element->accflags & Modifier::PROTECTED); | |
577 | accflags |= (element->accflags & Modifier::PRIVATE); | |
578 | array_class->accflags = accflags; | |
579 | } | |
9a6624c4 | 580 | |
9007522b | 581 | // An array class has no visible instance fields. "length" is invisible to |
582 | // reflection. | |
9a6624c4 | 583 | |
9007522b | 584 | // say this class is initialized and ready to go! |
585 | array_class->state = JV_STATE_DONE; | |
9a6624c4 | 586 | |
9007522b | 587 | // vmspec, section 5.3.3 describes this |
588 | if (element->loader != loader) | |
589 | _Jv_RegisterInitiatingLoader (array_class, loader); | |
9a6624c4 | 590 | |
9007522b | 591 | element->arrayclass = array_class; |
9a6624c4 | 592 | } |
56797587 | 593 | |
594 | static jclass stack_head; | |
595 | ||
596 | // These two functions form a stack of classes. When a class is loaded | |
597 | // it is pushed onto the stack by the class loader; this is so that | |
598 | // StackTrace can quickly determine which classes have been loaded. | |
599 | ||
600 | jclass | |
601 | _Jv_PopClass (void) | |
602 | { | |
603 | JvSynchronize sync (&java::lang::Class::class$); | |
604 | if (stack_head) | |
605 | { | |
606 | jclass tmp = stack_head; | |
607 | stack_head = tmp->chain; | |
608 | return tmp; | |
609 | } | |
610 | return NULL; | |
611 | } | |
612 | ||
613 | void | |
614 | _Jv_PushClass (jclass k) | |
615 | { | |
616 | JvSynchronize sync (&java::lang::Class::class$); | |
617 | jclass tmp = stack_head; | |
618 | stack_head = k; | |
619 | k->chain = tmp; | |
620 | } |