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