OSDN Git Service

8362dcc079e25d82a178a1a92bb5b12248294ad8
[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  Cygnus Solutions
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 <stdlib.h>
14 #include <string.h>
15
16 #pragma implementation "Class.h"
17
18 #include <gcj/cni.h>
19 #include <jvm.h>
20 #include <java/lang/Class.h>
21 #include <java/lang/ClassLoader.h>
22 #include <java/lang/String.h>
23 #include <java/lang/reflect/Modifier.h>
24 #include <java/lang/reflect/Member.h>
25 #include <java/lang/reflect/Method.h>
26 #include <java/lang/reflect/Field.h>
27 #include <java/lang/reflect/Constructor.h>
28 #include <java/lang/AbstractMethodError.h>
29 #include <java/lang/ClassNotFoundException.h>
30 #include <java/lang/IllegalAccessException.h>
31 #include <java/lang/IllegalAccessError.h>
32 #include <java/lang/IncompatibleClassChangeError.h>
33 #include <java/lang/InstantiationException.h>
34 #include <java/lang/NoClassDefFoundError.h>
35 #include <java/lang/NoSuchFieldException.h>
36 #include <java/lang/NoSuchMethodException.h>
37 #include <java/lang/Thread.h>
38 #include <java/lang/NullPointerException.h>
39 #include <java/lang/System.h>
40 #include <java/lang/SecurityManager.h>
41 #include <java/lang/StringBuffer.h>
42
43 #include <java-cpool.h>
44
45 \f
46
47 #define CloneableClass _CL_Q34java4lang9Cloneable
48 extern java::lang::Class CloneableClass;
49 #define ObjectClass _CL_Q34java4lang6Object
50 extern java::lang::Class ObjectClass;
51 #define ErrorClass _CL_Q34java4lang5Error
52 extern java::lang::Class ErrorClass;
53 #define ClassClass _CL_Q34java4lang5Class
54 extern java::lang::Class ClassClass;
55 #define MethodClass _CL_Q44java4lang7reflect6Method
56 extern java::lang::Class MethodClass;
57 #define FieldClass _CL_Q44java4lang7reflect5Field
58 extern java::lang::Class FieldClass;
59 #define ConstructorClass _CL_Q44java4lang7reflect11Constructor
60 extern java::lang::Class ConstructorClass;
61
62 // Some constants we use to look up the class initializer.
63 static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
64 static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
65 static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
66 static _Jv_Utf8Const *finit_name = _Jv_makeUtf8Const ("$finit$", 7);
67
68 \f
69
70 jclass
71 java::lang::Class::forName (jstring className)
72 {
73   if (! className)
74     JvThrow (new java::lang::NullPointerException);
75
76 #if 0
77   // FIXME: should check syntax of CLASSNAME and throw
78   // IllegalArgumentException on failure.
79
80   // FIXME: should use class loader from calling method.
81   jclass klass = _Jv_FindClass (className, NULL);
82 #else
83   jsize length = _Jv_GetStringUTFLength (className);
84   char buffer[length];
85   _Jv_GetStringUTFRegion (className, 0, length, buffer);
86
87   // FIXME: should check syntax of CLASSNAME and throw
88   // IllegalArgumentException on failure.
89   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
90
91   // FIXME: should use class loader from calling method.
92   jclass klass = (buffer[0] == '[' 
93                   ? _Jv_FindClassFromSignature (name->data, NULL)
94                   : _Jv_FindClass (name, NULL));
95 #endif
96   if (! klass)
97     JvThrow (new java::lang::ClassNotFoundException (className));
98
99   return klass;
100 }
101
102 java::lang::reflect::Constructor *
103 java::lang::Class::getConstructor (JArray<jclass> *param_types)
104 {
105   jstring partial_sig = getSignature (param_types, true);
106   jint hash = partial_sig->hashCode ();
107
108   int i = isPrimitive () ? 0 : method_count;
109   while (--i >= 0)
110     {
111       // FIXME: access checks.
112       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
113           && _Jv_equal (methods[i].signature, partial_sig, hash))
114         {
115           // Found it.  For getConstructor, the constructor must be
116           // public.
117           using namespace java::lang::reflect;
118           if (! Modifier::isPublic(methods[i].accflags))
119             break;
120           Constructor *cons = new Constructor ();
121           cons->offset = (char *) (&methods[i]) - (char *) methods;
122           cons->declaringClass = this;
123           return cons;
124         }
125     }
126   JvThrow (new java::lang::NoSuchMethodException);
127 }
128
129 JArray<java::lang::reflect::Constructor *> *
130 java::lang::Class::_getConstructors (jboolean declared)
131 {
132   // FIXME: this method needs access checks.
133
134   int numConstructors = 0;
135   int max = isPrimitive () ? 0 : method_count;
136   int i;
137   for (i = max; --i >= 0; )
138     {
139       _Jv_Method *method = &methods[i];
140       if (method->name == NULL
141           && ! _Jv_equalUtf8Consts (method->name, init_name))
142         continue;
143       if (! declared
144           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
145         continue;
146       numConstructors++;
147     }
148   JArray<java::lang::reflect::Constructor *> *result
149     = (JArray<java::lang::reflect::Constructor *> *)
150     JvNewObjectArray (numConstructors, &ConstructorClass, NULL);
151   java::lang::reflect::Constructor** cptr = elements (result);
152   for (i = 0;  i < max;  i++)
153     {
154       _Jv_Method *method = &methods[i];
155       if (method->name == NULL
156           && ! _Jv_equalUtf8Consts (method->name, init_name))
157         continue;
158       if (! declared
159           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
160         continue;
161       java::lang::reflect::Constructor *cons
162         = new java::lang::reflect::Constructor ();
163       cons->offset = (char *) method - (char *) methods;
164       cons->declaringClass = this;
165       *cptr++ = cons;
166     }
167   return result;
168 }
169
170 java::lang::reflect::Constructor *
171 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
172 {
173   jstring partial_sig = getSignature (param_types, true);
174   jint hash = partial_sig->hashCode ();
175
176   int i = isPrimitive () ? 0 : method_count;
177   while (--i >= 0)
178     {
179       // FIXME: access checks.
180       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
181           && _Jv_equal (methods[i].signature, partial_sig, hash))
182         {
183           // Found it.
184           using namespace java::lang::reflect;
185           Constructor *cons = new Constructor ();
186           cons->offset = (char *) (&methods[i]) - (char *) methods;
187           cons->declaringClass = this;
188           return cons;
189         }
190     }
191   JvThrow (new java::lang::NoSuchMethodException);
192 }
193
194 java::lang::reflect::Field *
195 java::lang::Class::getField (jstring name, jint hash)
196 {
197   java::lang::reflect::Field* rfield;
198   for (int i = 0;  i < field_count;  i++)
199     {
200       _Jv_Field *field = &fields[i];
201       if (! _Jv_equal (field->name, name, hash))
202         continue;
203       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
204         continue;
205       rfield = new java::lang::reflect::Field ();
206       rfield->offset = (char*) field - (char*) fields;
207       rfield->declaringClass = this;
208       rfield->name = name;
209       return rfield;
210     }
211   jclass superclass = getSuperclass();
212   if (superclass == NULL)
213     return NULL;
214   rfield = superclass->getField(name, hash);
215   for (int i = 0; i < interface_count && rfield == NULL; ++i)
216     rfield = interfaces[i]->getField (name, hash);
217   return rfield;
218 }
219
220 java::lang::reflect::Field *
221 java::lang::Class::getDeclaredField (jstring name)
222 {
223   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
224   if (s != NULL)
225     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
226   int hash = name->hashCode();
227   for (int i = 0;  i < field_count;  i++)
228     {
229       _Jv_Field *field = &fields[i];
230       if (! _Jv_equal (field->name, name, hash))
231         continue;
232       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
233       rfield->offset = (char*) field - (char*) fields;
234       rfield->declaringClass = this;
235       rfield->name = name;
236       return rfield;
237     }
238   JvThrow (new java::lang::NoSuchFieldException (name));
239 }
240
241 JArray<java::lang::reflect::Field *> *
242 java::lang::Class::getDeclaredFields (void)
243 {
244   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
245   if (s != NULL)
246     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
247   JArray<java::lang::reflect::Field *> *result
248     = (JArray<java::lang::reflect::Field *> *)
249     JvNewObjectArray (field_count, &FieldClass, NULL);
250   java::lang::reflect::Field** fptr = elements (result);
251   for (int i = 0;  i < field_count;  i++)
252     {
253       _Jv_Field *field = &fields[i];
254       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
255       rfield->offset = (char*) field - (char*) fields;
256       rfield->declaringClass = this;
257       *fptr++ = rfield;
258     }
259   return result;
260 }
261
262 void
263 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
264 {
265   if (isPrimitive())
266     buffer->append((jchar) method_count);
267   else
268     {
269       jstring name = getName();
270       if (name->charAt(0) != '[')
271         buffer->append((jchar) 'L');
272       buffer->append(name);
273       if (name->charAt(0) != '[')
274         buffer->append((jchar) ';');
275     }
276 }
277
278 // This doesn't have to be native.  It is an implementation detail
279 // only called from the C++ code, though, so maybe this is clearer.
280 jstring
281 java::lang::Class::getSignature (JArray<jclass> *param_types,
282                                  jboolean is_constructor)
283 {
284   java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
285   buf->append((jchar) '(');
286   jclass *v = elements (param_types);
287   for (int i = 0; i < param_types->length; ++i)
288     v[i]->getSignature(buf);
289   buf->append((jchar) ')');
290   if (is_constructor)
291     buf->append((jchar) 'V');
292   return buf->toString();
293 }
294
295 java::lang::reflect::Method *
296 java::lang::Class::getDeclaredMethod (jstring name,
297                                       JArray<jclass> *param_types)
298 {
299   jstring partial_sig = getSignature (param_types, false);
300   jint p_len = partial_sig->length();
301   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
302   int i = isPrimitive () ? 0 : method_count;
303   while (--i >= 0)
304     {
305       // FIXME: access checks.
306       if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
307           && _Jv_equaln (methods[i].signature, partial_sig, p_len))
308         {
309           // Found it.
310           using namespace java::lang::reflect;
311           Method *rmethod = new Method ();
312           rmethod->offset = (char*) (&methods[i]) - (char*) methods;
313           rmethod->declaringClass = this;
314           return rmethod;
315         }
316     }
317   JvThrow (new java::lang::NoSuchMethodException);
318 }
319
320 JArray<java::lang::reflect::Method *> *
321 java::lang::Class::getDeclaredMethods (void)
322 {
323   int numMethods = 0;
324   int max = isPrimitive () ? 0 : method_count;
325   int i;
326   for (i = max; --i >= 0; )
327     {
328       _Jv_Method *method = &methods[i];
329       if (method->name == NULL
330           || _Jv_equalUtf8Consts (method->name, clinit_name)
331           || _Jv_equalUtf8Consts (method->name, init_name)
332           || _Jv_equalUtf8Consts (method->name, finit_name))
333         continue;
334       numMethods++;
335     }
336   JArray<java::lang::reflect::Method *> *result
337     = (JArray<java::lang::reflect::Method *> *)
338     JvNewObjectArray (numMethods, &MethodClass, NULL);
339   java::lang::reflect::Method** mptr = elements (result);
340   for (i = 0;  i < max;  i++)
341     {
342       _Jv_Method *method = &methods[i];
343       if (method->name == NULL
344           || _Jv_equalUtf8Consts (method->name, clinit_name)
345           || _Jv_equalUtf8Consts (method->name, init_name)
346           || _Jv_equalUtf8Consts (method->name, finit_name))
347         continue;
348       java::lang::reflect::Method* rmethod
349         = new java::lang::reflect::Method ();
350       rmethod->offset = (char*) method - (char*) methods;
351       rmethod->declaringClass = this;
352       *mptr++ = rmethod;
353     }
354   return result;
355 }
356
357 jstring
358 java::lang::Class::getName (void)
359 {
360   char buffer[name->length + 1];  
361   memcpy (buffer, name->data, name->length); 
362   buffer[name->length] = '\0';
363   return _Jv_NewStringUTF (buffer);
364 }
365
366 JArray<jclass> *
367 java::lang::Class::getClasses (void)
368 {
369   // FIXME: implement.
370   return NULL;
371 }
372
373 JArray<jclass> *
374 java::lang::Class::getDeclaredClasses (void)
375 {
376   checkMemberAccess (java::lang::reflect::Member::DECLARED);
377   // Until we have inner classes, it always makes sense to return an
378   // empty array.
379   JArray<jclass> *result
380     = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
381   return result;
382 }
383
384 jclass
385 java::lang::Class::getDeclaringClass (void)
386 {
387   // Until we have inner classes, it makes sense to always return
388   // NULL.
389   return NULL;
390 }
391
392 jint
393 java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
394                                jint offset)
395 {
396   int count = 0;
397   for (int i = 0;  i < field_count;  i++)
398     {
399       _Jv_Field *field = &fields[i];
400       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
401         continue;
402       ++count;
403
404       if (result != NULL)
405         {
406           java::lang::reflect::Field *rfield
407             = new java::lang::reflect::Field ();
408           rfield->offset = (char *) field - (char *) fields;
409           rfield->declaringClass = this;
410           rfield->name = _Jv_NewStringUtf8Const (field->name);
411           (elements (result))[offset + i] = rfield;
412         }
413     }
414   jclass superclass = getSuperclass();
415   if (superclass != NULL)
416     {
417       int s_count = superclass->_getFields (result, offset);
418       count += s_count;
419       offset += s_count;
420     }
421   for (int i = 0; i < interface_count; ++i)
422     {
423       int f_count = interfaces[i]->_getFields (result, offset);
424       count += f_count;
425       offset += f_count;
426     }
427   return count;
428 }
429
430 JArray<java::lang::reflect::Field *> *
431 java::lang::Class::getFields (void)
432 {
433   using namespace java::lang::reflect;
434
435   int count = _getFields (NULL, 0);
436
437   JArray<java::lang::reflect::Field *> *result
438     = ((JArray<java::lang::reflect::Field *> *)
439        JvNewObjectArray (count, &FieldClass, NULL));
440
441   _getFields (result, 0);
442
443   return result;
444 }
445
446 JArray<jclass> *
447 java::lang::Class::getInterfaces (void)
448 {
449   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
450   jobject *data = elements (r);
451   for (int i = 0; i < interface_count; ++i)
452     data[i] = interfaces[i];
453   return reinterpret_cast<JArray<jclass> *> (r);
454 }
455
456 java::lang::reflect::Method *
457 java::lang::Class::getMethod (jstring name, JArray<jclass> *param_types)
458 {
459   jstring partial_sig = getSignature (param_types, false);
460   jint p_len = partial_sig->length();
461   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
462   for (Class *klass = this; klass; klass = klass->getSuperclass())
463     {
464       int i = klass->isPrimitive () ? 0 : klass->method_count;
465       while (--i >= 0)
466         {
467           // FIXME: access checks.
468           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
469               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
470             {
471               // Found it.
472               using namespace java::lang::reflect;
473
474               // Method must be public.
475               if (! Modifier::isPublic (methods[i].accflags))
476                 break;
477
478               Method *rmethod = new Method ();
479               rmethod->offset = (char*) (&klass->methods[i]) - (char*) methods;
480               rmethod->declaringClass = klass;
481               return rmethod;
482             }
483         }
484     }
485   JvThrow (new java::lang::NoSuchMethodException);
486 }
487
488 // This is a very slow implementation, since it re-scans all the
489 // methods we've already listed to make sure we haven't duplicated a
490 // method.  It also over-estimates the required size, so we have to
491 // shrink the result array later.
492 jint
493 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
494                                 jint offset)
495 {
496   jint count = 0;
497
498   // First examine all local methods
499   for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
500     {
501       _Jv_Method *method = &methods[i];
502       if (method->name == NULL
503           || _Jv_equalUtf8Consts (method->name, clinit_name)
504           || _Jv_equalUtf8Consts (method->name, init_name)
505           || _Jv_equalUtf8Consts (method->name, finit_name))
506         continue;
507       // Only want public methods.
508       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
509         continue;
510
511       // This is where we over-count the slots required if we aren't
512       // filling the result for real.
513       if (result != NULL)
514         {
515           jboolean add = true;
516           java::lang::reflect::Method **mp = elements (result);
517           // If we already have a method with this name and signature,
518           // then ignore this one.  This can happen with virtual
519           // methods.
520           for (int j = 0; j < offset; ++j)
521             {
522               _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
523               if (_Jv_equalUtf8Consts (method->name, meth_2->name)
524                   && _Jv_equalUtf8Consts (method->signature,
525                                           meth_2->signature))
526                 {
527                   add = false;
528                   break;
529                 }
530             }
531           if (! add)
532             continue;
533         }
534
535       if (result != NULL)
536         {
537           using namespace java::lang::reflect;
538           Method *rmethod = new Method ();
539           rmethod->offset = (char *) method - (char *) methods;
540           rmethod->declaringClass = this;
541           Method **mp = elements (result);
542           mp[offset + count] = rmethod;
543         }
544       ++count;
545     }
546   offset += count;
547
548   // Now examine superclasses.
549   if (getSuperclass () != NULL)
550     {
551       jint s_count = getSuperclass()->_getMethods (result, offset);
552       offset += s_count;
553       count += s_count;
554     }
555
556   // Finally, examine interfaces.
557   for (int i = 0; i < interface_count; ++i)
558     {
559       int f_count = interfaces[i]->_getMethods (result, offset);
560       count += f_count;
561       offset += f_count;
562     }
563
564   return count;
565 }
566
567 JArray<java::lang::reflect::Method *> *
568 java::lang::Class::getMethods (void)
569 {
570   using namespace java::lang::reflect;
571
572   // FIXME: security checks.
573
574   // This will overestimate the size we need.
575   jint count = _getMethods (NULL, 0);
576
577   JArray<Method *> *result
578     = ((JArray<Method *> *) JvNewObjectArray (count, &MethodClass, NULL));
579
580   // When filling the array for real, we get the actual count.  Then
581   // we resize the array.
582   jint real_count = _getMethods (result, 0);
583
584   if (real_count != count)
585     {
586       JArray<Method *> *r2
587         = ((JArray<Method *> *) JvNewObjectArray (real_count, &MethodClass,
588                                                   NULL));
589       
590       Method **destp = elements (r2);
591       Method **srcp = elements (result);
592
593       for (int i = 0; i < real_count; ++i)
594         *destp++ = *srcp++;
595
596       result = r2;
597     }
598
599   return result;
600 }
601
602 jboolean
603 java::lang::Class::isAssignableFrom (jclass klass)
604 {
605   if (this == klass)
606     return true;
607   // Primitive types must be equal, which we just tested for.
608   if (isPrimitive () || ! klass || klass->isPrimitive())
609     return false;
610
611   // If target is array, so must source be.
612   if (isArray ())
613     {
614       if (! klass->isArray())
615         return false;
616       return getComponentType()->isAssignableFrom(klass->getComponentType());
617     }
618
619   if (isAssignableFrom (klass->getSuperclass()))
620     return true;
621
622   if (isInterface())
623     {
624       // See if source implements this interface.
625       for (int i = 0; i < klass->interface_count; ++i)
626         {
627           jclass interface = klass->interfaces[i];
628           // FIXME: ensure that class is prepared here.
629           // See Spec 12.3.2.
630           if (isAssignableFrom (interface))
631             return true;
632         }
633     }
634
635   return false;
636 }
637
638 jboolean
639 java::lang::Class::isInstance (jobject obj)
640 {
641   if (! obj || isPrimitive ())
642     return false;
643   return isAssignableFrom (obj->getClass());
644 }
645
646 jboolean
647 java::lang::Class::isInterface (void)
648 {
649   return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
650 }
651
652 jobject
653 java::lang::Class::newInstance (void)
654 {
655   // FIXME: do accessibility checks here.  There currently doesn't
656   // seem to be any way to do these.
657   // FIXME: we special-case one check here just to pass a Plum Hall
658   // test.  Once access checking is implemented, remove this.
659   if (this == &ClassClass)
660     JvThrow (new java::lang::IllegalAccessException);
661
662   if (isPrimitive ()
663       || isInterface ()
664       || isArray ()
665       || java::lang::reflect::Modifier::isAbstract(accflags))
666     JvThrow (new java::lang::InstantiationException);
667
668   _Jv_InitClass (this);
669
670   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
671   if (! meth)
672     JvThrow (new java::lang::NoSuchMethodException);
673
674   jobject r = JvAllocObject (this);
675   ((void (*) (jobject)) meth->ncode) (r);
676   return r;
677 }
678
679 void
680 java::lang::Class::finalize (void)
681 {
682 #ifdef INTERPRETER
683   JvAssert (_Jv_IsInterpretedClass (this));
684   _Jv_UnregisterClass (this);
685 #endif
686 }
687
688 // FIXME.
689 void
690 java::lang::Class::hackRunInitializers (void)
691 {
692   _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, void_signature);
693   if (meth)
694     ((void (*) (void)) meth->ncode) ();
695 }
696
697 // This implements the initialization process for a class.  From Spec
698 // section 12.4.2.
699 void
700 java::lang::Class::initializeClass (void)
701 {
702   // Short-circuit to avoid needless locking.
703   if (state == JV_STATE_DONE)
704     return;
705
706   // do this before we enter the monitor below, since this can cause
707   // exceptions.  Here we assume, that reading "state" is an atomic
708   // operation, I pressume that is true? --Kresten
709   if (state < JV_STATE_LINKED)
710     {
711 #ifdef INTERPRETER
712       if (_Jv_IsInterpretedClass (this))
713         {
714           java::lang::ClassLoader::resolveClass0 (this);
715
716           // Step 1.
717           _Jv_MonitorEnter (this);
718         }
719       else
720 #endif
721         {
722           // Step 1.
723           _Jv_MonitorEnter (this);
724           _Jv_PrepareCompiledClass (this);
725         }
726     }
727   else
728     {
729       // Step 1.
730       _Jv_MonitorEnter (this);
731     }
732
733   // Step 2.
734   java::lang::Thread *self = java::lang::Thread::currentThread();
735   // FIXME: `self' can be null at startup.  Hence this nasty trick.
736   self = (java::lang::Thread *) ((long) self | 1);
737   while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
738     wait ();
739
740   // Steps 3 &  4.
741   if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self)
742     {
743       _Jv_MonitorExit (this);
744       return;
745     }
746
747   // Step 5.
748   if (state == JV_STATE_ERROR)
749     {
750       _Jv_MonitorExit (this);
751       JvThrow (new java::lang::NoClassDefFoundError);
752     }
753
754   // Step 6.
755   thread = self;
756   state = JV_STATE_IN_PROGRESS;
757   _Jv_MonitorExit (this);
758
759   // Step 7.
760   if (! isInterface () && superclass)
761     {
762       // FIXME: We can't currently catch a Java exception in C++ code.
763       // So instead we call a Java trampoline.  It returns an
764       // exception, or null.
765       jobject except = superclass->hackTrampoline(0, NULL);
766       if (except)
767         {
768           // Caught an exception.
769           _Jv_MonitorEnter (this);
770           state = JV_STATE_ERROR;
771           notifyAll ();
772           _Jv_MonitorExit (this);
773           JvThrow (except);
774         }
775     }
776
777   // Step 8.
778   // FIXME: once again we have to go through a trampoline.
779   java::lang::Throwable *except = hackTrampoline (1, NULL);
780
781   // Steps 9, 10, 11.
782   if (! except)
783     {
784       _Jv_MonitorEnter (this);
785       state = JV_STATE_DONE;
786     }
787   else
788     {
789       if (! ErrorClass.isInstance(except))
790         {
791           // Once again we must use the trampoline.  In this case we
792           // have to detect an OutOfMemoryError.
793           except = hackTrampoline(2, except);
794         }
795       _Jv_MonitorEnter (this);
796       state = JV_STATE_ERROR;
797     }
798   notifyAll ();
799   _Jv_MonitorExit (this);
800   if (except)
801     JvThrow (except);
802 }
803
804 \f
805
806 //
807 // Some class-related convenience functions.
808 //
809
810 // Find a method declared in the class.  If it is not declared locally
811 // (or if it is inherited), return NULL.
812 _Jv_Method *
813 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
814                     _Jv_Utf8Const *signature)
815 {
816   for (int i = 0; i < klass->method_count; ++i)
817     {
818       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
819           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
820         return &klass->methods[i];
821     }
822   return NULL;
823 }
824
825 _Jv_Method *
826 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
827                         _Jv_Utf8Const *signature)
828 {
829   for (; klass; klass = klass->getSuperclass())
830     {
831       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
832
833       if (meth)
834         return meth;
835     }
836
837   return NULL;
838 }
839
840 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
841 #define MCACHE_SIZE 1023
842
843 struct _Jv_mcache
844 {
845   jclass klass;
846   _Jv_Method *method;
847 };
848
849 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
850
851 static void *
852 _Jv_FindMethodInCache (jclass klass,
853                        _Jv_Utf8Const *name,
854                        _Jv_Utf8Const *signature)
855 {
856   int index = name->hash & MCACHE_SIZE;
857   _Jv_mcache *mc = method_cache + index;
858   _Jv_Method *m = mc->method;
859
860   if (mc->klass == klass
861       && m != NULL              // thread safe check
862       && _Jv_equalUtf8Consts (m->name, name)
863       && _Jv_equalUtf8Consts (m->signature, signature))
864     return mc->method->ncode;
865   return NULL;
866 }
867
868 static void
869 _Jv_AddMethodToCache (jclass klass,
870                         _Jv_Method *method)
871 {
872   _Jv_MonitorEnter (&ClassClass); 
873
874   int index = method->name->hash & MCACHE_SIZE;
875
876   method_cache[index].method = method;
877   method_cache[index].klass = klass;
878
879   _Jv_MonitorExit (&ClassClass);
880 }
881
882 void *
883 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
884                            _Jv_Utf8Const *signature)
885 {
886   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
887   if (ncode != 0)
888     return ncode;
889
890   for (; klass; klass = klass->getSuperclass())
891     {
892       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
893       if (! meth)
894         continue;
895
896       if (java::lang::reflect::Modifier::isStatic(meth->accflags))
897         JvThrow (new java::lang::IncompatibleClassChangeError);
898       if (java::lang::reflect::Modifier::isAbstract(meth->accflags))
899         JvThrow (new java::lang::AbstractMethodError);
900       if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
901         JvThrow (new java::lang::IllegalAccessError);
902
903       _Jv_AddMethodToCache (klass, meth);
904
905       return meth->ncode;
906     }
907   JvThrow (new java::lang::IncompatibleClassChangeError);
908   return NULL;                  // Placate compiler.
909 }
910
911 void
912 _Jv_InitClass (jclass klass)
913 {
914   klass->initializeClass();
915 }
916
917 jboolean
918 _Jv_IsInstanceOf(jobject obj, jclass cl)
919 {
920   return cl->isInstance(obj);
921 }