source: trunk/gcc/libjava/java/lang/natClassLoader.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

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