OSDN Git Service

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