OSDN Git Service

2005-03-10 Bryce McKinlay <mckinlay@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natClass.cc
1 // natClass.cc - Implementation of java.lang.Class native methods.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  
4    Free Software Foundation
5
6    This file is part of libgcj.
7
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
10 details.  */
11
12 #include <config.h>
13
14 #include <limits.h>
15 #include <string.h>
16 #include <stddef.h>
17 #include <stdio.h>
18
19 #pragma implementation "Class.h"
20
21 #include <gcj/cni.h>
22 #include <jvm.h>
23 #include <java-threads.h>
24
25 #include <java/lang/Class.h>
26 #include <java/lang/ClassLoader.h>
27 #include <java/lang/String.h>
28 #include <java/lang/reflect/Modifier.h>
29 #include <java/lang/reflect/Member.h>
30 #include <java/lang/reflect/Method.h>
31 #include <java/lang/reflect/Field.h>
32 #include <java/lang/reflect/Constructor.h>
33 #include <java/lang/AbstractMethodError.h>
34 #include <java/lang/ArrayStoreException.h>
35 #include <java/lang/ClassCastException.h>
36 #include <java/lang/ClassNotFoundException.h>
37 #include <java/lang/ExceptionInInitializerError.h>
38 #include <java/lang/IllegalAccessException.h>
39 #include <java/lang/IllegalAccessError.h>
40 #include <java/lang/IllegalArgumentException.h>
41 #include <java/lang/IncompatibleClassChangeError.h>
42 #include <java/lang/NoSuchFieldError.h>
43 #include <java/lang/ArrayIndexOutOfBoundsException.h>
44 #include <java/lang/InstantiationException.h>
45 #include <java/lang/NoClassDefFoundError.h>
46 #include <java/lang/NoSuchFieldException.h>
47 #include <java/lang/NoSuchMethodError.h>
48 #include <java/lang/NoSuchMethodException.h>
49 #include <java/lang/Thread.h>
50 #include <java/lang/NullPointerException.h>
51 #include <java/lang/RuntimePermission.h>
52 #include <java/lang/System.h>
53 #include <java/lang/SecurityManager.h>
54 #include <java/lang/StringBuffer.h>
55 #include <java/lang/VMClassLoader.h>
56 #include <gcj/method.h>
57 #include <gnu/gcj/runtime/MethodRef.h>
58 #include <gnu/gcj/RawData.h>
59 #include <java/lang/VerifyError.h>
60
61 #include <java-cpool.h>
62 #include <java-interp.h>
63 #include <java-assert.h>
64 #include <java-stack.h>
65 #include <execution.h>
66
67 \f
68
69 using namespace gcj;
70
71 jclass
72 java::lang::Class::forName (jstring className, jboolean initialize,
73                             java::lang::ClassLoader *loader)
74 {
75   if (! className)
76     throw new java::lang::NullPointerException;
77
78   jsize length = _Jv_GetStringUTFLength (className);
79   char buffer[length];
80   _Jv_GetStringUTFRegion (className, 0, className->length(), buffer);
81
82   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
83
84   if (! _Jv_VerifyClassName (name))
85     throw new java::lang::ClassNotFoundException (className);
86
87   jclass klass = (buffer[0] == '[' 
88                   ? _Jv_FindClassFromSignature (name->chars(), loader)
89                   : _Jv_FindClass (name, loader));
90
91   if (klass == NULL)
92     throw new java::lang::ClassNotFoundException (className);
93
94   if (initialize)
95     _Jv_InitClass (klass);
96
97   return klass;
98 }
99
100 jclass
101 java::lang::Class::forName (jstring className)
102 {
103   java::lang::ClassLoader *loader = NULL;
104
105   jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
106   if (caller)
107     loader = caller->getClassLoaderInternal();
108
109   return forName (className, true, loader);
110 }
111
112 java::lang::ClassLoader *
113 java::lang::Class::getClassLoader (void)
114 {
115   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
116   if (s != NULL)
117     {
118       jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
119       ClassLoader *caller_loader = NULL;
120       if (caller)
121         caller_loader = caller->getClassLoaderInternal();
122
123       // If the caller has a non-null class loader, and that loader
124       // is not this class' loader or an ancestor thereof, then do a
125       // security check.
126       if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader))
127         s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader")));
128     }
129
130   // The spec requires us to return `null' for primitive classes.  In
131   // other cases we have the option of returning `null' for classes
132   // loaded with the bootstrap loader.  All gcj-compiled classes which
133   // are linked into the application used to return `null' here, but
134   // that confuses some poorly-written applications.  It is a useful
135   // and apparently harmless compatibility hack to simply never return
136   // `null' instead.
137   if (isPrimitive ())
138     return NULL;
139   return loader ? loader : ClassLoader::systemClassLoader;
140 }
141
142 java::lang::reflect::Constructor *
143 java::lang::Class::getConstructor (JArray<jclass> *param_types)
144 {
145   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
146
147   jstring partial_sig = getSignature (param_types, true);
148   jint hash = partial_sig->hashCode ();
149
150   int i = isPrimitive () ? 0 : method_count;
151   while (--i >= 0)
152     {
153       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
154           && _Jv_equal (methods[i].signature, partial_sig, hash))
155         {
156           // Found it.  For getConstructor, the constructor must be
157           // public.
158           using namespace java::lang::reflect;
159           if (! Modifier::isPublic(methods[i].accflags))
160             break;
161           Constructor *cons = new Constructor ();
162           cons->offset = (char *) (&methods[i]) - (char *) methods;
163           cons->declaringClass = this;
164           return cons;
165         }
166     }
167   throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name));
168 }
169
170 JArray<java::lang::reflect::Constructor *> *
171 java::lang::Class::_getConstructors (jboolean declared)
172 {
173   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
174
175   int numConstructors = 0;
176   int max = isPrimitive () ? 0 : method_count;
177   int i;
178   for (i = max; --i >= 0; )
179     {
180       _Jv_Method *method = &methods[i];
181       if (method->name == NULL
182           || ! _Jv_equalUtf8Consts (method->name, init_name))
183         continue;
184       if (! declared
185           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
186         continue;
187       numConstructors++;
188     }
189   JArray<java::lang::reflect::Constructor *> *result
190     = (JArray<java::lang::reflect::Constructor *> *)
191     JvNewObjectArray (numConstructors,
192                       &java::lang::reflect::Constructor::class$,
193                       NULL);
194   java::lang::reflect::Constructor** cptr = elements (result);
195   for (i = 0;  i < max;  i++)
196     {
197       _Jv_Method *method = &methods[i];
198       if (method->name == NULL
199           || ! _Jv_equalUtf8Consts (method->name, init_name))
200         continue;
201       if (! declared
202           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
203         continue;
204       java::lang::reflect::Constructor *cons
205         = new java::lang::reflect::Constructor ();
206       cons->offset = (char *) method - (char *) methods;
207       cons->declaringClass = this;
208       *cptr++ = cons;
209     }
210   return result;
211 }
212
213 java::lang::reflect::Constructor *
214 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
215 {
216   memberAccessCheck(java::lang::reflect::Member::DECLARED);
217
218   jstring partial_sig = getSignature (param_types, true);
219   jint hash = partial_sig->hashCode ();
220
221   int i = isPrimitive () ? 0 : method_count;
222   while (--i >= 0)
223     {
224       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
225           && _Jv_equal (methods[i].signature, partial_sig, hash))
226         {
227           // Found it.
228           using namespace java::lang::reflect;
229           Constructor *cons = new Constructor ();
230           cons->offset = (char *) (&methods[i]) - (char *) methods;
231           cons->declaringClass = this;
232           return cons;
233         }
234     }
235   throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name));
236 }
237
238 java::lang::reflect::Field *
239 java::lang::Class::getField (jstring name, jint hash)
240 {
241   java::lang::reflect::Field* rfield;
242   for (int i = 0;  i < field_count;  i++)
243     {
244       _Jv_Field *field = &fields[i];
245       if (! _Jv_equal (field->name, name, hash))
246         continue;
247       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
248         continue;
249       rfield = new java::lang::reflect::Field ();
250       rfield->offset = (char*) field - (char*) fields;
251       rfield->declaringClass = this;
252       rfield->name = name;
253       return rfield;
254     }
255   jclass superclass = getSuperclass();
256   if (superclass == NULL)
257     return NULL;
258   rfield = superclass->getField(name, hash);
259   for (int i = 0; i < interface_count && rfield == NULL; ++i)
260     rfield = interfaces[i]->getField (name, hash);
261   return rfield;
262 }
263
264 java::lang::reflect::Field *
265 java::lang::Class::getDeclaredField (jstring name)
266 {
267   memberAccessCheck(java::lang::reflect::Member::DECLARED);
268   int hash = name->hashCode();
269   for (int i = 0;  i < field_count;  i++)
270     {
271       _Jv_Field *field = &fields[i];
272       if (! _Jv_equal (field->name, name, hash))
273         continue;
274       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
275       rfield->offset = (char*) field - (char*) fields;
276       rfield->declaringClass = this;
277       rfield->name = name;
278       return rfield;
279     }
280   throw new java::lang::NoSuchFieldException (name);
281 }
282
283 JArray<java::lang::reflect::Field *> *
284 java::lang::Class::getDeclaredFields (jboolean public_only)
285 {
286   int size;
287   if (public_only)
288     {
289       size = 0;
290       for (int i = 0; i < field_count; ++i)
291         {
292           _Jv_Field *field = &fields[i];
293           if ((field->flags & java::lang::reflect::Modifier::PUBLIC))
294             ++size;
295         }
296     }
297   else
298     size = field_count;
299
300   JArray<java::lang::reflect::Field *> *result
301     = (JArray<java::lang::reflect::Field *> *)
302     JvNewObjectArray (size, &java::lang::reflect::Field::class$, NULL);
303   java::lang::reflect::Field** fptr = elements (result);
304   for (int i = 0;  i < field_count;  i++)
305     {
306       _Jv_Field *field = &fields[i];
307       if (public_only
308           && ! (field->flags & java::lang::reflect::Modifier::PUBLIC))
309         continue;
310       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
311       rfield->offset = (char*) field - (char*) fields;
312       rfield->declaringClass = this;
313       *fptr++ = rfield;
314     }
315   return result;
316 }
317
318 void
319 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
320 {
321   if (isPrimitive())
322     buffer->append((jchar) method_count);
323   else
324     {
325       jstring name = getName();
326       if (name->charAt(0) != '[')
327         buffer->append((jchar) 'L');
328       buffer->append(name);
329       if (name->charAt(0) != '[')
330         buffer->append((jchar) ';');
331     }
332 }
333
334 // This doesn't have to be native.  It is an implementation detail
335 // only called from the C++ code, though, so maybe this is clearer.
336 jstring
337 java::lang::Class::getSignature (JArray<jclass> *param_types,
338                                  jboolean is_constructor)
339 {
340   java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
341   buf->append((jchar) '(');
342   // A NULL param_types means "no parameters".
343   if (param_types != NULL)
344     {
345       jclass *v = elements (param_types);
346       for (int i = 0; i < param_types->length; ++i)
347         v[i]->getSignature(buf);
348     }
349   buf->append((jchar) ')');
350   if (is_constructor)
351     buf->append((jchar) 'V');
352   return buf->toString();
353 }
354
355 java::lang::reflect::Method *
356 java::lang::Class::_getDeclaredMethod (jstring name,
357                                        JArray<jclass> *param_types)
358 {
359   jstring partial_sig = getSignature (param_types, false);
360   jint p_len = partial_sig->length();
361   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
362   int i = isPrimitive () ? 0 : method_count;
363   while (--i >= 0)
364     {
365       if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
366           && _Jv_equaln (methods[i].signature, partial_sig, p_len)
367           && (methods[i].accflags
368               & java::lang::reflect::Modifier::INVISIBLE) == 0)
369         {
370           // Found it.
371           using namespace java::lang::reflect;
372           Method *rmethod = new Method ();
373           rmethod->offset = (char*) (&methods[i]) - (char*) methods;
374           rmethod->declaringClass = this;
375           return rmethod;
376         }
377     }
378   return NULL;
379 }
380
381 JArray<java::lang::reflect::Method *> *
382 java::lang::Class::getDeclaredMethods (void)
383 {
384   memberAccessCheck(java::lang::reflect::Member::DECLARED);
385
386   int numMethods = 0;
387   int max = isPrimitive () ? 0 : method_count;
388   int i;
389   for (i = max; --i >= 0; )
390     {
391       _Jv_Method *method = &methods[i];
392       if (method->name == NULL
393           || _Jv_equalUtf8Consts (method->name, clinit_name)
394           || _Jv_equalUtf8Consts (method->name, init_name)
395           || _Jv_equalUtf8Consts (method->name, finit_name)
396           || (methods[i].accflags
397               & java::lang::reflect::Modifier::INVISIBLE) != 0)
398         continue;
399       numMethods++;
400     }
401   JArray<java::lang::reflect::Method *> *result
402     = (JArray<java::lang::reflect::Method *> *)
403     JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL);
404   java::lang::reflect::Method** mptr = elements (result);
405   for (i = 0;  i < max;  i++)
406     {
407       _Jv_Method *method = &methods[i];
408       if (method->name == NULL
409           || _Jv_equalUtf8Consts (method->name, clinit_name)
410           || _Jv_equalUtf8Consts (method->name, init_name)
411           || _Jv_equalUtf8Consts (method->name, finit_name)
412           || (methods[i].accflags
413               & java::lang::reflect::Modifier::INVISIBLE) != 0)
414         continue;
415       java::lang::reflect::Method* rmethod
416         = new java::lang::reflect::Method ();
417       rmethod->offset = (char*) method - (char*) methods;
418       rmethod->declaringClass = this;
419       *mptr++ = rmethod;
420     }
421   return result;
422 }
423
424 jstring
425 java::lang::Class::getName (void)
426 {
427   return name->toString();
428 }
429
430 JArray<jclass> *
431 java::lang::Class::getClasses (void)
432 {
433   // FIXME: security checking.
434
435   // Until we have inner classes, it always makes sense to return an
436   // empty array.
437   JArray<jclass> *result
438     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
439                                            NULL);
440   return result;
441 }
442
443 JArray<jclass> *
444 java::lang::Class::getDeclaredClasses (void)
445 {
446   memberAccessCheck (java::lang::reflect::Member::DECLARED);
447   // Until we have inner classes, it always makes sense to return an
448   // empty array.
449   JArray<jclass> *result
450     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
451                                            NULL);
452   return result;
453 }
454
455 jclass
456 java::lang::Class::getDeclaringClass (void)
457 {
458   // Until we have inner classes, it makes sense to always return
459   // NULL.
460   return NULL;
461 }
462
463 JArray<jclass> *
464 java::lang::Class::getInterfaces (void)
465 {
466   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
467   jobject *data = elements (r);
468   for (int i = 0; i < interface_count; ++i)
469     {
470       typedef unsigned int uaddr __attribute__ ((mode (pointer)));
471       data[i] = interfaces[i];
472       if ((uaddr)data[i] < (uaddr)constants.size)
473         fprintf (stderr, "ERROR !!!\n");
474     }
475   return reinterpret_cast<JArray<jclass> *> (r);
476 }
477
478 java::lang::reflect::Method *
479 java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types)
480 {
481   jstring partial_sig = getSignature (param_types, false);
482   jint p_len = partial_sig->length();
483   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
484
485    for (Class *klass = this; klass; klass = klass->getSuperclass())
486     {
487       int i = klass->isPrimitive () ? 0 : klass->method_count;
488       while (--i >= 0)
489         {
490           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
491               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)
492               && (klass->methods[i].accflags
493                   & java::lang::reflect::Modifier::INVISIBLE) == 0)
494             {
495               // Found it.
496               using namespace java::lang::reflect;
497
498               // Method must be public.
499               if (! Modifier::isPublic (klass->methods[i].accflags))
500                 break;
501
502               Method *rmethod = new Method ();
503               rmethod->offset = ((char *) (&klass->methods[i])
504                                  - (char *) klass->methods);
505               rmethod->declaringClass = klass;
506               return rmethod;
507             }
508         }
509     }
510
511   // If we haven't found a match, and this class is an interface, then
512   // check all the superinterfaces.
513   if (isInterface())
514     {
515       for (int i = 0; i < interface_count; ++i)
516         {
517           using namespace java::lang::reflect;
518           Method *rmethod = interfaces[i]->_getMethod (name, param_types);
519           if (rmethod != NULL)
520             return rmethod;
521         }
522     }
523
524   return NULL;
525 }
526
527 // This is a very slow implementation, since it re-scans all the
528 // methods we've already listed to make sure we haven't duplicated a
529 // method.  It also over-estimates the required size, so we have to
530 // shrink the result array later.
531 jint
532 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
533                                 jint offset)
534 {
535   jint count = 0;
536
537   // First examine all local methods
538   for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
539     {
540       _Jv_Method *method = &methods[i];
541       if (method->name == NULL
542           || _Jv_equalUtf8Consts (method->name, clinit_name)
543           || _Jv_equalUtf8Consts (method->name, init_name)
544           || _Jv_equalUtf8Consts (method->name, finit_name)
545           || (method->accflags
546               & java::lang::reflect::Modifier::INVISIBLE) != 0)
547         continue;
548       // Only want public methods.
549       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
550         continue;
551
552       // This is where we over-count the slots required if we aren't
553       // filling the result for real.
554       if (result != NULL)
555         {
556           jboolean add = true;
557           java::lang::reflect::Method **mp = elements (result);
558           // If we already have a method with this name and signature,
559           // then ignore this one.  This can happen with virtual
560           // methods.
561           for (int j = 0; j < offset; ++j)
562             {
563               _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
564               if (_Jv_equalUtf8Consts (method->name, meth_2->name)
565                   && _Jv_equalUtf8Consts (method->signature,
566                                           meth_2->signature))
567                 {
568                   add = false;
569                   break;
570                 }
571             }
572           if (! add)
573             continue;
574         }
575
576       if (result != NULL)
577         {
578           using namespace java::lang::reflect;
579           Method *rmethod = new Method ();
580           rmethod->offset = (char *) method - (char *) methods;
581           rmethod->declaringClass = this;
582           Method **mp = elements (result);
583           mp[offset + count] = rmethod;
584         }
585       ++count;
586     }
587   offset += count;
588
589   // Now examine superclasses.
590   if (getSuperclass () != NULL)
591     {
592       jint s_count = getSuperclass()->_getMethods (result, offset);
593       offset += s_count;
594       count += s_count;
595     }
596
597   // Finally, examine interfaces.
598   for (int i = 0; i < interface_count; ++i)
599     {
600       int f_count = interfaces[i]->_getMethods (result, offset);
601       count += f_count;
602       offset += f_count;
603     }
604
605   return count;
606 }
607
608 JArray<java::lang::reflect::Method *> *
609 java::lang::Class::getMethods (void)
610 {
611   using namespace java::lang::reflect;
612
613   memberAccessCheck(Member::PUBLIC);
614
615   // This will overestimate the size we need.
616   jint count = _getMethods (NULL, 0);
617
618   JArray<Method *> *result
619     = ((JArray<Method *> *) JvNewObjectArray (count,
620                                               &Method::class$,
621                                               NULL));
622
623   // When filling the array for real, we get the actual count.  Then
624   // we resize the array.
625   jint real_count = _getMethods (result, 0);
626
627   if (real_count != count)
628     {
629       JArray<Method *> *r2
630         = ((JArray<Method *> *) JvNewObjectArray (real_count,
631                                                   &Method::class$,
632                                                   NULL));
633       
634       Method **destp = elements (r2);
635       Method **srcp = elements (result);
636
637       for (int i = 0; i < real_count; ++i)
638         *destp++ = *srcp++;
639
640       result = r2;
641     }
642
643   return result;
644 }
645
646 jboolean
647 java::lang::Class::isAssignableFrom (jclass klass)
648 {
649   // Arguments may not have been initialized, given ".class" syntax.
650   _Jv_InitClass (this);
651   _Jv_InitClass (klass);
652   return _Jv_IsAssignableFrom (this, klass);
653 }
654
655 jboolean
656 java::lang::Class::isInstance (jobject obj)
657 {
658   if (! obj)
659     return false;
660   _Jv_InitClass (this);
661   return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
662 }
663
664 jobject
665 java::lang::Class::newInstance (void)
666 {
667   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
668
669   if (isPrimitive ()
670       || isInterface ()
671       || isArray ()
672       || java::lang::reflect::Modifier::isAbstract(accflags))
673     throw new java::lang::InstantiationException (getName ());
674
675   _Jv_InitClass (this);
676
677   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
678   if (! meth)
679     throw new java::lang::InstantiationException (getName());
680
681   jobject r = _Jv_AllocObject (this);
682   ((void (*) (jobject)) meth->ncode) (r);
683   return r;
684 }
685
686 void
687 java::lang::Class::finalize (void)
688 {
689   engine->unregister(this);
690 }
691
692 // This implements the initialization process for a class.  From Spec
693 // section 12.4.2.
694 void
695 java::lang::Class::initializeClass (void)
696 {
697   // Short-circuit to avoid needless locking.
698   if (state == JV_STATE_DONE)
699     return;
700
701   // Step 1.  We introduce a new scope so we can synchronize more
702   // easily.
703   {
704     JvSynchronize sync (this);
705
706     if (state < JV_STATE_LINKED)
707       java::lang::VMClassLoader::resolveClass (this);
708
709     // Step 2.
710     java::lang::Thread *self = java::lang::Thread::currentThread();
711     self = (java::lang::Thread *) ((long) self | 1);
712     while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
713       wait ();
714
715     // Steps 3 &  4.
716     if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS)
717       return;
718
719     // Step 5.
720     if (state == JV_STATE_ERROR)
721       throw new java::lang::NoClassDefFoundError (getName());
722
723     // Step 6.
724     thread = self;
725     _Jv_Linker::wait_for_state (this, JV_STATE_LINKED);
726     state = JV_STATE_IN_PROGRESS;
727   }
728
729   // Step 7.
730   if (! isInterface () && superclass)
731     {
732       try
733         {
734           _Jv_InitClass (superclass);
735         }
736       catch (java::lang::Throwable *except)
737         {
738           // Caught an exception.
739           JvSynchronize sync (this);
740           state = JV_STATE_ERROR;
741           notifyAll ();
742           throw except;
743         }
744     }
745
746   // Steps 8, 9, 10, 11.
747   try
748     {
749       _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
750                                              void_signature);
751       if (meth)
752         ((void (*) (void)) meth->ncode) ();
753     }
754   catch (java::lang::Throwable *except)
755     {
756       if (! java::lang::Error::class$.isInstance(except))
757         {
758           try
759             {
760               except = new ExceptionInInitializerError (except);
761             }
762           catch (java::lang::Throwable *t)
763             {
764               except = t;
765             }
766         }
767
768       JvSynchronize sync (this);
769       state = JV_STATE_ERROR;
770       notifyAll ();
771       throw except;
772     }
773
774   JvSynchronize sync (this);
775   state = JV_STATE_DONE;
776   notifyAll ();
777 }
778
779 // Only used by serialization
780 java::lang::reflect::Field *
781 java::lang::Class::getPrivateField (jstring name)
782 {
783   int hash = name->hashCode ();
784
785   java::lang::reflect::Field* rfield;
786   for (int i = 0;  i < field_count;  i++)
787     {
788       _Jv_Field *field = &fields[i];
789       if (! _Jv_equal (field->name, name, hash))
790         continue;
791       rfield = new java::lang::reflect::Field ();
792       rfield->offset = (char*) field - (char*) fields;
793       rfield->declaringClass = this;
794       rfield->name = name;
795       return rfield;
796     }
797   jclass superclass = getSuperclass();
798   if (superclass == NULL)
799     return NULL;
800   rfield = superclass->getPrivateField(name);
801   for (int i = 0; i < interface_count && rfield == NULL; ++i)
802     rfield = interfaces[i]->getPrivateField (name);
803   return rfield;
804 }
805
806 // Only used by serialization
807 java::lang::reflect::Method *
808 java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
809 {
810   jstring partial_sig = getSignature (param_types, false);
811   jint p_len = partial_sig->length();
812   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
813   for (Class *klass = this; klass; klass = klass->getSuperclass())
814     {
815       int i = klass->isPrimitive () ? 0 : klass->method_count;
816       while (--i >= 0)
817         {
818           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
819               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
820             {
821               // Found it.
822               using namespace java::lang::reflect;
823
824               Method *rmethod = new Method ();
825               rmethod->offset = ((char *) (&klass->methods[i])
826                                  - (char *) klass->methods);
827               rmethod->declaringClass = klass;
828               return rmethod;
829             }
830         }
831     }
832   throw new java::lang::NoSuchMethodException (name);
833 }
834
835 // Private accessor method for Java code to retrieve the protection domain.
836 java::security::ProtectionDomain *
837 java::lang::Class::getProtectionDomain0 ()
838 {
839   return protectionDomain;
840 }
841
842 JArray<jobject> *
843 java::lang::Class::getSigners()
844 {
845   return hack_signers;
846 }
847
848 void
849 java::lang::Class::setSigners(JArray<jobject> *s)
850 {
851   hack_signers = s;
852 }
853
854 \f
855
856 //
857 // Some class-related convenience functions.
858 //
859
860 // Find a method declared in the class.  If it is not declared locally
861 // (or if it is inherited), return NULL.
862 _Jv_Method *
863 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
864                     _Jv_Utf8Const *signature)
865 {
866   for (int i = 0; i < klass->method_count; ++i)
867     {
868       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
869           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
870         return &klass->methods[i];
871     }
872   return NULL;
873 }
874
875 _Jv_Method *
876 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
877                           _Jv_Utf8Const *signature,
878                           jclass *declarer_result)
879 {
880   for (; klass; klass = klass->getSuperclass())
881     {
882       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
883
884       if (meth)
885         {
886           if (declarer_result)
887             *declarer_result = klass;
888           return meth;
889         }
890     }
891
892   return NULL;
893 }
894
895 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
896 #define MCACHE_SIZE 1023
897
898 struct _Jv_mcache
899 {
900   jclass klass;
901   _Jv_Method *method;
902 };
903
904 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
905
906 static void *
907 _Jv_FindMethodInCache (jclass klass,
908                        _Jv_Utf8Const *name,
909                        _Jv_Utf8Const *signature)
910 {
911   int index = name->hash16 () & MCACHE_SIZE;
912   _Jv_mcache *mc = method_cache + index;
913   _Jv_Method *m = mc->method;
914
915   if (mc->klass == klass
916       && m != NULL             // thread safe check
917       && _Jv_equalUtf8Consts (m->name, name)
918       && _Jv_equalUtf8Consts (m->signature, signature))
919     return mc->method->ncode;
920   return NULL;
921 }
922
923 static void
924 _Jv_AddMethodToCache (jclass klass,
925                        _Jv_Method *method)
926 {
927   _Jv_MonitorEnter (&java::lang::Class::class$); 
928
929   int index = method->name->hash16 () & MCACHE_SIZE;
930
931   method_cache[index].method = method;
932   method_cache[index].klass = klass;
933
934   _Jv_MonitorExit (&java::lang::Class::class$);
935 }
936
937 void *
938 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
939                            _Jv_Utf8Const *signature)
940 {
941   using namespace java::lang::reflect;
942
943   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
944   if (ncode != 0)
945     return ncode;
946
947   for (; klass; klass = klass->getSuperclass())
948     {
949       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
950       if (! meth)
951         continue;
952
953       if (Modifier::isStatic(meth->accflags))
954         throw new java::lang::IncompatibleClassChangeError
955           (_Jv_GetMethodString (klass, meth));
956       if (Modifier::isAbstract(meth->accflags))
957         throw new java::lang::AbstractMethodError
958           (_Jv_GetMethodString (klass, meth));
959       if (! Modifier::isPublic(meth->accflags))
960         throw new java::lang::IllegalAccessError
961           (_Jv_GetMethodString (klass, meth));
962
963       _Jv_AddMethodToCache (klass, meth);
964
965       return meth->ncode;
966     }
967   throw new java::lang::IncompatibleClassChangeError;
968 }
969
970 // Fast interface method lookup by index.
971 void *
972 _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
973 {
974   _Jv_IDispatchTable *cldt = klass->idt;
975   int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
976   return cldt->cls.itable[idx];
977 }
978
979 jboolean
980 _Jv_IsAssignableFrom (jclass target, jclass source)
981 {
982   if (source == target)
983     return true;
984
985   // If target is array, so must source be.  
986   while (target->isArray ())
987     {
988       if (! source->isArray())
989         return false;
990       target = target->getComponentType();
991       source = source->getComponentType();
992     }
993
994   if (target->isInterface())
995     {
996       // Abstract classes have no IDT, and IDTs provide no way to check
997       // two interfaces for assignability.
998       if (__builtin_expect 
999           (source->idt == NULL || source->isInterface(), false))
1000         return _Jv_InterfaceAssignableFrom (target, source);
1001
1002       _Jv_IDispatchTable *cl_idt = source->idt;
1003       _Jv_IDispatchTable *if_idt = target->idt;
1004
1005       if (__builtin_expect ((if_idt == NULL), false))
1006         return false; // No class implementing TARGET has been loaded.    
1007       jshort cl_iindex = cl_idt->cls.iindex;
1008       if (cl_iindex < if_idt->iface.ioffsets[0])
1009         {
1010           jshort offset = if_idt->iface.ioffsets[cl_iindex];
1011           if (offset != -1 && offset < cl_idt->cls.itable_length
1012               && cl_idt->cls.itable[offset] == target)
1013             return true;
1014         }
1015       return false;
1016     }
1017
1018   // Primitive TYPE classes are only assignable to themselves.
1019   if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false))
1020     return false;
1021
1022   if (target == &java::lang::Object::class$)
1023     return true;
1024   else if (source->ancestors == NULL || target->ancestors == NULL)
1025     {
1026       // We need this case when either SOURCE or TARGET has not has
1027       // its constant-time tables prepared.
1028
1029       // At this point we know that TARGET can't be Object, so it is
1030       // safe to use that as the termination point.
1031       while (source && source != &java::lang::Object::class$)
1032         {
1033           if (source == target)
1034             return true;
1035           source = source->getSuperclass();
1036         }
1037     }
1038   else if (source->depth >= target->depth
1039            && source->ancestors[source->depth - target->depth] == target)
1040     return true;
1041
1042   return false;
1043 }
1044
1045 // Interface type checking, the slow way. Returns TRUE if IFACE is a 
1046 // superinterface of SOURCE. This is used when SOURCE is also an interface,
1047 // or a class with no interface dispatch table.
1048 jboolean
1049 _Jv_InterfaceAssignableFrom (jclass iface, jclass source)
1050 {
1051   for (int i = 0; i < source->interface_count; i++)
1052     {
1053       jclass interface = source->interfaces[i];
1054       if (iface == interface
1055           || _Jv_InterfaceAssignableFrom (iface, interface))
1056         return true;      
1057     }
1058     
1059   if (!source->isInterface()
1060       && source->superclass 
1061       && _Jv_InterfaceAssignableFrom (iface, source->superclass))
1062     return true;
1063         
1064   return false;
1065 }
1066
1067 jboolean
1068 _Jv_IsInstanceOf(jobject obj, jclass cl)
1069 {
1070   if (__builtin_expect (!obj, false))
1071     return false;
1072   return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
1073 }
1074
1075 void *
1076 _Jv_CheckCast (jclass c, jobject obj)
1077 {
1078   if (__builtin_expect 
1079        (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
1080     throw new java::lang::ClassCastException
1081       ((new java::lang::StringBuffer
1082         (obj->getClass()->getName()))->append
1083        (JvNewStringUTF(" cannot be cast to "))->append
1084        (c->getName())->toString());
1085
1086   return obj;
1087 }
1088
1089 void
1090 _Jv_CheckArrayStore (jobject arr, jobject obj)
1091 {
1092   if (obj)
1093     {
1094       JvAssert (arr != NULL);
1095       jclass elt_class = (JV_CLASS (arr))->getComponentType();
1096       if (elt_class == &java::lang::Object::class$)
1097         return;
1098       jclass obj_class = JV_CLASS (obj);
1099       if (__builtin_expect 
1100           (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
1101         throw new java::lang::ArrayStoreException
1102                 ((new java::lang::StringBuffer
1103                  (JvNewStringUTF("Cannot store ")))->append
1104                  (obj_class->getName())->append
1105                  (JvNewStringUTF(" in array of type "))->append
1106                  (elt_class->getName())->toString());
1107     }
1108 }
1109
1110 jboolean
1111 _Jv_IsAssignableFromSlow (jclass target, jclass source)
1112 {
1113   // First, strip arrays.
1114   while (target->isArray ())
1115     {
1116       // If target is array, source must be as well.
1117       if (! source->isArray ())
1118        return false;
1119       target = target->getComponentType ();
1120       source = source->getComponentType ();
1121     }
1122
1123   // Quick success.
1124   if (target == &java::lang::Object::class$)
1125     return true;
1126
1127   // Ensure that the classes have their supers installed.
1128   _Jv_Linker::wait_for_state (source, JV_STATE_LOADING);
1129   _Jv_Linker::wait_for_state (target, JV_STATE_LOADING);
1130
1131   do
1132     {
1133       if (source == target)
1134        return true;
1135
1136       if (target->isPrimitive () || source->isPrimitive ())
1137        return false;
1138
1139       if (target->isInterface ())
1140        {
1141          for (int i = 0; i < source->interface_count; ++i)
1142            {
1143              // We use a recursive call because we also need to
1144              // check superinterfaces.
1145              if (_Jv_IsAssignableFromSlow (target, source->getInterface (i)))
1146                return true;
1147            }
1148        }
1149       source = source->getSuperclass ();
1150     }
1151   while (source != NULL);
1152
1153   return false;
1154 }
1155
1156 // Lookup an interface method by name.  This is very similar to
1157 // purpose to _getMethod, but the interfaces are quite different.  It
1158 // might be a good idea for _getMethod to call this function.
1159 //
1160 // Return true of the method is found, with the class in FOUND_CLASS
1161 // and the index in INDEX.
1162 bool
1163 _Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index,
1164                         const _Jv_Utf8Const *utf_name,  
1165                         const _Jv_Utf8Const *utf_sig)
1166 {
1167    for (jclass klass = search_class; klass; klass = klass->getSuperclass())
1168     {
1169       // FIXME: Throw an exception?
1170       if (!klass->isInterface ())
1171         return false;
1172       
1173       int i = klass->method_count;
1174       while (--i >= 0)
1175         {
1176           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1177               && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig))
1178             {
1179               // Found it.
1180               using namespace java::lang::reflect;
1181
1182               // FIXME: Method must be public.  Throw an exception?
1183               if (! Modifier::isPublic (klass->methods[i].accflags))
1184                 break;
1185
1186               found_class = klass;
1187               // Interface method indexes count from 1.
1188               index = i+1;
1189               return true;
1190             }
1191         }
1192     }
1193
1194   // If we haven't found a match, and this class is an interface, then
1195   // check all the superinterfaces.
1196   if (search_class->isInterface())
1197     {
1198       for (int i = 0; i < search_class->interface_count; ++i)
1199         {
1200           using namespace java::lang::reflect;
1201           bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], 
1202                                            found_class, index,
1203                                            utf_name, utf_sig);
1204           if (found)
1205             return true;
1206         }
1207     }
1208
1209   return false;
1210 }