OSDN Git Service

Jumbo patch:
[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  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include <limits.h>
14 #include <string.h>
15
16 #pragma implementation "Class.h"
17
18 #include <gcj/cni.h>
19 #include <jvm.h>
20 #include <java-threads.h>
21
22 #include <java/lang/Class.h>
23 #include <java/lang/ClassLoader.h>
24 #include <java/lang/String.h>
25 #include <java/lang/reflect/Modifier.h>
26 #include <java/lang/reflect/Member.h>
27 #include <java/lang/reflect/Method.h>
28 #include <java/lang/reflect/Field.h>
29 #include <java/lang/reflect/Constructor.h>
30 #include <java/lang/AbstractMethodError.h>
31 #include <java/lang/ArrayStoreException.h>
32 #include <java/lang/ClassCastException.h>
33 #include <java/lang/ClassNotFoundException.h>
34 #include <java/lang/ExceptionInInitializerError.h>
35 #include <java/lang/IllegalAccessException.h>
36 #include <java/lang/IllegalAccessError.h>
37 #include <java/lang/IncompatibleClassChangeError.h>
38 #include <java/lang/InstantiationException.h>
39 #include <java/lang/NoClassDefFoundError.h>
40 #include <java/lang/NoSuchFieldException.h>
41 #include <java/lang/NoSuchMethodError.h>
42 #include <java/lang/NoSuchMethodException.h>
43 #include <java/lang/Thread.h>
44 #include <java/lang/NullPointerException.h>
45 #include <java/lang/System.h>
46 #include <java/lang/SecurityManager.h>
47 #include <java/lang/StringBuffer.h>
48 #include <gcj/method.h>
49
50 #include <java-cpool.h>
51
52 \f
53
54 #define CloneableClass _CL_Q34java4lang9Cloneable
55 extern java::lang::Class CloneableClass;
56 #define ObjectClass _CL_Q34java4lang6Object
57 extern java::lang::Class ObjectClass;
58 #define ErrorClass _CL_Q34java4lang5Error
59 extern java::lang::Class ErrorClass;
60 #define ClassClass _CL_Q34java4lang5Class
61 extern java::lang::Class ClassClass;
62 #define MethodClass _CL_Q44java4lang7reflect6Method
63 extern java::lang::Class MethodClass;
64 #define FieldClass _CL_Q44java4lang7reflect5Field
65 extern java::lang::Class FieldClass;
66 #define ConstructorClass _CL_Q44java4lang7reflect11Constructor
67 extern java::lang::Class ConstructorClass;
68
69 // Some constants we use to look up the class initializer.
70 static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
71 static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
72 static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
73 static _Jv_Utf8Const *finit_name = _Jv_makeUtf8Const ("$finit$", 7);
74
75 \f
76
77 jclass
78 java::lang::Class::forName (jstring className)
79 {
80   if (! className)
81     JvThrow (new java::lang::NullPointerException);
82
83 #if 0
84   // FIXME: should check syntax of CLASSNAME and throw
85   // IllegalArgumentException on failure.
86
87   // FIXME: should use class loader from calling method.
88   jclass klass = _Jv_FindClass (className, NULL);
89 #else
90   jsize length = _Jv_GetStringUTFLength (className);
91   char buffer[length];
92   _Jv_GetStringUTFRegion (className, 0, length, buffer);
93
94   // FIXME: should check syntax of CLASSNAME and throw
95   // IllegalArgumentException on failure.
96   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
97
98   // FIXME: should use class loader from calling method.
99   jclass klass = (buffer[0] == '[' 
100                   ? _Jv_FindClassFromSignature (name->data, NULL)
101                   : _Jv_FindClass (name, NULL));
102 #endif
103   if (! klass)
104     JvThrow (new java::lang::ClassNotFoundException (className));
105
106   return klass;
107 }
108
109 java::lang::reflect::Constructor *
110 java::lang::Class::getConstructor (JArray<jclass> *param_types)
111 {
112   jstring partial_sig = getSignature (param_types, true);
113   jint hash = partial_sig->hashCode ();
114
115   int i = isPrimitive () ? 0 : method_count;
116   while (--i >= 0)
117     {
118       // FIXME: access checks.
119       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
120           && _Jv_equal (methods[i].signature, partial_sig, hash))
121         {
122           // Found it.  For getConstructor, the constructor must be
123           // public.
124           using namespace java::lang::reflect;
125           if (! Modifier::isPublic(methods[i].accflags))
126             break;
127           Constructor *cons = new Constructor ();
128           cons->offset = (char *) (&methods[i]) - (char *) methods;
129           cons->declaringClass = this;
130           return cons;
131         }
132     }
133   JvThrow (new java::lang::NoSuchMethodException);
134 }
135
136 JArray<java::lang::reflect::Constructor *> *
137 java::lang::Class::_getConstructors (jboolean declared)
138 {
139   // FIXME: this method needs access checks.
140
141   int numConstructors = 0;
142   int max = isPrimitive () ? 0 : method_count;
143   int i;
144   for (i = max; --i >= 0; )
145     {
146       _Jv_Method *method = &methods[i];
147       if (method->name == NULL
148           || ! _Jv_equalUtf8Consts (method->name, init_name))
149         continue;
150       if (! declared
151           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
152         continue;
153       numConstructors++;
154     }
155   JArray<java::lang::reflect::Constructor *> *result
156     = (JArray<java::lang::reflect::Constructor *> *)
157     JvNewObjectArray (numConstructors, &ConstructorClass, NULL);
158   java::lang::reflect::Constructor** cptr = elements (result);
159   for (i = 0;  i < max;  i++)
160     {
161       _Jv_Method *method = &methods[i];
162       if (method->name == NULL
163           || ! _Jv_equalUtf8Consts (method->name, init_name))
164         continue;
165       if (! declared
166           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
167         continue;
168       java::lang::reflect::Constructor *cons
169         = new java::lang::reflect::Constructor ();
170       cons->offset = (char *) method - (char *) methods;
171       cons->declaringClass = this;
172       *cptr++ = cons;
173     }
174   return result;
175 }
176
177 java::lang::reflect::Constructor *
178 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
179 {
180   jstring partial_sig = getSignature (param_types, true);
181   jint hash = partial_sig->hashCode ();
182
183   int i = isPrimitive () ? 0 : method_count;
184   while (--i >= 0)
185     {
186       // FIXME: access checks.
187       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
188           && _Jv_equal (methods[i].signature, partial_sig, hash))
189         {
190           // Found it.
191           using namespace java::lang::reflect;
192           Constructor *cons = new Constructor ();
193           cons->offset = (char *) (&methods[i]) - (char *) methods;
194           cons->declaringClass = this;
195           return cons;
196         }
197     }
198   JvThrow (new java::lang::NoSuchMethodException);
199 }
200
201 java::lang::reflect::Field *
202 java::lang::Class::getField (jstring name, jint hash)
203 {
204   java::lang::reflect::Field* rfield;
205   for (int i = 0;  i < field_count;  i++)
206     {
207       _Jv_Field *field = &fields[i];
208       if (! _Jv_equal (field->name, name, hash))
209         continue;
210       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
211         continue;
212       rfield = new java::lang::reflect::Field ();
213       rfield->offset = (char*) field - (char*) fields;
214       rfield->declaringClass = this;
215       rfield->name = name;
216       return rfield;
217     }
218   jclass superclass = getSuperclass();
219   if (superclass == NULL)
220     return NULL;
221   rfield = superclass->getField(name, hash);
222   for (int i = 0; i < interface_count && rfield == NULL; ++i)
223     rfield = interfaces[i]->getField (name, hash);
224   return rfield;
225 }
226
227 java::lang::reflect::Field *
228 java::lang::Class::getDeclaredField (jstring name)
229 {
230   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
231   if (s != NULL)
232     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
233   int hash = name->hashCode();
234   for (int i = 0;  i < field_count;  i++)
235     {
236       _Jv_Field *field = &fields[i];
237       if (! _Jv_equal (field->name, name, hash))
238         continue;
239       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
240       rfield->offset = (char*) field - (char*) fields;
241       rfield->declaringClass = this;
242       rfield->name = name;
243       return rfield;
244     }
245   JvThrow (new java::lang::NoSuchFieldException (name));
246 }
247
248 JArray<java::lang::reflect::Field *> *
249 java::lang::Class::getDeclaredFields (void)
250 {
251   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
252   if (s != NULL)
253     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
254   JArray<java::lang::reflect::Field *> *result
255     = (JArray<java::lang::reflect::Field *> *)
256     JvNewObjectArray (field_count, &FieldClass, NULL);
257   java::lang::reflect::Field** fptr = elements (result);
258   for (int i = 0;  i < field_count;  i++)
259     {
260       _Jv_Field *field = &fields[i];
261       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
262       rfield->offset = (char*) field - (char*) fields;
263       rfield->declaringClass = this;
264       *fptr++ = rfield;
265     }
266   return result;
267 }
268
269 void
270 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
271 {
272   if (isPrimitive())
273     buffer->append((jchar) method_count);
274   else
275     {
276       jstring name = getName();
277       if (name->charAt(0) != '[')
278         buffer->append((jchar) 'L');
279       buffer->append(name);
280       if (name->charAt(0) != '[')
281         buffer->append((jchar) ';');
282     }
283 }
284
285 // This doesn't have to be native.  It is an implementation detail
286 // only called from the C++ code, though, so maybe this is clearer.
287 jstring
288 java::lang::Class::getSignature (JArray<jclass> *param_types,
289                                  jboolean is_constructor)
290 {
291   java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
292   buf->append((jchar) '(');
293   jclass *v = elements (param_types);
294   for (int i = 0; i < param_types->length; ++i)
295     v[i]->getSignature(buf);
296   buf->append((jchar) ')');
297   if (is_constructor)
298     buf->append((jchar) 'V');
299   return buf->toString();
300 }
301
302 java::lang::reflect::Method *
303 java::lang::Class::getDeclaredMethod (jstring name,
304                                       JArray<jclass> *param_types)
305 {
306   jstring partial_sig = getSignature (param_types, false);
307   jint p_len = partial_sig->length();
308   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
309   int i = isPrimitive () ? 0 : method_count;
310   while (--i >= 0)
311     {
312       // FIXME: access checks.
313       if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
314           && _Jv_equaln (methods[i].signature, partial_sig, p_len))
315         {
316           // Found it.
317           using namespace java::lang::reflect;
318           Method *rmethod = new Method ();
319           rmethod->offset = (char*) (&methods[i]) - (char*) methods;
320           rmethod->declaringClass = this;
321           return rmethod;
322         }
323     }
324   JvThrow (new java::lang::NoSuchMethodException);
325 }
326
327 JArray<java::lang::reflect::Method *> *
328 java::lang::Class::getDeclaredMethods (void)
329 {
330   int numMethods = 0;
331   int max = isPrimitive () ? 0 : method_count;
332   int i;
333   for (i = max; --i >= 0; )
334     {
335       _Jv_Method *method = &methods[i];
336       if (method->name == NULL
337           || _Jv_equalUtf8Consts (method->name, clinit_name)
338           || _Jv_equalUtf8Consts (method->name, init_name)
339           || _Jv_equalUtf8Consts (method->name, finit_name))
340         continue;
341       numMethods++;
342     }
343   JArray<java::lang::reflect::Method *> *result
344     = (JArray<java::lang::reflect::Method *> *)
345     JvNewObjectArray (numMethods, &MethodClass, NULL);
346   java::lang::reflect::Method** mptr = elements (result);
347   for (i = 0;  i < max;  i++)
348     {
349       _Jv_Method *method = &methods[i];
350       if (method->name == NULL
351           || _Jv_equalUtf8Consts (method->name, clinit_name)
352           || _Jv_equalUtf8Consts (method->name, init_name)
353           || _Jv_equalUtf8Consts (method->name, finit_name))
354         continue;
355       java::lang::reflect::Method* rmethod
356         = new java::lang::reflect::Method ();
357       rmethod->offset = (char*) method - (char*) methods;
358       rmethod->declaringClass = this;
359       *mptr++ = rmethod;
360     }
361   return result;
362 }
363
364 jstring
365 java::lang::Class::getName (void)
366 {
367   char buffer[name->length + 1];  
368   memcpy (buffer, name->data, name->length); 
369   buffer[name->length] = '\0';
370   return _Jv_NewStringUTF (buffer);
371 }
372
373 JArray<jclass> *
374 java::lang::Class::getClasses (void)
375 {
376   // Until we have inner classes, it always makes sense to return an
377   // empty array.
378   JArray<jclass> *result
379     = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
380   return result;
381 }
382
383 JArray<jclass> *
384 java::lang::Class::getDeclaredClasses (void)
385 {
386   checkMemberAccess (java::lang::reflect::Member::DECLARED);
387   // Until we have inner classes, it always makes sense to return an
388   // empty array.
389   JArray<jclass> *result
390     = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
391   return result;
392 }
393
394 jclass
395 java::lang::Class::getDeclaringClass (void)
396 {
397   // Until we have inner classes, it makes sense to always return
398   // NULL.
399   return NULL;
400 }
401
402 jint
403 java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
404                                jint offset)
405 {
406   int count = 0;
407   for (int i = 0;  i < field_count;  i++)
408     {
409       _Jv_Field *field = &fields[i];
410       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
411         continue;
412       ++count;
413
414       if (result != NULL)
415         {
416           java::lang::reflect::Field *rfield
417             = new java::lang::reflect::Field ();
418           rfield->offset = (char *) field - (char *) fields;
419           rfield->declaringClass = this;
420           rfield->name = _Jv_NewStringUtf8Const (field->name);
421           (elements (result))[offset + i] = rfield;
422         }
423     }
424   jclass superclass = getSuperclass();
425   if (superclass != NULL)
426     {
427       int s_count = superclass->_getFields (result, offset);
428       count += s_count;
429       offset += s_count;
430     }
431   for (int i = 0; i < interface_count; ++i)
432     {
433       int f_count = interfaces[i]->_getFields (result, offset);
434       count += f_count;
435       offset += f_count;
436     }
437   return count;
438 }
439
440 JArray<java::lang::reflect::Field *> *
441 java::lang::Class::getFields (void)
442 {
443   using namespace java::lang::reflect;
444
445   int count = _getFields (NULL, 0);
446
447   JArray<java::lang::reflect::Field *> *result
448     = ((JArray<java::lang::reflect::Field *> *)
449        JvNewObjectArray (count, &FieldClass, NULL));
450
451   _getFields (result, 0);
452
453   return result;
454 }
455
456 JArray<jclass> *
457 java::lang::Class::getInterfaces (void)
458 {
459   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
460   jobject *data = elements (r);
461   for (int i = 0; i < interface_count; ++i)
462     data[i] = interfaces[i];
463   return reinterpret_cast<JArray<jclass> *> (r);
464 }
465
466 java::lang::reflect::Method *
467 java::lang::Class::getMethod (jstring name, JArray<jclass> *param_types)
468 {
469   jstring partial_sig = getSignature (param_types, false);
470   jint p_len = partial_sig->length();
471   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
472   for (Class *klass = this; klass; klass = klass->getSuperclass())
473     {
474       int i = klass->isPrimitive () ? 0 : klass->method_count;
475       while (--i >= 0)
476         {
477           // FIXME: access checks.
478           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
479               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
480             {
481               // Found it.
482               using namespace java::lang::reflect;
483
484               // Method must be public.
485               if (! Modifier::isPublic (klass->methods[i].accflags))
486                 break;
487
488               Method *rmethod = new Method ();
489               rmethod->offset = ((char *) (&klass->methods[i])
490                                  - (char *) klass->methods);
491               rmethod->declaringClass = klass;
492               return rmethod;
493             }
494         }
495     }
496   JvThrow (new java::lang::NoSuchMethodException);
497 }
498
499 // This is a very slow implementation, since it re-scans all the
500 // methods we've already listed to make sure we haven't duplicated a
501 // method.  It also over-estimates the required size, so we have to
502 // shrink the result array later.
503 jint
504 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
505                                 jint offset)
506 {
507   jint count = 0;
508
509   // First examine all local methods
510   for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
511     {
512       _Jv_Method *method = &methods[i];
513       if (method->name == NULL
514           || _Jv_equalUtf8Consts (method->name, clinit_name)
515           || _Jv_equalUtf8Consts (method->name, init_name)
516           || _Jv_equalUtf8Consts (method->name, finit_name))
517         continue;
518       // Only want public methods.
519       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
520         continue;
521
522       // This is where we over-count the slots required if we aren't
523       // filling the result for real.
524       if (result != NULL)
525         {
526           jboolean add = true;
527           java::lang::reflect::Method **mp = elements (result);
528           // If we already have a method with this name and signature,
529           // then ignore this one.  This can happen with virtual
530           // methods.
531           for (int j = 0; j < offset; ++j)
532             {
533               _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
534               if (_Jv_equalUtf8Consts (method->name, meth_2->name)
535                   && _Jv_equalUtf8Consts (method->signature,
536                                           meth_2->signature))
537                 {
538                   add = false;
539                   break;
540                 }
541             }
542           if (! add)
543             continue;
544         }
545
546       if (result != NULL)
547         {
548           using namespace java::lang::reflect;
549           Method *rmethod = new Method ();
550           rmethod->offset = (char *) method - (char *) methods;
551           rmethod->declaringClass = this;
552           Method **mp = elements (result);
553           mp[offset + count] = rmethod;
554         }
555       ++count;
556     }
557   offset += count;
558
559   // Now examine superclasses.
560   if (getSuperclass () != NULL)
561     {
562       jint s_count = getSuperclass()->_getMethods (result, offset);
563       offset += s_count;
564       count += s_count;
565     }
566
567   // Finally, examine interfaces.
568   for (int i = 0; i < interface_count; ++i)
569     {
570       int f_count = interfaces[i]->_getMethods (result, offset);
571       count += f_count;
572       offset += f_count;
573     }
574
575   return count;
576 }
577
578 JArray<java::lang::reflect::Method *> *
579 java::lang::Class::getMethods (void)
580 {
581   using namespace java::lang::reflect;
582
583   // FIXME: security checks.
584
585   // This will overestimate the size we need.
586   jint count = _getMethods (NULL, 0);
587
588   JArray<Method *> *result
589     = ((JArray<Method *> *) JvNewObjectArray (count, &MethodClass, NULL));
590
591   // When filling the array for real, we get the actual count.  Then
592   // we resize the array.
593   jint real_count = _getMethods (result, 0);
594
595   if (real_count != count)
596     {
597       JArray<Method *> *r2
598         = ((JArray<Method *> *) JvNewObjectArray (real_count, &MethodClass,
599                                                   NULL));
600       
601       Method **destp = elements (r2);
602       Method **srcp = elements (result);
603
604       for (int i = 0; i < real_count; ++i)
605         *destp++ = *srcp++;
606
607       result = r2;
608     }
609
610   return result;
611 }
612
613 jboolean
614 java::lang::Class::isAssignableFrom (jclass klass)
615 {
616   // Arguments may not have been initialized, given ".class" syntax.
617   _Jv_InitClass (this);
618   _Jv_InitClass (klass);
619   return _Jv_IsAssignableFrom (this, klass);
620 }
621
622 inline jboolean
623 java::lang::Class::isInstance (jobject obj)
624 {
625   if (__builtin_expect (! obj || isPrimitive (), false))
626     return false;
627   _Jv_InitClass (this);
628   return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
629 }
630
631 inline jboolean
632 java::lang::Class::isInterface (void)
633 {
634   return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
635 }
636
637 jobject
638 java::lang::Class::newInstance (void)
639 {
640   // FIXME: do accessibility checks here.  There currently doesn't
641   // seem to be any way to do these.
642   // FIXME: we special-case one check here just to pass a Plum Hall
643   // test.  Once access checking is implemented, remove this.
644   if (this == &ClassClass)
645     JvThrow (new java::lang::IllegalAccessException);
646
647   if (isPrimitive ()
648       || isInterface ()
649       || isArray ()
650       || java::lang::reflect::Modifier::isAbstract(accflags))
651     JvThrow (new java::lang::InstantiationException);
652
653   _Jv_InitClass (this);
654
655   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
656   if (! meth)
657     JvThrow (new java::lang::NoSuchMethodException);
658
659   jobject r = JvAllocObject (this);
660   ((void (*) (jobject)) meth->ncode) (r);
661   return r;
662 }
663
664 void
665 java::lang::Class::finalize (void)
666 {
667 #ifdef INTERPRETER
668   JvAssert (_Jv_IsInterpretedClass (this));
669   _Jv_UnregisterClass (this);
670 #endif
671 }
672
673 // This implements the initialization process for a class.  From Spec
674 // section 12.4.2.
675 void
676 java::lang::Class::initializeClass (void)
677 {
678   // jshort-circuit to avoid needless locking.
679   if (state == JV_STATE_DONE)
680     return;
681
682   // Step 1.
683   _Jv_MonitorEnter (this);
684
685   if (state < JV_STATE_LINKED)
686     {    
687 #ifdef INTERPRETER
688       if (_Jv_IsInterpretedClass (this))
689         {
690           // this can throw exceptions, so exit the monitor as a precaution.
691           _Jv_MonitorExit (this);
692           java::lang::ClassLoader::resolveClass0 (this);
693           _Jv_MonitorEnter (this);
694         }
695       else
696 #endif
697         {
698           _Jv_PrepareCompiledClass (this);
699         }
700     }
701   
702   if (state <= JV_STATE_LINKED)
703     _Jv_PrepareConstantTimeTables (this);
704
705   // Step 2.
706   java::lang::Thread *self = java::lang::Thread::currentThread();
707   // FIXME: `self' can be null at startup.  Hence this nasty trick.
708   self = (java::lang::Thread *) ((long) self | 1);
709   while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
710     wait ();
711
712   // Steps 3 &  4.
713   if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self)
714     {
715       _Jv_MonitorExit (this);
716       return;
717     }
718
719   // Step 5.
720   if (state == JV_STATE_ERROR)
721     {
722       _Jv_MonitorExit (this);
723       JvThrow (new java::lang::NoClassDefFoundError);
724     }
725
726   // Step 6.
727   thread = self;
728   state = JV_STATE_IN_PROGRESS;
729   _Jv_MonitorExit (this);
730
731   // Step 7.
732   if (! isInterface () && superclass)
733     {
734       try
735         {
736           superclass->initializeClass ();
737         }
738       catch (java::lang::Throwable *except)
739         {
740           // Caught an exception.
741           _Jv_MonitorEnter (this);
742           state = JV_STATE_ERROR;
743           notifyAll ();
744           _Jv_MonitorExit (this);
745           throw except;
746         }
747     }
748
749   // Steps 8, 9, 10, 11.
750   try
751     {
752       _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
753                                              void_signature);
754       if (meth)
755         ((void (*) (void)) meth->ncode) ();
756     }
757   catch (java::lang::Throwable *except)
758     {
759       if (! ErrorClass.isInstance(except))
760         {
761           try
762             {
763               except = new ExceptionInInitializerError (except);
764             }
765           catch (java::lang::Throwable *t)
766             {
767               except = t;
768             }
769         }
770       _Jv_MonitorEnter (this);
771       state = JV_STATE_ERROR;
772       notifyAll ();
773       _Jv_MonitorExit (this);
774       JvThrow (except);
775     }
776
777   _Jv_MonitorEnter (this);
778   state = JV_STATE_DONE;
779   notifyAll ();
780   _Jv_MonitorExit (this);
781 }
782
783 \f
784
785 //
786 // Some class-related convenience functions.
787 //
788
789 // Find a method declared in the class.  If it is not declared locally
790 // (or if it is inherited), return NULL.
791 _Jv_Method *
792 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
793                     _Jv_Utf8Const *signature)
794 {
795   for (int i = 0; i < klass->method_count; ++i)
796     {
797       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
798           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
799         return &klass->methods[i];
800     }
801   return NULL;
802 }
803
804 _Jv_Method *
805 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
806                           _Jv_Utf8Const *signature)
807 {
808   for (; klass; klass = klass->getSuperclass())
809     {
810       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
811
812       if (meth)
813         return meth;
814     }
815
816   return NULL;
817 }
818
819 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
820 #define MCACHE_SIZE 1023
821
822 struct _Jv_mcache
823 {
824   jclass klass;
825   _Jv_Method *method;
826 };
827
828 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
829
830 static void *
831 _Jv_FindMethodInCache (jclass klass,
832                        _Jv_Utf8Const *name,
833                        _Jv_Utf8Const *signature)
834 {
835   int index = name->hash & MCACHE_SIZE;
836   _Jv_mcache *mc = method_cache + index;
837   _Jv_Method *m = mc->method;
838
839   if (mc->klass == klass
840       && m != NULL             // thread safe check
841       && _Jv_equalUtf8Consts (m->name, name)
842       && _Jv_equalUtf8Consts (m->signature, signature))
843     return mc->method->ncode;
844   return NULL;
845 }
846
847 static void
848 _Jv_AddMethodToCache (jclass klass,
849                        _Jv_Method *method)
850 {
851   _Jv_MonitorEnter (&ClassClass); 
852
853   int index = method->name->hash & MCACHE_SIZE;
854
855   method_cache[index].method = method;
856   method_cache[index].klass = klass;
857
858   _Jv_MonitorExit (&ClassClass);
859 }
860
861 void *
862 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
863                            _Jv_Utf8Const *signature)
864 {
865   using namespace java::lang::reflect;
866
867   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
868   if (ncode != 0)
869     return ncode;
870
871   for (; klass; klass = klass->getSuperclass())
872     {
873       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
874       if (! meth)
875         continue;
876
877       if (Modifier::isStatic(meth->accflags))
878         JvThrow (new java::lang::IncompatibleClassChangeError
879                  (_Jv_GetMethodString (klass, meth->name)));
880       if (Modifier::isAbstract(meth->accflags))
881         JvThrow (new java::lang::AbstractMethodError
882                  (_Jv_GetMethodString (klass, meth->name)));
883       if (! Modifier::isPublic(meth->accflags))
884         JvThrow (new java::lang::IllegalAccessError
885                  (_Jv_GetMethodString (klass, meth->name)));
886
887       _Jv_AddMethodToCache (klass, meth);
888
889       return meth->ncode;
890     }
891   JvThrow (new java::lang::IncompatibleClassChangeError);
892   return NULL;                 // Placate compiler.
893 }
894
895 // Fast interface method lookup by index.
896 void *
897 _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
898 {
899   _Jv_IDispatchTable *cldt = klass->idt;
900   int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
901   return cldt->cls.itable[idx];
902 }
903
904 inline jboolean
905 _Jv_IsAssignableFrom (jclass target, jclass source)
906 {
907   if (target == &ObjectClass 
908       || source == target 
909       || (source->ancestors != NULL 
910           && source->ancestors[source->depth - target->depth] == target))
911      return true;
912      
913   // If target is array, so must source be.  
914   if (target->isArray ())
915     {
916       if (! source->isArray())
917         return false;
918       return _Jv_IsAssignableFrom(target->getComponentType(), 
919                                   source->getComponentType());
920     }
921
922   if (target->isInterface())
923     {
924       // Abstract classes have no IDTs, so compare superclasses instead.
925       if (java::lang::reflect::Modifier::isAbstract (source->accflags))
926         {
927           jclass super = source->getSuperclass();
928           return super ? _Jv_IsAssignableFrom (target, super) : false;
929         }
930
931       if (source->state != JV_STATE_DONE)
932         source->initializeClass ();
933       if (target->state != JV_STATE_DONE)
934         target->initializeClass ();
935
936       _Jv_IDispatchTable *cl_idt = source->idt;
937       _Jv_IDispatchTable *if_idt = target->idt;
938
939       if (if_idt == NULL) // The interface has no implementations
940         return false;
941
942       if (__builtin_expect ((if_idt == NULL), false))
943         return false; // No class implementing TARGET has been loaded.    
944       jshort cl_iindex = cl_idt->cls.iindex;
945       if (cl_iindex <= if_idt->iface.ioffsets[0])
946         {
947           jshort offset = if_idt->iface.ioffsets[cl_iindex];
948           if (offset < cl_idt->cls.itable_length
949               && cl_idt->cls.itable[offset] == target)
950             return true;
951         }
952     }
953     
954   return false;
955 }
956
957 jboolean
958 _Jv_IsInstanceOf(jobject obj, jclass cl)
959 {
960   if (__builtin_expect (!obj, false))
961     return false;
962   return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
963 }
964
965 void *
966 _Jv_CheckCast (jclass c, jobject obj)
967 {
968   if (__builtin_expect 
969        (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
970     JvThrow (new java::lang::ClassCastException);
971   return obj;
972 }
973
974 void
975 _Jv_CheckArrayStore (jobject arr, jobject obj)
976 {
977   if (obj)
978     {
979       JvAssert (arr != NULL);
980       jclass elt_class = (JV_CLASS (arr))->getComponentType();
981       jclass obj_class = JV_CLASS (obj);
982       if (__builtin_expect 
983           (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
984         JvThrow (new java::lang::ArrayStoreException);
985     }
986 }
987
988 #define INITIAL_IOFFSETS_LEN 4
989 #define INITIAL_IFACES_LEN 4
990
991 // Generate tables for constant-time assignment testing and interface
992 // method lookup. This implements the technique described by Per Bothner
993 // <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
994 // http://sourceware.cygnus.com/ml/java-discuss/1999-q3/msg00377.html
995 void 
996 _Jv_PrepareConstantTimeTables (jclass klass)
997 {  
998   if (klass->isPrimitive () || klass->isInterface ())
999     return;
1000   
1001   // Short-circuit in case we've been called already.
1002   if ((klass->idt != NULL) || klass->depth != 0)
1003     return;
1004
1005   // Calculate the class depth and ancestor table. The depth of a class 
1006   // is how many "extends" it is removed from Object. Thus the depth of 
1007   // java.lang.Object is 0, but the depth of java.io.FilterOutputStream 
1008   // is 2. Depth is defined for all regular and array classes, but not 
1009   // interfaces or primitive types.
1010    
1011   jclass klass0 = klass;
1012   while (klass0 != &ObjectClass)
1013     {
1014       klass0 = klass0->superclass;
1015       klass->depth++;
1016     }
1017
1018   // We do class member testing in constant time by using a small table 
1019   // of all the ancestor classes within each class. The first element is 
1020   // a pointer to the current class, and the rest are pointers to the 
1021   // classes ancestors, ordered from the current class down by decreasing 
1022   // depth. We do not include java.lang.Object in the table of ancestors, 
1023   // since it is redundant.
1024         
1025   klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
1026   klass0 = klass;
1027   for (int index = 0; index < klass->depth; index++)
1028     {
1029       klass->ancestors[index] = klass0;
1030       klass0 = klass0->superclass;
1031     }
1032     
1033   if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
1034     return;
1035
1036   klass->idt = 
1037     (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1038     
1039   _Jv_ifaces ifaces;
1040
1041   ifaces.count = 0;
1042   ifaces.len = INITIAL_IFACES_LEN;
1043   ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
1044
1045   int itable_size = _Jv_GetInterfaces (klass, &ifaces);
1046
1047   if (ifaces.count > 0)
1048     {
1049       klass->idt->cls.itable = 
1050         (void **) _Jv_Malloc (itable_size * sizeof (void *));
1051       klass->idt->cls.itable_length = itable_size;
1052           
1053       jshort *itable_offsets = 
1054         (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
1055
1056       _Jv_GenerateITable (klass, &ifaces, itable_offsets);
1057
1058       jshort cls_iindex = 
1059         _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
1060
1061       for (int i=0; i < ifaces.count; i++)
1062         {
1063           ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
1064             itable_offsets[i];
1065         }
1066
1067       klass->idt->cls.iindex = cls_iindex;          
1068
1069       _Jv_Free (ifaces.list);
1070       _Jv_Free (itable_offsets);
1071     }
1072   else 
1073     {
1074       klass->idt->cls.iindex = SHRT_MAX;
1075     }
1076 }
1077
1078 // Return index of item in list, or -1 if item is not present.
1079 jshort
1080 _Jv_IndexOf (void *item, void **list, jshort list_len)
1081 {
1082   for (int i=0; i < list_len; i++)
1083     {
1084       if (list[i] == item)
1085         return i;
1086     }
1087   return -1;
1088 }
1089
1090 // Find all unique interfaces directly or indirectly implemented by klass.
1091 // Returns the size of the interface dispatch table (itable) for klass, which 
1092 // is the number of unique interfaces plus the total number of methods that 
1093 // those interfaces declare. May extend ifaces if required.
1094 jshort
1095 _Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
1096 {
1097   jshort result = 0;
1098   
1099   for (int i=0; i < klass->interface_count; i++)
1100     {
1101       jclass iface = klass->interfaces[i];
1102       if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
1103         {
1104           if (ifaces->count + 1 >= ifaces->len)
1105             {
1106               /* Resize ifaces list */
1107               ifaces->len = ifaces->len * 2;
1108               ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, 
1109                              ifaces->len * sizeof(jclass));
1110             }
1111           ifaces->list[ifaces->count] = iface;
1112           ifaces->count++;
1113
1114           result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
1115         }
1116     }
1117     
1118   if (klass->isInterface())
1119     {
1120       result += klass->method_count + 1;
1121     }
1122   else
1123     {
1124       if (klass->superclass)
1125         {
1126           result += _Jv_GetInterfaces (klass->superclass, ifaces);
1127         }
1128     }
1129   return result;
1130 }
1131
1132 // Fill out itable in klass, resolving method declarations in each ifaces.
1133 // itable_offsets is filled out with the position of each iface in itable,
1134 // such that itable[itable_offsets[n]] == ifaces.list[n].
1135 void
1136 _Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
1137 {
1138   void **itable = klass->idt->cls.itable;
1139   jshort itable_pos = 0;
1140
1141   for (int i=0; i < ifaces->count; i++)
1142     { 
1143       jclass iface = ifaces->list[i];
1144       itable_offsets[i] = itable_pos;
1145       itable_pos = _Jv_AppendPartialITable (klass, iface, itable,
1146                    itable_pos);
1147       
1148       /* Create interface dispatch table for iface */
1149       if (iface->idt == NULL)
1150         {
1151           iface->idt = 
1152             (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1153
1154           // The first element of ioffsets is its length (itself included).
1155           jshort *ioffsets = 
1156             (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
1157           ioffsets[0] = INITIAL_IOFFSETS_LEN;
1158           for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
1159             ioffsets[i] = -1;
1160
1161           iface->idt->iface.ioffsets = ioffsets;            
1162         }
1163     }
1164 }
1165
1166 // Format method name for use in error messages.
1167 jstring
1168 _Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
1169 {
1170   jstring r = JvNewStringUTF (klass->name->data);
1171   r = r->concat (JvNewStringUTF ("."));
1172   r = r->concat (JvNewStringUTF (name->data));
1173   return r;
1174 }
1175
1176 void 
1177 _Jv_ThrowNoSuchMethodError ()
1178 {
1179   JvThrow (new java::lang::NoSuchMethodError ());
1180 }
1181
1182 // Each superinterface of a class (i.e. each interface that the class
1183 // directly or indirectly implements) has a corresponding "Partial
1184 // Interface Dispatch Table" whose size is (number of methods + 1) words.
1185 // The first word is a pointer to the interface (i.e. the java.lang.Class
1186 // instance for that interface).  The remaining words are pointers to the
1187 // actual methods that implement the methods declared in the interface,
1188 // in order of declaration.
1189 //
1190 // Append partial interface dispatch table for "iface" to "itable", at
1191 // position itable_pos.
1192 // Returns the offset at which the next partial ITable should be appended.
1193 jshort
1194 _Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, 
1195                          jshort pos)
1196 {
1197   using namespace java::lang::reflect;
1198
1199   itable[pos++] = (void *) iface;
1200   _Jv_Method *meth;
1201   
1202   for (int j=0; j < iface->method_count; j++)
1203     {
1204       meth = NULL;
1205       for (jclass cl = klass; cl; cl = cl->getSuperclass())
1206         {
1207           meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
1208                  iface->methods[j].signature);
1209                  
1210           if (meth)
1211             break;
1212         }
1213
1214       if (meth && (meth->name->data[0] == '<'))
1215         {
1216           // leave a placeholder in the itable for hidden init methods.
1217           itable[pos] = NULL;   
1218         }
1219       else if (meth)
1220         {
1221           if (Modifier::isStatic(meth->accflags))
1222             JvThrow (new java::lang::IncompatibleClassChangeError
1223                      (_Jv_GetMethodString (klass, meth->name)));
1224           if (Modifier::isAbstract(meth->accflags))
1225             JvThrow (new java::lang::AbstractMethodError
1226                      (_Jv_GetMethodString (klass, meth->name)));
1227           if (! Modifier::isPublic(meth->accflags))
1228             JvThrow (new java::lang::IllegalAccessError
1229                      (_Jv_GetMethodString (klass, meth->name)));
1230
1231           itable[pos] = meth->ncode;
1232         }
1233       else
1234         {
1235           // The method doesn't exist in klass. Binary compatibility rules
1236           // permit this, so we delay the error until runtime using a pointer
1237           // to a method which throws an exception.
1238           itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
1239         }
1240       pos++;
1241     }
1242     
1243   return pos;
1244 }
1245
1246 static _Jv_Mutex_t iindex_mutex;
1247 bool iindex_mutex_initialized = false;
1248
1249 // We need to find the correct offset in the Class Interface Dispatch 
1250 // Table for a given interface. Once we have that, invoking an interface 
1251 // method just requires combining the Method's index in the interface 
1252 // (known at compile time) to get the correct method.  Doing a type test 
1253 // (cast or instanceof) is the same problem: Once we have a possible Partial 
1254 // Interface Dispatch Table, we just compare the first element to see if it 
1255 // matches the desired interface. So how can we find the correct offset?  
1256 // Our solution is to keep a vector of candiate offsets in each interface 
1257 // (idt->iface.ioffsets), and in each class we have an index 
1258 // (idt->cls.iindex) used to select the correct offset from ioffsets.
1259 //
1260 // Calculate and return iindex for a new class. 
1261 // ifaces is a vector of num interfaces that the class implements.
1262 // offsets[j] is the offset in the interface dispatch table for the
1263 // interface corresponding to ifaces[j].
1264 // May extend the interface ioffsets if required.
1265 jshort
1266 _Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
1267 {
1268   int i;
1269   int j;
1270   
1271   // Acquire a global lock to prevent itable corruption in case of multiple 
1272   // classes that implement an intersecting set of interfaces being linked
1273   // simultaneously. We can assume that the mutex will be initialized
1274   // single-threaded.
1275   if (! iindex_mutex_initialized)
1276     {
1277       _Jv_MutexInit (&iindex_mutex);
1278       iindex_mutex_initialized = true;
1279     }
1280   
1281   _Jv_MutexLock (&iindex_mutex);
1282   
1283   for (i=1;; i++)  /* each potential position in ioffsets */
1284     {
1285       for (j=0;; j++)  /* each iface */
1286         {
1287           if (j >= num)
1288             goto found;
1289           if (i > ifaces[j]->idt->iface.ioffsets[0])
1290             continue;
1291           int ioffset = ifaces[j]->idt->iface.ioffsets[i];
1292           /* We can potentially share this position with another class. */
1293           if (ioffset >= 0 && ioffset != offsets[j])
1294             break; /* Nope. Try next i. */        
1295         }
1296     }
1297   found:
1298   for (j = 0; j < num; j++)
1299     {
1300       int len = ifaces[j]->idt->iface.ioffsets[0];
1301       if (i >= len) 
1302         {
1303           /* Resize ioffsets. */
1304           int newlen = 2 * len;
1305           if (i >= newlen)
1306             newlen = i + 3;
1307           jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
1308           jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, 
1309                                           newlen * sizeof(jshort));       
1310           new_ioffsets[0] = newlen;
1311
1312           while (len < newlen)
1313             new_ioffsets[len++] = -1;
1314           
1315           ifaces[j]->idt->iface.ioffsets = new_ioffsets;
1316         }
1317       ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
1318     }
1319
1320   _Jv_MutexUnlock (&iindex_mutex);
1321
1322   return i;
1323 }
1324
1325 // Only used by serialization
1326 java::lang::reflect::Field *
1327 java::lang::Class::getPrivateField (jstring name)
1328 {
1329   int hash = name->hashCode ();
1330
1331   java::lang::reflect::Field* rfield;
1332   for (int i = 0;  i < field_count;  i++)
1333     {
1334       _Jv_Field *field = &fields[i];
1335       if (! _Jv_equal (field->name, name, hash))
1336         continue;
1337       rfield = new java::lang::reflect::Field ();
1338       rfield->offset = (char*) field - (char*) fields;
1339       rfield->declaringClass = this;
1340       rfield->name = name;
1341       return rfield;
1342     }
1343   jclass superclass = getSuperclass();
1344   if (superclass == NULL)
1345     return NULL;
1346   rfield = superclass->getPrivateField(name);
1347   for (int i = 0; i < interface_count && rfield == NULL; ++i)
1348     rfield = interfaces[i]->getPrivateField (name);
1349   return rfield;
1350 }
1351
1352 // Only used by serialization
1353 java::lang::reflect::Method *
1354 java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
1355 {
1356   jstring partial_sig = getSignature (param_types, false);
1357   jint p_len = partial_sig->length();
1358   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
1359   for (Class *klass = this; klass; klass = klass->getSuperclass())
1360     {
1361       int i = klass->isPrimitive () ? 0 : klass->method_count;
1362       while (--i >= 0)
1363         {
1364           // FIXME: access checks.
1365           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1366               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
1367             {
1368               // Found it.
1369               using namespace java::lang::reflect;
1370
1371               Method *rmethod = new Method ();
1372               rmethod->offset = ((char *) (&klass->methods[i])
1373                                  - (char *) klass->methods);
1374               rmethod->declaringClass = klass;
1375               return rmethod;
1376             }
1377         }
1378     }
1379   JvThrow (new java::lang::NoSuchMethodException);
1380 }
1381