OSDN Git Service

2002-12-03 Andrew Haley <aph@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  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/IllegalArgumentException.h>
38 #include <java/lang/IncompatibleClassChangeError.h>
39 #include <java/lang/ArrayIndexOutOfBoundsException.h>
40 #include <java/lang/InstantiationException.h>
41 #include <java/lang/NoClassDefFoundError.h>
42 #include <java/lang/NoSuchFieldException.h>
43 #include <java/lang/NoSuchMethodError.h>
44 #include <java/lang/NoSuchMethodException.h>
45 #include <java/lang/Thread.h>
46 #include <java/lang/NullPointerException.h>
47 #include <java/lang/RuntimePermission.h>
48 #include <java/lang/System.h>
49 #include <java/lang/SecurityManager.h>
50 #include <java/lang/StringBuffer.h>
51 #include <gnu/gcj/runtime/StackTrace.h>
52 #include <gcj/method.h>
53 #include <gnu/gcj/runtime/MethodRef.h>
54 #include <gnu/gcj/RawData.h>
55
56 #include <java-cpool.h>
57
58 \f
59
60 using namespace gcj;
61
62 jclass
63 java::lang::Class::forName (jstring className, jboolean initialize,
64                             java::lang::ClassLoader *loader)
65 {
66   if (! className)
67     throw new java::lang::NullPointerException;
68
69   jsize length = _Jv_GetStringUTFLength (className);
70   char buffer[length];
71   _Jv_GetStringUTFRegion (className, 0, length, buffer);
72
73   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
74
75   if (! _Jv_VerifyClassName (name))
76     throw new java::lang::ClassNotFoundException (className);
77
78   jclass klass = (buffer[0] == '[' 
79                   ? _Jv_FindClassFromSignature (name->data, loader)
80                   : _Jv_FindClass (name, loader));
81
82   if (klass == NULL)
83     throw new java::lang::ClassNotFoundException (className);
84
85   if (initialize)
86     _Jv_InitClass (klass);
87
88   return klass;
89 }
90
91 jclass
92 java::lang::Class::forName (jstring className)
93 {
94   java::lang::ClassLoader *loader = NULL;
95   gnu::gcj::runtime::StackTrace *t 
96     = new gnu::gcj::runtime::StackTrace(4);
97   java::lang::Class *klass = NULL;
98   try
99     {
100       for (int i=1; !klass; i++)
101         {
102           klass = t->classAt (i);
103         }
104       loader = klass->getClassLoader();
105     }
106   catch (::java::lang::ArrayIndexOutOfBoundsException *e)
107     {
108     }
109
110   return forName (className, true, loader);
111 }
112
113 java::lang::ClassLoader *
114 java::lang::Class::getClassLoader (void)
115 {
116 #if 0
117   // FIXME: the checks we need to do are more complex.  See the spec.
118   // Currently we can't implement them.
119   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
120   if (s != NULL)
121     s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader")));
122 #endif
123
124   // The spec requires us to return `null' for primitive classes.  In
125   // other cases we have the option of returning `null' for classes
126   // loaded with the bootstrap loader.  All gcj-compiled classes which
127   // are linked into the application used to return `null' here, but
128   // that confuses some poorly-written applications.  It is a useful
129   // and apparently harmless compatibility hack to simply never return
130   // `null' instead.
131   if (isPrimitive ())
132     return NULL;
133   return loader ? loader : ClassLoader::getSystemClassLoader ();
134 }
135
136 java::lang::reflect::Constructor *
137 java::lang::Class::getConstructor (JArray<jclass> *param_types)
138 {
139   jstring partial_sig = getSignature (param_types, true);
140   jint hash = partial_sig->hashCode ();
141
142   int i = isPrimitive () ? 0 : method_count;
143   while (--i >= 0)
144     {
145       // FIXME: access checks.
146       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
147           && _Jv_equal (methods[i].signature, partial_sig, hash))
148         {
149           // Found it.  For getConstructor, the constructor must be
150           // public.
151           using namespace java::lang::reflect;
152           if (! Modifier::isPublic(methods[i].accflags))
153             break;
154           Constructor *cons = new Constructor ();
155           cons->offset = (char *) (&methods[i]) - (char *) methods;
156           cons->declaringClass = this;
157           return cons;
158         }
159     }
160   throw new java::lang::NoSuchMethodException;
161 }
162
163 JArray<java::lang::reflect::Constructor *> *
164 java::lang::Class::_getConstructors (jboolean declared)
165 {
166   // FIXME: this method needs access checks.
167
168   int numConstructors = 0;
169   int max = isPrimitive () ? 0 : method_count;
170   int i;
171   for (i = max; --i >= 0; )
172     {
173       _Jv_Method *method = &methods[i];
174       if (method->name == NULL
175           || ! _Jv_equalUtf8Consts (method->name, init_name))
176         continue;
177       if (! declared
178           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
179         continue;
180       numConstructors++;
181     }
182   JArray<java::lang::reflect::Constructor *> *result
183     = (JArray<java::lang::reflect::Constructor *> *)
184     JvNewObjectArray (numConstructors,
185                       &java::lang::reflect::Constructor::class$,
186                       NULL);
187   java::lang::reflect::Constructor** cptr = elements (result);
188   for (i = 0;  i < max;  i++)
189     {
190       _Jv_Method *method = &methods[i];
191       if (method->name == NULL
192           || ! _Jv_equalUtf8Consts (method->name, init_name))
193         continue;
194       if (! declared
195           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
196         continue;
197       java::lang::reflect::Constructor *cons
198         = new java::lang::reflect::Constructor ();
199       cons->offset = (char *) method - (char *) methods;
200       cons->declaringClass = this;
201       *cptr++ = cons;
202     }
203   return result;
204 }
205
206 java::lang::reflect::Constructor *
207 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
208 {
209   jstring partial_sig = getSignature (param_types, true);
210   jint hash = partial_sig->hashCode ();
211
212   int i = isPrimitive () ? 0 : method_count;
213   while (--i >= 0)
214     {
215       // FIXME: access checks.
216       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
217           && _Jv_equal (methods[i].signature, partial_sig, hash))
218         {
219           // Found it.
220           using namespace java::lang::reflect;
221           Constructor *cons = new Constructor ();
222           cons->offset = (char *) (&methods[i]) - (char *) methods;
223           cons->declaringClass = this;
224           return cons;
225         }
226     }
227   throw new java::lang::NoSuchMethodException;
228 }
229
230 java::lang::reflect::Field *
231 java::lang::Class::getField (jstring name, jint hash)
232 {
233   java::lang::reflect::Field* rfield;
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       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
240         continue;
241       rfield = new java::lang::reflect::Field ();
242       rfield->offset = (char*) field - (char*) fields;
243       rfield->declaringClass = this;
244       rfield->name = name;
245       return rfield;
246     }
247   jclass superclass = getSuperclass();
248   if (superclass == NULL)
249     return NULL;
250   rfield = superclass->getField(name, hash);
251   for (int i = 0; i < interface_count && rfield == NULL; ++i)
252     rfield = interfaces[i]->getField (name, hash);
253   return rfield;
254 }
255
256 java::lang::reflect::Field *
257 java::lang::Class::getDeclaredField (jstring name)
258 {
259   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
260   if (s != NULL)
261     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
262   int hash = name->hashCode();
263   for (int i = 0;  i < field_count;  i++)
264     {
265       _Jv_Field *field = &fields[i];
266       if (! _Jv_equal (field->name, name, hash))
267         continue;
268       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
269       rfield->offset = (char*) field - (char*) fields;
270       rfield->declaringClass = this;
271       rfield->name = name;
272       return rfield;
273     }
274   throw new java::lang::NoSuchFieldException (name);
275 }
276
277 JArray<java::lang::reflect::Field *> *
278 java::lang::Class::getDeclaredFields (void)
279 {
280   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
281   if (s != NULL)
282     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
283   JArray<java::lang::reflect::Field *> *result
284     = (JArray<java::lang::reflect::Field *> *)
285     JvNewObjectArray (field_count, &java::lang::reflect::Field::class$, NULL);
286   java::lang::reflect::Field** fptr = elements (result);
287   for (int i = 0;  i < field_count;  i++)
288     {
289       _Jv_Field *field = &fields[i];
290       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
291       rfield->offset = (char*) field - (char*) fields;
292       rfield->declaringClass = this;
293       *fptr++ = rfield;
294     }
295   return result;
296 }
297
298 void
299 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
300 {
301   if (isPrimitive())
302     buffer->append((jchar) method_count);
303   else
304     {
305       jstring name = getName();
306       if (name->charAt(0) != '[')
307         buffer->append((jchar) 'L');
308       buffer->append(name);
309       if (name->charAt(0) != '[')
310         buffer->append((jchar) ';');
311     }
312 }
313
314 // This doesn't have to be native.  It is an implementation detail
315 // only called from the C++ code, though, so maybe this is clearer.
316 jstring
317 java::lang::Class::getSignature (JArray<jclass> *param_types,
318                                  jboolean is_constructor)
319 {
320   java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
321   buf->append((jchar) '(');
322   // A NULL param_types means "no parameters".
323   if (param_types != NULL)
324     {
325       jclass *v = elements (param_types);
326       for (int i = 0; i < param_types->length; ++i)
327         v[i]->getSignature(buf);
328     }
329   buf->append((jchar) ')');
330   if (is_constructor)
331     buf->append((jchar) 'V');
332   return buf->toString();
333 }
334
335 java::lang::reflect::Method *
336 java::lang::Class::_getDeclaredMethod (jstring name,
337                                        JArray<jclass> *param_types)
338 {
339   jstring partial_sig = getSignature (param_types, false);
340   jint p_len = partial_sig->length();
341   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
342   int i = isPrimitive () ? 0 : method_count;
343   while (--i >= 0)
344     {
345       if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
346           && _Jv_equaln (methods[i].signature, partial_sig, p_len))
347         {
348           // Found it.
349           using namespace java::lang::reflect;
350           Method *rmethod = new Method ();
351           rmethod->offset = (char*) (&methods[i]) - (char*) methods;
352           rmethod->declaringClass = this;
353           return rmethod;
354         }
355     }
356   return NULL;
357 }
358
359 JArray<java::lang::reflect::Method *> *
360 java::lang::Class::getDeclaredMethods (void)
361 {
362   int numMethods = 0;
363   int max = isPrimitive () ? 0 : method_count;
364   int i;
365   for (i = max; --i >= 0; )
366     {
367       _Jv_Method *method = &methods[i];
368       if (method->name == NULL
369           || _Jv_equalUtf8Consts (method->name, clinit_name)
370           || _Jv_equalUtf8Consts (method->name, init_name)
371           || _Jv_equalUtf8Consts (method->name, finit_name))
372         continue;
373       numMethods++;
374     }
375   JArray<java::lang::reflect::Method *> *result
376     = (JArray<java::lang::reflect::Method *> *)
377     JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL);
378   java::lang::reflect::Method** mptr = elements (result);
379   for (i = 0;  i < max;  i++)
380     {
381       _Jv_Method *method = &methods[i];
382       if (method->name == NULL
383           || _Jv_equalUtf8Consts (method->name, clinit_name)
384           || _Jv_equalUtf8Consts (method->name, init_name)
385           || _Jv_equalUtf8Consts (method->name, finit_name))
386         continue;
387       java::lang::reflect::Method* rmethod
388         = new java::lang::reflect::Method ();
389       rmethod->offset = (char*) method - (char*) methods;
390       rmethod->declaringClass = this;
391       *mptr++ = rmethod;
392     }
393   return result;
394 }
395
396 jstring
397 java::lang::Class::getName (void)
398 {
399   char buffer[name->length + 1];  
400   memcpy (buffer, name->data, name->length); 
401   buffer[name->length] = '\0';
402   return _Jv_NewStringUTF (buffer);
403 }
404
405 JArray<jclass> *
406 java::lang::Class::getClasses (void)
407 {
408   // FIXME: security checking.
409
410   // Until we have inner classes, it always makes sense to return an
411   // empty array.
412   JArray<jclass> *result
413     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
414                                            NULL);
415   return result;
416 }
417
418 JArray<jclass> *
419 java::lang::Class::getDeclaredClasses (void)
420 {
421   checkMemberAccess (java::lang::reflect::Member::DECLARED);
422   // Until we have inner classes, it always makes sense to return an
423   // empty array.
424   JArray<jclass> *result
425     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
426                                            NULL);
427   return result;
428 }
429
430 jclass
431 java::lang::Class::getDeclaringClass (void)
432 {
433   // Until we have inner classes, it makes sense to always return
434   // NULL.
435   return NULL;
436 }
437
438 jint
439 java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
440                                jint offset)
441 {
442   int count = 0;
443   for (int i = 0;  i < field_count;  i++)
444     {
445       _Jv_Field *field = &fields[i];
446       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
447         continue;
448       ++count;
449
450       if (result != NULL)
451         {
452           java::lang::reflect::Field *rfield
453             = new java::lang::reflect::Field ();
454           rfield->offset = (char *) field - (char *) fields;
455           rfield->declaringClass = this;
456           rfield->name = _Jv_NewStringUtf8Const (field->name);
457           (elements (result))[offset++] = rfield;
458         }
459     }
460   jclass superclass = getSuperclass();
461   if (superclass != NULL)
462     {
463       int s_count = superclass->_getFields (result, offset);
464       count += s_count;
465       offset += s_count;
466     }
467   for (int i = 0; i < interface_count; ++i)
468     {
469       int f_count = interfaces[i]->_getFields (result, offset);
470       count += f_count;
471       offset += f_count;
472     }
473   return count;
474 }
475
476 JArray<java::lang::reflect::Field *> *
477 java::lang::Class::getFields (void)
478 {
479   // FIXME: security checking.
480
481   using namespace java::lang::reflect;
482
483   int count = _getFields (NULL, 0);
484
485   JArray<java::lang::reflect::Field *> *result
486     = ((JArray<java::lang::reflect::Field *> *)
487        JvNewObjectArray (count, &java::lang::reflect::Field::class$, NULL));
488
489   _getFields (result, 0);
490
491   return result;
492 }
493
494 JArray<jclass> *
495 java::lang::Class::getInterfaces (void)
496 {
497   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
498   jobject *data = elements (r);
499   for (int i = 0; i < interface_count; ++i)
500     data[i] = interfaces[i];
501   return reinterpret_cast<JArray<jclass> *> (r);
502 }
503
504 java::lang::reflect::Method *
505 java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types)
506 {
507   jstring partial_sig = getSignature (param_types, false);
508   jint p_len = partial_sig->length();
509   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
510   for (Class *klass = this; klass; klass = klass->getSuperclass())
511     {
512       int i = klass->isPrimitive () ? 0 : klass->method_count;
513       while (--i >= 0)
514         {
515           // FIXME: access checks.
516           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
517               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
518             {
519               // Found it.
520               using namespace java::lang::reflect;
521
522               // Method must be public.
523               if (! Modifier::isPublic (klass->methods[i].accflags))
524                 break;
525
526               Method *rmethod = new Method ();
527               rmethod->offset = ((char *) (&klass->methods[i])
528                                  - (char *) klass->methods);
529               rmethod->declaringClass = klass;
530               return rmethod;
531             }
532         }
533     }
534
535   // If we haven't found a match, and this class is an interface, then
536   // check all the superinterfaces.
537   if (isInterface())
538     {
539       for (int i = 0; i < interface_count; ++i)
540         {
541           using namespace java::lang::reflect;
542           Method *rmethod = interfaces[i]->_getMethod (name, param_types);
543           if (rmethod != NULL)
544             return rmethod;
545         }
546     }
547
548   return NULL;
549 }
550
551 // This is a very slow implementation, since it re-scans all the
552 // methods we've already listed to make sure we haven't duplicated a
553 // method.  It also over-estimates the required size, so we have to
554 // shrink the result array later.
555 jint
556 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
557                                 jint offset)
558 {
559   jint count = 0;
560
561   // First examine all local methods
562   for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
563     {
564       _Jv_Method *method = &methods[i];
565       if (method->name == NULL
566           || _Jv_equalUtf8Consts (method->name, clinit_name)
567           || _Jv_equalUtf8Consts (method->name, init_name)
568           || _Jv_equalUtf8Consts (method->name, finit_name))
569         continue;
570       // Only want public methods.
571       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
572         continue;
573
574       // This is where we over-count the slots required if we aren't
575       // filling the result for real.
576       if (result != NULL)
577         {
578           jboolean add = true;
579           java::lang::reflect::Method **mp = elements (result);
580           // If we already have a method with this name and signature,
581           // then ignore this one.  This can happen with virtual
582           // methods.
583           for (int j = 0; j < offset; ++j)
584             {
585               _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
586               if (_Jv_equalUtf8Consts (method->name, meth_2->name)
587                   && _Jv_equalUtf8Consts (method->signature,
588                                           meth_2->signature))
589                 {
590                   add = false;
591                   break;
592                 }
593             }
594           if (! add)
595             continue;
596         }
597
598       if (result != NULL)
599         {
600           using namespace java::lang::reflect;
601           Method *rmethod = new Method ();
602           rmethod->offset = (char *) method - (char *) methods;
603           rmethod->declaringClass = this;
604           Method **mp = elements (result);
605           mp[offset + count] = rmethod;
606         }
607       ++count;
608     }
609   offset += count;
610
611   // Now examine superclasses.
612   if (getSuperclass () != NULL)
613     {
614       jint s_count = getSuperclass()->_getMethods (result, offset);
615       offset += s_count;
616       count += s_count;
617     }
618
619   // Finally, examine interfaces.
620   for (int i = 0; i < interface_count; ++i)
621     {
622       int f_count = interfaces[i]->_getMethods (result, offset);
623       count += f_count;
624       offset += f_count;
625     }
626
627   return count;
628 }
629
630 JArray<java::lang::reflect::Method *> *
631 java::lang::Class::getMethods (void)
632 {
633   using namespace java::lang::reflect;
634
635   // FIXME: security checks.
636
637   // This will overestimate the size we need.
638   jint count = _getMethods (NULL, 0);
639
640   JArray<Method *> *result
641     = ((JArray<Method *> *) JvNewObjectArray (count,
642                                               &Method::class$,
643                                               NULL));
644
645   // When filling the array for real, we get the actual count.  Then
646   // we resize the array.
647   jint real_count = _getMethods (result, 0);
648
649   if (real_count != count)
650     {
651       JArray<Method *> *r2
652         = ((JArray<Method *> *) JvNewObjectArray (real_count,
653                                                   &Method::class$,
654                                                   NULL));
655       
656       Method **destp = elements (r2);
657       Method **srcp = elements (result);
658
659       for (int i = 0; i < real_count; ++i)
660         *destp++ = *srcp++;
661
662       result = r2;
663     }
664
665   return result;
666 }
667
668 jboolean
669 java::lang::Class::isAssignableFrom (jclass klass)
670 {
671   // Arguments may not have been initialized, given ".class" syntax.
672   _Jv_InitClass (this);
673   _Jv_InitClass (klass);
674   return _Jv_IsAssignableFrom (this, klass);
675 }
676
677 jboolean
678 java::lang::Class::isInstance (jobject obj)
679 {
680   if (! obj)
681     return false;
682   _Jv_InitClass (this);
683   return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
684 }
685
686 jobject
687 java::lang::Class::newInstance (void)
688 {
689   // FIXME: do accessibility checks here.  There currently doesn't
690   // seem to be any way to do these.
691   // FIXME: we special-case one check here just to pass a Plum Hall
692   // test.  Once access checking is implemented, remove this.
693   if (this == &java::lang::Class::class$)
694     throw new java::lang::IllegalAccessException;
695
696   if (isPrimitive ()
697       || isInterface ()
698       || isArray ()
699       || java::lang::reflect::Modifier::isAbstract(accflags))
700     throw new java::lang::InstantiationException;
701
702   _Jv_InitClass (this);
703
704   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
705   if (! meth)
706     throw new java::lang::NoSuchMethodException;
707
708   jobject r = JvAllocObject (this);
709   ((void (*) (jobject)) meth->ncode) (r);
710   return r;
711 }
712
713 void
714 java::lang::Class::finalize (void)
715 {
716 #ifdef INTERPRETER
717   JvAssert (_Jv_IsInterpretedClass (this));
718   _Jv_UnregisterClass (this);
719 #endif
720 }
721
722 // This implements the initialization process for a class.  From Spec
723 // section 12.4.2.
724 void
725 java::lang::Class::initializeClass (void)
726 {
727   // short-circuit to avoid needless locking.
728   if (state == JV_STATE_DONE)
729     return;
730
731   // Step 1.
732   _Jv_MonitorEnter (this);
733
734   if (state < JV_STATE_LINKED)
735     {    
736 #ifdef INTERPRETER
737       if (_Jv_IsInterpretedClass (this))
738         {
739           // this can throw exceptions, so exit the monitor as a precaution.
740           _Jv_MonitorExit (this);
741           java::lang::ClassLoader::resolveClass0 (this);
742           _Jv_MonitorEnter (this);
743         }
744       else
745 #endif
746         {
747           _Jv_PrepareCompiledClass (this);
748         }
749     }
750
751   if (state <= JV_STATE_LINKED)
752     _Jv_PrepareConstantTimeTables (this);
753
754   // Step 2.
755   java::lang::Thread *self = java::lang::Thread::currentThread();
756   // FIXME: `self' can be null at startup.  Hence this nasty trick.
757   self = (java::lang::Thread *) ((long) self | 1);
758   while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
759     wait ();
760
761   // Steps 3 &  4.
762   if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS)
763     {
764       _Jv_MonitorExit (this);
765       return;
766     }
767
768   // Step 5.
769   if (state == JV_STATE_ERROR)
770     {
771       _Jv_MonitorExit (this);
772       throw new java::lang::NoClassDefFoundError (getName());
773     }
774
775   // Step 6.
776   thread = self;
777   state = JV_STATE_IN_PROGRESS;
778   _Jv_MonitorExit (this);
779
780   // Step 7.
781   if (! isInterface () && superclass)
782     {
783       try
784         {
785           _Jv_InitClass (superclass);
786         }
787       catch (java::lang::Throwable *except)
788         {
789           // Caught an exception.
790           _Jv_MonitorEnter (this);
791           state = JV_STATE_ERROR;
792           notifyAll ();
793           _Jv_MonitorExit (this);
794           throw except;
795         }
796     }
797
798   // Steps 8, 9, 10, 11.
799   try
800     {
801       _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
802                                              void_signature);
803       if (meth)
804         ((void (*) (void)) meth->ncode) ();
805     }
806   catch (java::lang::Throwable *except)
807     {
808       if (! java::lang::Error::class$.isInstance(except))
809         {
810           try
811             {
812               except = new ExceptionInInitializerError (except);
813             }
814           catch (java::lang::Throwable *t)
815             {
816               except = t;
817             }
818         }
819       _Jv_MonitorEnter (this);
820       state = JV_STATE_ERROR;
821       notifyAll ();
822       _Jv_MonitorExit (this);
823       throw except;
824     }
825
826   _Jv_MonitorEnter (this);
827   state = JV_STATE_DONE;
828   notifyAll ();
829   _Jv_MonitorExit (this);
830 }
831
832 \f
833
834 //
835 // Some class-related convenience functions.
836 //
837
838 // Find a method declared in the class.  If it is not declared locally
839 // (or if it is inherited), return NULL.
840 _Jv_Method *
841 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
842                     _Jv_Utf8Const *signature)
843 {
844   for (int i = 0; i < klass->method_count; ++i)
845     {
846       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
847           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
848         return &klass->methods[i];
849     }
850   return NULL;
851 }
852
853 _Jv_Method *
854 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
855                           _Jv_Utf8Const *signature)
856 {
857   for (; klass; klass = klass->getSuperclass())
858     {
859       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
860
861       if (meth)
862         return meth;
863     }
864
865   return NULL;
866 }
867
868 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
869 #define MCACHE_SIZE 1023
870
871 struct _Jv_mcache
872 {
873   jclass klass;
874   _Jv_Method *method;
875 };
876
877 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
878
879 static void *
880 _Jv_FindMethodInCache (jclass klass,
881                        _Jv_Utf8Const *name,
882                        _Jv_Utf8Const *signature)
883 {
884   int index = name->hash & MCACHE_SIZE;
885   _Jv_mcache *mc = method_cache + index;
886   _Jv_Method *m = mc->method;
887
888   if (mc->klass == klass
889       && m != NULL             // thread safe check
890       && _Jv_equalUtf8Consts (m->name, name)
891       && _Jv_equalUtf8Consts (m->signature, signature))
892     return mc->method->ncode;
893   return NULL;
894 }
895
896 static void
897 _Jv_AddMethodToCache (jclass klass,
898                        _Jv_Method *method)
899 {
900   _Jv_MonitorEnter (&java::lang::Class::class$); 
901
902   int index = method->name->hash & MCACHE_SIZE;
903
904   method_cache[index].method = method;
905   method_cache[index].klass = klass;
906
907   _Jv_MonitorExit (&java::lang::Class::class$);
908 }
909
910 void *
911 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
912                            _Jv_Utf8Const *signature)
913 {
914   using namespace java::lang::reflect;
915
916   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
917   if (ncode != 0)
918     return ncode;
919
920   for (; klass; klass = klass->getSuperclass())
921     {
922       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
923       if (! meth)
924         continue;
925
926       if (Modifier::isStatic(meth->accflags))
927         throw new java::lang::IncompatibleClassChangeError
928           (_Jv_GetMethodString (klass, meth->name));
929       if (Modifier::isAbstract(meth->accflags))
930         throw new java::lang::AbstractMethodError
931           (_Jv_GetMethodString (klass, meth->name));
932       if (! Modifier::isPublic(meth->accflags))
933         throw new java::lang::IllegalAccessError
934           (_Jv_GetMethodString (klass, meth->name));
935
936       _Jv_AddMethodToCache (klass, meth);
937
938       return meth->ncode;
939     }
940   throw new java::lang::IncompatibleClassChangeError;
941 }
942
943 // Fast interface method lookup by index.
944 void *
945 _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
946 {
947   _Jv_IDispatchTable *cldt = klass->idt;
948   int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
949   return cldt->cls.itable[idx];
950 }
951
952 jboolean
953 _Jv_IsAssignableFrom (jclass target, jclass source)
954 {
955   if (source == target)
956     return true;
957      
958   // If target is array, so must source be.  
959   if (target->isArray ())
960     {
961       if (! source->isArray())
962         return false;
963       return _Jv_IsAssignableFrom(target->getComponentType(), 
964                                   source->getComponentType());
965     }
966
967   if (target->isInterface())
968     {
969       // Abstract classes have no IDT, and IDTs provide no way to check
970       // two interfaces for assignability.
971       if (__builtin_expect 
972           (source->idt == NULL || source->isInterface(), false))
973         return _Jv_InterfaceAssignableFrom (target, source);
974         
975       _Jv_IDispatchTable *cl_idt = source->idt;
976       _Jv_IDispatchTable *if_idt = target->idt;
977
978       if (__builtin_expect ((if_idt == NULL), false))
979         return false; // No class implementing TARGET has been loaded.    
980       jshort cl_iindex = cl_idt->cls.iindex;
981       if (cl_iindex < if_idt->iface.ioffsets[0])
982         {
983           jshort offset = if_idt->iface.ioffsets[cl_iindex];
984           if (offset != -1 && offset < cl_idt->cls.itable_length
985               && cl_idt->cls.itable[offset] == target)
986             return true;
987         }
988       return false;
989     }
990      
991   // Primitive TYPE classes are only assignable to themselves.
992   if (__builtin_expect (target->isPrimitive(), false))
993     return false;
994     
995   if (target == &java::lang::Object::class$)
996     {
997       if (source->isPrimitive())
998         return false;
999       return true;
1000     }
1001   else if (source->ancestors != NULL
1002            && target->ancestors != NULL
1003            && source->depth >= target->depth
1004            && source->ancestors[source->depth - target->depth] == target)
1005     return true;
1006       
1007   return false;
1008 }
1009
1010 // Interface type checking, the slow way. Returns TRUE if IFACE is a 
1011 // superinterface of SOURCE. This is used when SOURCE is also an interface,
1012 // or a class with no interface dispatch table.
1013 jboolean
1014 _Jv_InterfaceAssignableFrom (jclass iface, jclass source)
1015 {
1016   for (int i = 0; i < source->interface_count; i++)
1017     {
1018       jclass interface = source->interfaces[i];
1019       if (iface == interface
1020           || _Jv_InterfaceAssignableFrom (iface, interface))
1021         return true;      
1022     }
1023     
1024   if (!source->isInterface()
1025       && source->superclass 
1026       && _Jv_InterfaceAssignableFrom (iface, source->superclass))
1027     return true;
1028         
1029   return false;
1030 }
1031
1032 jboolean
1033 _Jv_IsInstanceOf(jobject obj, jclass cl)
1034 {
1035   if (__builtin_expect (!obj, false))
1036     return false;
1037   return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
1038 }
1039
1040 void *
1041 _Jv_CheckCast (jclass c, jobject obj)
1042 {
1043   if (__builtin_expect 
1044        (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
1045     throw new java::lang::ClassCastException
1046       ((new java::lang::StringBuffer
1047         (obj->getClass()->getName()))->append
1048        (JvNewStringUTF(" cannot be cast to "))->append
1049        (c->getName())->toString());
1050
1051   return obj;
1052 }
1053
1054 void
1055 _Jv_CheckArrayStore (jobject arr, jobject obj)
1056 {
1057   if (obj)
1058     {
1059       JvAssert (arr != NULL);
1060       jclass elt_class = (JV_CLASS (arr))->getComponentType();
1061       if (elt_class == &java::lang::Object::class$)
1062         return;
1063       jclass obj_class = JV_CLASS (obj);
1064       if (__builtin_expect 
1065           (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
1066         throw new java::lang::ArrayStoreException
1067                 ((new java::lang::StringBuffer
1068                  (JvNewStringUTF("Cannot store ")))->append
1069                  (obj_class->getName())->append
1070                  (JvNewStringUTF(" in array of type "))->append
1071                  (elt_class->getName())->toString());
1072     }
1073 }
1074
1075 #define INITIAL_IOFFSETS_LEN 4
1076 #define INITIAL_IFACES_LEN 4
1077
1078 static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
1079
1080 // Generate tables for constant-time assignment testing and interface
1081 // method lookup. This implements the technique described by Per Bothner
1082 // <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
1083 // http://gcc.gnu.org/ml/java/1999-q3/msg00377.html
1084 void 
1085 _Jv_PrepareConstantTimeTables (jclass klass)
1086 {  
1087   if (klass->isPrimitive () || klass->isInterface ())
1088     return;
1089   
1090   // Short-circuit in case we've been called already.
1091   if ((klass->idt != NULL) || klass->depth != 0)
1092     return;
1093
1094   // Calculate the class depth and ancestor table. The depth of a class 
1095   // is how many "extends" it is removed from Object. Thus the depth of 
1096   // java.lang.Object is 0, but the depth of java.io.FilterOutputStream 
1097   // is 2. Depth is defined for all regular and array classes, but not 
1098   // interfaces or primitive types.
1099    
1100   jclass klass0 = klass;
1101   jboolean has_interfaces = 0;
1102   while (klass0 != &java::lang::Object::class$)
1103     {
1104       has_interfaces += klass0->interface_count;
1105       klass0 = klass0->superclass;
1106       klass->depth++;
1107     }
1108
1109   // We do class member testing in constant time by using a small table 
1110   // of all the ancestor classes within each class. The first element is 
1111   // a pointer to the current class, and the rest are pointers to the 
1112   // classes ancestors, ordered from the current class down by decreasing 
1113   // depth. We do not include java.lang.Object in the table of ancestors, 
1114   // since it is redundant.
1115         
1116   klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
1117   klass0 = klass;
1118   for (int index = 0; index < klass->depth; index++)
1119     {
1120       klass->ancestors[index] = klass0;
1121       klass0 = klass0->superclass;
1122     }
1123     
1124   if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
1125     return;
1126   
1127   // Optimization: If class implements no interfaces, use a common
1128   // predefined interface table.
1129   if (!has_interfaces)
1130     {
1131       klass->idt = &null_idt;
1132       return;
1133     }
1134
1135   klass->idt = 
1136     (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1137     
1138   _Jv_ifaces ifaces;
1139
1140   ifaces.count = 0;
1141   ifaces.len = INITIAL_IFACES_LEN;
1142   ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
1143
1144   int itable_size = _Jv_GetInterfaces (klass, &ifaces);
1145
1146   if (ifaces.count > 0)
1147     {
1148       klass->idt->cls.itable = 
1149         (void **) _Jv_Malloc (itable_size * sizeof (void *));
1150       klass->idt->cls.itable_length = itable_size;
1151           
1152       jshort *itable_offsets = 
1153         (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
1154
1155       _Jv_GenerateITable (klass, &ifaces, itable_offsets);
1156
1157       jshort cls_iindex = 
1158         _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
1159
1160       for (int i=0; i < ifaces.count; i++)
1161         {
1162           ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
1163             itable_offsets[i];
1164         }
1165
1166       klass->idt->cls.iindex = cls_iindex;          
1167
1168       _Jv_Free (ifaces.list);
1169       _Jv_Free (itable_offsets);
1170     }
1171   else 
1172     {
1173       klass->idt->cls.iindex = SHRT_MAX;
1174     }
1175 }
1176
1177 // Return index of item in list, or -1 if item is not present.
1178 inline jshort
1179 _Jv_IndexOf (void *item, void **list, jshort list_len)
1180 {
1181   for (int i=0; i < list_len; i++)
1182     {
1183       if (list[i] == item)
1184         return i;
1185     }
1186   return -1;
1187 }
1188
1189 // Find all unique interfaces directly or indirectly implemented by klass.
1190 // Returns the size of the interface dispatch table (itable) for klass, which 
1191 // is the number of unique interfaces plus the total number of methods that 
1192 // those interfaces declare. May extend ifaces if required.
1193 jshort
1194 _Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
1195 {
1196   jshort result = 0;
1197   
1198   for (int i=0; i < klass->interface_count; i++)
1199     {
1200       jclass iface = klass->interfaces[i];
1201       if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
1202         {
1203           if (ifaces->count + 1 >= ifaces->len)
1204             {
1205               /* Resize ifaces list */
1206               ifaces->len = ifaces->len * 2;
1207               ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, 
1208                              ifaces->len * sizeof(jclass));
1209             }
1210           ifaces->list[ifaces->count] = iface;
1211           ifaces->count++;
1212
1213           result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
1214         }
1215     }
1216     
1217   if (klass->isInterface())
1218     {
1219       result += klass->method_count + 1;
1220     }
1221   else
1222     {
1223       if (klass->superclass)
1224         {
1225           result += _Jv_GetInterfaces (klass->superclass, ifaces);
1226         }
1227     }
1228   return result;
1229 }
1230
1231 // Fill out itable in klass, resolving method declarations in each ifaces.
1232 // itable_offsets is filled out with the position of each iface in itable,
1233 // such that itable[itable_offsets[n]] == ifaces.list[n].
1234 void
1235 _Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
1236 {
1237   void **itable = klass->idt->cls.itable;
1238   jshort itable_pos = 0;
1239
1240   for (int i=0; i < ifaces->count; i++)
1241     { 
1242       jclass iface = ifaces->list[i];
1243       itable_offsets[i] = itable_pos;
1244       itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos);
1245       
1246       /* Create interface dispatch table for iface */
1247       if (iface->idt == NULL)
1248         {
1249           iface->idt = 
1250             (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1251
1252           // The first element of ioffsets is its length (itself included).
1253           jshort *ioffsets = 
1254             (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
1255           ioffsets[0] = INITIAL_IOFFSETS_LEN;
1256           for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
1257             ioffsets[i] = -1;
1258
1259           iface->idt->iface.ioffsets = ioffsets;            
1260         }
1261     }
1262 }
1263
1264 // Format method name for use in error messages.
1265 jstring
1266 _Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
1267 {
1268   jstring r = JvNewStringUTF (klass->name->data);
1269   r = r->concat (JvNewStringUTF ("."));
1270   r = r->concat (JvNewStringUTF (name->data));
1271   return r;
1272 }
1273
1274 void 
1275 _Jv_ThrowNoSuchMethodError ()
1276 {
1277   throw new java::lang::NoSuchMethodError;
1278 }
1279
1280 // Each superinterface of a class (i.e. each interface that the class
1281 // directly or indirectly implements) has a corresponding "Partial
1282 // Interface Dispatch Table" whose size is (number of methods + 1) words.
1283 // The first word is a pointer to the interface (i.e. the java.lang.Class
1284 // instance for that interface).  The remaining words are pointers to the
1285 // actual methods that implement the methods declared in the interface,
1286 // in order of declaration.
1287 //
1288 // Append partial interface dispatch table for "iface" to "itable", at
1289 // position itable_pos.
1290 // Returns the offset at which the next partial ITable should be appended.
1291 jshort
1292 _Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, 
1293                          jshort pos)
1294 {
1295   using namespace java::lang::reflect;
1296
1297   itable[pos++] = (void *) iface;
1298   _Jv_Method *meth;
1299   
1300   for (int j=0; j < iface->method_count; j++)
1301     {
1302       meth = NULL;
1303       for (jclass cl = klass; cl; cl = cl->getSuperclass())
1304         {
1305           meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
1306                                      iface->methods[j].signature);
1307                  
1308           if (meth)
1309             break;
1310         }
1311
1312       if (meth && (meth->name->data[0] == '<'))
1313         {
1314           // leave a placeholder in the itable for hidden init methods.
1315           itable[pos] = NULL;   
1316         }
1317       else if (meth)
1318         {
1319           if (Modifier::isStatic(meth->accflags))
1320             throw new java::lang::IncompatibleClassChangeError
1321               (_Jv_GetMethodString (klass, meth->name));
1322           if (Modifier::isAbstract(meth->accflags))
1323             throw new java::lang::AbstractMethodError
1324               (_Jv_GetMethodString (klass, meth->name));
1325           if (! Modifier::isPublic(meth->accflags))
1326             throw new java::lang::IllegalAccessError
1327               (_Jv_GetMethodString (klass, meth->name));
1328
1329           itable[pos] = meth->ncode;
1330         }
1331       else
1332         {
1333           // The method doesn't exist in klass. Binary compatibility rules
1334           // permit this, so we delay the error until runtime using a pointer
1335           // to a method which throws an exception.
1336           itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
1337         }
1338       pos++;
1339     }
1340     
1341   return pos;
1342 }
1343
1344 static _Jv_Mutex_t iindex_mutex;
1345 bool iindex_mutex_initialized = false;
1346
1347 // We need to find the correct offset in the Class Interface Dispatch 
1348 // Table for a given interface. Once we have that, invoking an interface 
1349 // method just requires combining the Method's index in the interface 
1350 // (known at compile time) to get the correct method.  Doing a type test 
1351 // (cast or instanceof) is the same problem: Once we have a possible Partial 
1352 // Interface Dispatch Table, we just compare the first element to see if it 
1353 // matches the desired interface. So how can we find the correct offset?  
1354 // Our solution is to keep a vector of candiate offsets in each interface 
1355 // (idt->iface.ioffsets), and in each class we have an index 
1356 // (idt->cls.iindex) used to select the correct offset from ioffsets.
1357 //
1358 // Calculate and return iindex for a new class. 
1359 // ifaces is a vector of num interfaces that the class implements.
1360 // offsets[j] is the offset in the interface dispatch table for the
1361 // interface corresponding to ifaces[j].
1362 // May extend the interface ioffsets if required.
1363 jshort
1364 _Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
1365 {
1366   int i;
1367   int j;
1368   
1369   // Acquire a global lock to prevent itable corruption in case of multiple 
1370   // classes that implement an intersecting set of interfaces being linked
1371   // simultaneously. We can assume that the mutex will be initialized
1372   // single-threaded.
1373   if (! iindex_mutex_initialized)
1374     {
1375       _Jv_MutexInit (&iindex_mutex);
1376       iindex_mutex_initialized = true;
1377     }
1378   
1379   _Jv_MutexLock (&iindex_mutex);
1380   
1381   for (i=1;; i++)  /* each potential position in ioffsets */
1382     {
1383       for (j=0;; j++)  /* each iface */
1384         {
1385           if (j >= num)
1386             goto found;
1387           if (i >= ifaces[j]->idt->iface.ioffsets[0])
1388             continue;
1389           int ioffset = ifaces[j]->idt->iface.ioffsets[i];
1390           /* We can potentially share this position with another class. */
1391           if (ioffset >= 0 && ioffset != offsets[j])
1392             break; /* Nope. Try next i. */        
1393         }
1394     }
1395   found:
1396   for (j = 0; j < num; j++)
1397     {
1398       int len = ifaces[j]->idt->iface.ioffsets[0];
1399       if (i >= len) 
1400         {
1401           /* Resize ioffsets. */
1402           int newlen = 2 * len;
1403           if (i >= newlen)
1404             newlen = i + 3;
1405           jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
1406           jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, 
1407                                           newlen * sizeof(jshort));       
1408           new_ioffsets[0] = newlen;
1409
1410           while (len < newlen)
1411             new_ioffsets[len++] = -1;
1412           
1413           ifaces[j]->idt->iface.ioffsets = new_ioffsets;
1414         }
1415       ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
1416     }
1417
1418   _Jv_MutexUnlock (&iindex_mutex);
1419
1420   return i;
1421 }
1422
1423 // Only used by serialization
1424 java::lang::reflect::Field *
1425 java::lang::Class::getPrivateField (jstring name)
1426 {
1427   int hash = name->hashCode ();
1428
1429   java::lang::reflect::Field* rfield;
1430   for (int i = 0;  i < field_count;  i++)
1431     {
1432       _Jv_Field *field = &fields[i];
1433       if (! _Jv_equal (field->name, name, hash))
1434         continue;
1435       rfield = new java::lang::reflect::Field ();
1436       rfield->offset = (char*) field - (char*) fields;
1437       rfield->declaringClass = this;
1438       rfield->name = name;
1439       return rfield;
1440     }
1441   jclass superclass = getSuperclass();
1442   if (superclass == NULL)
1443     return NULL;
1444   rfield = superclass->getPrivateField(name);
1445   for (int i = 0; i < interface_count && rfield == NULL; ++i)
1446     rfield = interfaces[i]->getPrivateField (name);
1447   return rfield;
1448 }
1449
1450 // Only used by serialization
1451 java::lang::reflect::Method *
1452 java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
1453 {
1454   jstring partial_sig = getSignature (param_types, false);
1455   jint p_len = partial_sig->length();
1456   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
1457   for (Class *klass = this; klass; klass = klass->getSuperclass())
1458     {
1459       int i = klass->isPrimitive () ? 0 : klass->method_count;
1460       while (--i >= 0)
1461         {
1462           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1463               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
1464             {
1465               // Found it.
1466               using namespace java::lang::reflect;
1467
1468               Method *rmethod = new Method ();
1469               rmethod->offset = ((char *) (&klass->methods[i])
1470                                  - (char *) klass->methods);
1471               rmethod->declaringClass = klass;
1472               return rmethod;
1473             }
1474         }
1475     }
1476   throw new java::lang::NoSuchMethodException;
1477 }
1478
1479 // Private accessor method for Java code to retrieve the protection domain.
1480 java::security::ProtectionDomain *
1481 java::lang::Class::getProtectionDomain0 ()
1482 {
1483   return protectionDomain;
1484 }
1485
1486 // Functions for indirect dispatch (symbolic virtual method binding) support.
1487
1488 // Resolve entries in the virtual method offset symbol table 
1489 // (klass->otable_syms). The vtable offset (in bytes) for each resolved method 
1490 // is placed at the corresponding position in the virtual method offset table 
1491 // (klass->otable). A single otable and otable_syms pair may be shared by many 
1492 // classes.
1493 void
1494 _Jv_LinkOffsetTable(jclass klass)
1495 {
1496   //// FIXME: Need to lock the otable ////
1497   
1498   if (klass->otable == NULL
1499       || klass->otable->state != 0)
1500     return;
1501   
1502   klass->otable->state = 1;
1503
1504   int index = 0;
1505   _Jv_MethodSymbol sym = klass->otable_syms[0];
1506
1507   while (sym.name != NULL)
1508     {
1509       jclass target_class = _Jv_FindClass (sym.class_name, NULL);
1510       _Jv_Method *meth = NULL;            
1511       
1512       if (target_class != NULL)
1513         if (target_class->isInterface())
1514           {
1515             // FIXME: This does not yet fully conform to binary compatibility
1516             // rules. It will break if a declaration is moved into a 
1517             // superinterface.
1518             for (int i=0; i < target_class->method_count; i++)
1519               {
1520                 meth = &target_class->methods[i];
1521                 if (_Jv_equalUtf8Consts (sym.name, meth->name)
1522                     && _Jv_equalUtf8Consts (sym.signature, meth->signature))
1523                   {
1524                     klass->otable->offsets[index] = i + 1;
1525                     break;
1526                   }
1527               }
1528           }
1529         else
1530           {
1531             // If the target class does not have a vtable_method_count yet, 
1532             // then we can't tell the offsets for its methods, so we must lay 
1533             // it out now.
1534             if (target_class->vtable_method_count == -1)
1535               {
1536                 JvSynchronize sync (target_class);
1537                 _Jv_LayoutVTableMethods (target_class);
1538               }
1539
1540             meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
1541                                             sym.signature);
1542
1543             if (meth != NULL)
1544               {
1545                 klass->otable->offsets[index] = 
1546                   _Jv_VTable::idx_to_offset (meth->index);
1547               }
1548           }
1549
1550       if (meth == NULL)
1551         // FIXME: This should be special index for ThrowNoSuchMethod().
1552         klass->otable->offsets[index] = -1;
1553
1554       sym = klass->otable_syms[++index];
1555     }
1556 }
1557
1558 // Returns true if METH should get an entry in a VTable.
1559 static bool
1560 isVirtualMethod (_Jv_Method *meth)
1561 {
1562   using namespace java::lang::reflect;
1563   return (((meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) == 0)
1564           && meth->name->data[0] != '<');
1565 }
1566
1567 // Prepare virtual method declarations in KLASS, and any superclasses as 
1568 // required, by determining their vtable index, setting method->index, and
1569 // finally setting the class's vtable_method_count. Must be called with the
1570 // lock for KLASS held.
1571 void
1572 _Jv_LayoutVTableMethods (jclass klass)
1573 {
1574   if (klass->vtable != NULL || klass->isInterface() 
1575       || klass->vtable_method_count != -1)
1576     return;
1577     
1578   jclass superclass = klass->superclass;
1579
1580   if (superclass != NULL && superclass->vtable_method_count == -1)
1581     {
1582       JvSynchronize sync (superclass);
1583       _Jv_LayoutVTableMethods (superclass);
1584     }
1585     
1586   int index = (superclass == NULL ? 0 : superclass->vtable_method_count);
1587
1588   for (int i = 0; i < klass->method_count; ++i)
1589     {
1590       _Jv_Method *meth = &klass->methods[i];
1591       _Jv_Method *super_meth = NULL;
1592     
1593       if (!isVirtualMethod(meth))
1594         continue;
1595               
1596       if (superclass != NULL)
1597         super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, 
1598                                                meth->signature);
1599       
1600       if (super_meth)
1601         meth->index = super_meth->index;
1602       else
1603         meth->index = index++;
1604     }
1605   
1606   klass->vtable_method_count = index;
1607 }
1608
1609 // Set entries in VTABLE for virtual methods declared in KLASS. If KLASS has
1610 // an immediate abstract parent, recursivly do its methods first.
1611 void
1612 _Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable)
1613 {
1614   using namespace java::lang::reflect;
1615
1616   jclass superclass = klass->getSuperclass();
1617
1618   if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
1619     _Jv_SetVTableEntries (superclass, vtable);
1620     
1621   for (int i = klass->method_count - 1; i >= 0; i--)
1622     {
1623       _Jv_Method *meth = &klass->methods[i];
1624       if (!isVirtualMethod(meth))
1625         continue;
1626       vtable->set_method(meth->index, meth->ncode);
1627     }
1628 }
1629
1630 // Allocate and lay out the virtual method table for KLASS. This will also
1631 // cause vtables to be generated for any non-abstract superclasses, and
1632 // virtual method layout to occur for any abstract superclasses. Must be
1633 // called with monitor lock for KLASS held.
1634 void
1635 _Jv_MakeVTable (jclass klass)
1636 {
1637   using namespace java::lang::reflect;  
1638
1639   if (klass->vtable != NULL || klass->isInterface() 
1640       || (klass->accflags & Modifier::ABSTRACT))
1641     return;
1642   
1643   //  out before we can create a vtable. 
1644   if (klass->vtable_method_count == -1)
1645     _Jv_LayoutVTableMethods (klass);
1646
1647   // Allocate the new vtable.
1648   _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
1649   klass->vtable = vtable;
1650   
1651   // Copy the vtable of the closest non-abstract superclass.
1652   jclass superclass = klass->superclass;
1653   if (superclass != NULL)
1654     {
1655       while ((superclass->accflags & Modifier::ABSTRACT) != 0)
1656         superclass = superclass->superclass;
1657
1658       if (superclass->vtable == NULL)
1659         {
1660           JvSynchronize sync (superclass);
1661           _Jv_MakeVTable (superclass);
1662         }
1663
1664       for (int i = 0; i < superclass->vtable_method_count; ++i)
1665         vtable->set_method (i, superclass->vtable->get_method (i));
1666     }
1667
1668   // Set the class pointer and GC descriptor.
1669   vtable->clas = klass;
1670   vtable->gc_descr = _Jv_BuildGCDescr (klass);
1671
1672   // For each virtual declared in klass and any immediate abstract 
1673   // superclasses, set new vtable entry or override an old one.
1674   _Jv_SetVTableEntries (klass, vtable);
1675 }