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