1 // natClass.cc - Implementation of java.lang.Class native methods.
3 /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
16 #pragma implementation "Class.h"
20 #include <java-threads.h>
22 #include <java/lang/Class.h>
23 #include <java/lang/ClassLoader.h>
24 #include <java/lang/String.h>
25 #include <java/lang/reflect/Modifier.h>
26 #include <java/lang/reflect/Member.h>
27 #include <java/lang/reflect/Method.h>
28 #include <java/lang/reflect/Field.h>
29 #include <java/lang/reflect/Constructor.h>
30 #include <java/lang/AbstractMethodError.h>
31 #include <java/lang/ArrayStoreException.h>
32 #include <java/lang/ClassCastException.h>
33 #include <java/lang/ClassNotFoundException.h>
34 #include <java/lang/ExceptionInInitializerError.h>
35 #include <java/lang/IllegalAccessException.h>
36 #include <java/lang/IllegalAccessError.h>
37 #include <java/lang/IncompatibleClassChangeError.h>
38 #include <java/lang/InstantiationException.h>
39 #include <java/lang/NoClassDefFoundError.h>
40 #include <java/lang/NoSuchFieldException.h>
41 #include <java/lang/NoSuchMethodError.h>
42 #include <java/lang/NoSuchMethodException.h>
43 #include <java/lang/Thread.h>
44 #include <java/lang/NullPointerException.h>
45 #include <java/lang/System.h>
46 #include <java/lang/SecurityManager.h>
47 #include <java/lang/StringBuffer.h>
48 #include <gcj/method.h>
50 #include <java-cpool.h>
54 // FIXME: remove these.
55 #define CloneableClass java::lang::Cloneable::class$
56 #define ObjectClass java::lang::Object::class$
57 #define ErrorClass java::lang::Error::class$
58 #define ClassClass java::lang::Class::class$
59 #define MethodClass java::lang::reflect::Method::class$
60 #define FieldClass java::lang::reflect::Field::class$
61 #define ConstructorClass java::lang::reflect::Constructor::class$
63 // Some constants we use to look up the class initializer.
64 static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
65 static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
66 static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
67 static _Jv_Utf8Const *finit_name = _Jv_makeUtf8Const ("finit$", 6);
68 // The legacy `$finit$' method name, which still needs to be
69 // recognized as equivalent to the now prefered `finit$' name.
70 static _Jv_Utf8Const *finit_leg_name = _Jv_makeUtf8Const ("$finit$", 7);
75 java::lang::Class::forName (jstring className, jboolean initialize,
76 java::lang::ClassLoader *loader)
79 throw new java::lang::NullPointerException;
81 jsize length = _Jv_GetStringUTFLength (className);
83 _Jv_GetStringUTFRegion (className, 0, length, buffer);
85 // FIXME: should check syntax of CLASSNAME and throw
86 // IllegalArgumentException on failure.
87 _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
89 // FIXME: should use bootstrap class loader if loader is null.
90 jclass klass = (buffer[0] == '['
91 ? _Jv_FindClassFromSignature (name->data, loader)
92 : _Jv_FindClass (name, loader));
95 throw new java::lang::ClassNotFoundException (className);
98 _Jv_InitClass (klass);
104 java::lang::Class::forName (jstring className)
106 // FIXME: should use class loader from calling method.
107 return forName (className, true, NULL);
110 java::lang::reflect::Constructor *
111 java::lang::Class::getConstructor (JArray<jclass> *param_types)
113 jstring partial_sig = getSignature (param_types, true);
114 jint hash = partial_sig->hashCode ();
116 int i = isPrimitive () ? 0 : method_count;
119 // FIXME: access checks.
120 if (_Jv_equalUtf8Consts (methods[i].name, init_name)
121 && _Jv_equal (methods[i].signature, partial_sig, hash))
123 // Found it. For getConstructor, the constructor must be
125 using namespace java::lang::reflect;
126 if (! Modifier::isPublic(methods[i].accflags))
128 Constructor *cons = new Constructor ();
129 cons->offset = (char *) (&methods[i]) - (char *) methods;
130 cons->declaringClass = this;
134 throw new java::lang::NoSuchMethodException;
137 JArray<java::lang::reflect::Constructor *> *
138 java::lang::Class::_getConstructors (jboolean declared)
140 // FIXME: this method needs access checks.
142 int numConstructors = 0;
143 int max = isPrimitive () ? 0 : method_count;
145 for (i = max; --i >= 0; )
147 _Jv_Method *method = &methods[i];
148 if (method->name == NULL
149 || ! _Jv_equalUtf8Consts (method->name, init_name))
152 && ! java::lang::reflect::Modifier::isPublic(method->accflags))
156 JArray<java::lang::reflect::Constructor *> *result
157 = (JArray<java::lang::reflect::Constructor *> *)
158 JvNewObjectArray (numConstructors, &ConstructorClass, NULL);
159 java::lang::reflect::Constructor** cptr = elements (result);
160 for (i = 0; i < max; i++)
162 _Jv_Method *method = &methods[i];
163 if (method->name == NULL
164 || ! _Jv_equalUtf8Consts (method->name, init_name))
167 && ! java::lang::reflect::Modifier::isPublic(method->accflags))
169 java::lang::reflect::Constructor *cons
170 = new java::lang::reflect::Constructor ();
171 cons->offset = (char *) method - (char *) methods;
172 cons->declaringClass = this;
178 java::lang::reflect::Constructor *
179 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
181 jstring partial_sig = getSignature (param_types, true);
182 jint hash = partial_sig->hashCode ();
184 int i = isPrimitive () ? 0 : method_count;
187 // FIXME: access checks.
188 if (_Jv_equalUtf8Consts (methods[i].name, init_name)
189 && _Jv_equal (methods[i].signature, partial_sig, hash))
192 using namespace java::lang::reflect;
193 Constructor *cons = new Constructor ();
194 cons->offset = (char *) (&methods[i]) - (char *) methods;
195 cons->declaringClass = this;
199 throw new java::lang::NoSuchMethodException;
202 java::lang::reflect::Field *
203 java::lang::Class::getField (jstring name, jint hash)
205 java::lang::reflect::Field* rfield;
206 for (int i = 0; i < field_count; i++)
208 _Jv_Field *field = &fields[i];
209 if (! _Jv_equal (field->name, name, hash))
211 if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
213 rfield = new java::lang::reflect::Field ();
214 rfield->offset = (char*) field - (char*) fields;
215 rfield->declaringClass = this;
219 jclass superclass = getSuperclass();
220 if (superclass == NULL)
222 rfield = superclass->getField(name, hash);
223 for (int i = 0; i < interface_count && rfield == NULL; ++i)
224 rfield = interfaces[i]->getField (name, hash);
228 java::lang::reflect::Field *
229 java::lang::Class::getDeclaredField (jstring name)
231 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
233 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
234 int hash = name->hashCode();
235 for (int i = 0; i < field_count; i++)
237 _Jv_Field *field = &fields[i];
238 if (! _Jv_equal (field->name, name, hash))
240 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
241 rfield->offset = (char*) field - (char*) fields;
242 rfield->declaringClass = this;
246 throw new java::lang::NoSuchFieldException (name);
249 JArray<java::lang::reflect::Field *> *
250 java::lang::Class::getDeclaredFields (void)
252 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
254 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
255 JArray<java::lang::reflect::Field *> *result
256 = (JArray<java::lang::reflect::Field *> *)
257 JvNewObjectArray (field_count, &FieldClass, NULL);
258 java::lang::reflect::Field** fptr = elements (result);
259 for (int i = 0; i < field_count; i++)
261 _Jv_Field *field = &fields[i];
262 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
263 rfield->offset = (char*) field - (char*) fields;
264 rfield->declaringClass = this;
271 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
274 buffer->append((jchar) method_count);
277 jstring name = getName();
278 if (name->charAt(0) != '[')
279 buffer->append((jchar) 'L');
280 buffer->append(name);
281 if (name->charAt(0) != '[')
282 buffer->append((jchar) ';');
286 // This doesn't have to be native. It is an implementation detail
287 // only called from the C++ code, though, so maybe this is clearer.
289 java::lang::Class::getSignature (JArray<jclass> *param_types,
290 jboolean is_constructor)
292 java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
293 buf->append((jchar) '(');
294 jclass *v = elements (param_types);
295 // A NULL param_types means "no parameters".
296 if (param_types != NULL)
298 for (int i = 0; i < param_types->length; ++i)
299 v[i]->getSignature(buf);
301 buf->append((jchar) ')');
303 buf->append((jchar) 'V');
304 return buf->toString();
307 java::lang::reflect::Method *
308 java::lang::Class::getDeclaredMethod (jstring name,
309 JArray<jclass> *param_types)
311 jstring partial_sig = getSignature (param_types, false);
312 jint p_len = partial_sig->length();
313 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
314 int i = isPrimitive () ? 0 : method_count;
317 // FIXME: access checks.
318 if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
319 && _Jv_equaln (methods[i].signature, partial_sig, p_len))
322 using namespace java::lang::reflect;
323 Method *rmethod = new Method ();
324 rmethod->offset = (char*) (&methods[i]) - (char*) methods;
325 rmethod->declaringClass = this;
329 throw new java::lang::NoSuchMethodException;
332 JArray<java::lang::reflect::Method *> *
333 java::lang::Class::getDeclaredMethods (void)
336 int max = isPrimitive () ? 0 : method_count;
338 for (i = max; --i >= 0; )
340 _Jv_Method *method = &methods[i];
341 if (method->name == NULL
342 || _Jv_equalUtf8Consts (method->name, clinit_name)
343 || _Jv_equalUtf8Consts (method->name, init_name)
344 || _Jv_equalUtf8Consts (method->name, finit_name)
345 // Backward compatibility hack: match the legacy `$finit$' name
346 || _Jv_equalUtf8Consts (method->name, finit_leg_name))
350 JArray<java::lang::reflect::Method *> *result
351 = (JArray<java::lang::reflect::Method *> *)
352 JvNewObjectArray (numMethods, &MethodClass, NULL);
353 java::lang::reflect::Method** mptr = elements (result);
354 for (i = 0; i < max; i++)
356 _Jv_Method *method = &methods[i];
357 if (method->name == NULL
358 || _Jv_equalUtf8Consts (method->name, clinit_name)
359 || _Jv_equalUtf8Consts (method->name, init_name)
360 || _Jv_equalUtf8Consts (method->name, finit_name)
361 // Backward compatibility hack: match the legacy `$finit$' name
362 || _Jv_equalUtf8Consts (method->name, finit_leg_name))
364 java::lang::reflect::Method* rmethod
365 = new java::lang::reflect::Method ();
366 rmethod->offset = (char*) method - (char*) methods;
367 rmethod->declaringClass = this;
374 java::lang::Class::getName (void)
376 char buffer[name->length + 1];
377 memcpy (buffer, name->data, name->length);
378 buffer[name->length] = '\0';
379 return _Jv_NewStringUTF (buffer);
383 java::lang::Class::getClasses (void)
385 // Until we have inner classes, it always makes sense to return an
387 JArray<jclass> *result
388 = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
393 java::lang::Class::getDeclaredClasses (void)
395 checkMemberAccess (java::lang::reflect::Member::DECLARED);
396 // Until we have inner classes, it always makes sense to return an
398 JArray<jclass> *result
399 = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass, NULL);
404 java::lang::Class::getDeclaringClass (void)
406 // Until we have inner classes, it makes sense to always return
412 java::lang::Class::_getFields (JArray<java::lang::reflect::Field *> *result,
416 for (int i = 0; i < field_count; i++)
418 _Jv_Field *field = &fields[i];
419 if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
425 java::lang::reflect::Field *rfield
426 = new java::lang::reflect::Field ();
427 rfield->offset = (char *) field - (char *) fields;
428 rfield->declaringClass = this;
429 rfield->name = _Jv_NewStringUtf8Const (field->name);
430 (elements (result))[offset++] = rfield;
433 jclass superclass = getSuperclass();
434 if (superclass != NULL)
436 int s_count = superclass->_getFields (result, offset);
440 for (int i = 0; i < interface_count; ++i)
442 int f_count = interfaces[i]->_getFields (result, offset);
449 JArray<java::lang::reflect::Field *> *
450 java::lang::Class::getFields (void)
452 using namespace java::lang::reflect;
454 int count = _getFields (NULL, 0);
456 JArray<java::lang::reflect::Field *> *result
457 = ((JArray<java::lang::reflect::Field *> *)
458 JvNewObjectArray (count, &FieldClass, NULL));
460 _getFields (result, 0);
466 java::lang::Class::getInterfaces (void)
468 jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
469 jobject *data = elements (r);
470 for (int i = 0; i < interface_count; ++i)
471 data[i] = interfaces[i];
472 return reinterpret_cast<JArray<jclass> *> (r);
475 java::lang::reflect::Method *
476 java::lang::Class::getMethod (jstring name, JArray<jclass> *param_types)
478 jstring partial_sig = getSignature (param_types, false);
479 jint p_len = partial_sig->length();
480 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
481 for (Class *klass = this; klass; klass = klass->getSuperclass())
483 int i = klass->isPrimitive () ? 0 : klass->method_count;
486 // FIXME: access checks.
487 if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
488 && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
491 using namespace java::lang::reflect;
493 // Method must be public.
494 if (! Modifier::isPublic (klass->methods[i].accflags))
497 Method *rmethod = new Method ();
498 rmethod->offset = ((char *) (&klass->methods[i])
499 - (char *) klass->methods);
500 rmethod->declaringClass = klass;
505 throw new java::lang::NoSuchMethodException;
508 // This is a very slow implementation, since it re-scans all the
509 // methods we've already listed to make sure we haven't duplicated a
510 // method. It also over-estimates the required size, so we have to
511 // shrink the result array later.
513 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
518 // First examine all local methods
519 for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
521 _Jv_Method *method = &methods[i];
522 if (method->name == NULL
523 || _Jv_equalUtf8Consts (method->name, clinit_name)
524 || _Jv_equalUtf8Consts (method->name, init_name)
525 || _Jv_equalUtf8Consts (method->name, finit_name)
526 // Backward compatibility hack: match the legacy `$finit$' name
527 || _Jv_equalUtf8Consts (method->name, finit_leg_name))
529 // Only want public methods.
530 if (! java::lang::reflect::Modifier::isPublic (method->accflags))
533 // This is where we over-count the slots required if we aren't
534 // filling the result for real.
538 java::lang::reflect::Method **mp = elements (result);
539 // If we already have a method with this name and signature,
540 // then ignore this one. This can happen with virtual
542 for (int j = 0; j < offset; ++j)
544 _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
545 if (_Jv_equalUtf8Consts (method->name, meth_2->name)
546 && _Jv_equalUtf8Consts (method->signature,
559 using namespace java::lang::reflect;
560 Method *rmethod = new Method ();
561 rmethod->offset = (char *) method - (char *) methods;
562 rmethod->declaringClass = this;
563 Method **mp = elements (result);
564 mp[offset + count] = rmethod;
570 // Now examine superclasses.
571 if (getSuperclass () != NULL)
573 jint s_count = getSuperclass()->_getMethods (result, offset);
578 // Finally, examine interfaces.
579 for (int i = 0; i < interface_count; ++i)
581 int f_count = interfaces[i]->_getMethods (result, offset);
589 JArray<java::lang::reflect::Method *> *
590 java::lang::Class::getMethods (void)
592 using namespace java::lang::reflect;
594 // FIXME: security checks.
596 // This will overestimate the size we need.
597 jint count = _getMethods (NULL, 0);
599 JArray<Method *> *result
600 = ((JArray<Method *> *) JvNewObjectArray (count, &MethodClass, NULL));
602 // When filling the array for real, we get the actual count. Then
603 // we resize the array.
604 jint real_count = _getMethods (result, 0);
606 if (real_count != count)
609 = ((JArray<Method *> *) JvNewObjectArray (real_count, &MethodClass,
612 Method **destp = elements (r2);
613 Method **srcp = elements (result);
615 for (int i = 0; i < real_count; ++i)
625 java::lang::Class::isAssignableFrom (jclass klass)
627 // Arguments may not have been initialized, given ".class" syntax.
628 _Jv_InitClass (this);
629 _Jv_InitClass (klass);
630 return _Jv_IsAssignableFrom (this, klass);
634 java::lang::Class::isInstance (jobject obj)
636 if (__builtin_expect (! obj || isPrimitive (), false))
638 _Jv_InitClass (this);
639 return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
643 java::lang::Class::newInstance (void)
645 // FIXME: do accessibility checks here. There currently doesn't
646 // seem to be any way to do these.
647 // FIXME: we special-case one check here just to pass a Plum Hall
648 // test. Once access checking is implemented, remove this.
649 if (this == &ClassClass)
650 throw new java::lang::IllegalAccessException;
655 || java::lang::reflect::Modifier::isAbstract(accflags))
656 throw new java::lang::InstantiationException;
658 _Jv_InitClass (this);
660 _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
662 throw new java::lang::NoSuchMethodException;
664 jobject r = JvAllocObject (this);
665 ((void (*) (jobject)) meth->ncode) (r);
670 java::lang::Class::finalize (void)
673 JvAssert (_Jv_IsInterpretedClass (this));
674 _Jv_UnregisterClass (this);
678 // This implements the initialization process for a class. From Spec
681 java::lang::Class::initializeClass (void)
683 // short-circuit to avoid needless locking.
684 if (state == JV_STATE_DONE)
688 _Jv_MonitorEnter (this);
690 if (state < JV_STATE_LINKED)
693 if (_Jv_IsInterpretedClass (this))
695 // this can throw exceptions, so exit the monitor as a precaution.
696 _Jv_MonitorExit (this);
697 java::lang::ClassLoader::resolveClass0 (this);
698 _Jv_MonitorEnter (this);
703 _Jv_PrepareCompiledClass (this);
707 if (state <= JV_STATE_LINKED)
708 _Jv_PrepareConstantTimeTables (this);
711 java::lang::Thread *self = java::lang::Thread::currentThread();
712 // FIXME: `self' can be null at startup. Hence this nasty trick.
713 self = (java::lang::Thread *) ((long) self | 1);
714 while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
718 if (state == JV_STATE_DONE
719 || state == JV_STATE_IN_PROGRESS
722 _Jv_MonitorExit (this);
727 if (state == JV_STATE_ERROR)
729 _Jv_MonitorExit (this);
730 throw new java::lang::NoClassDefFoundError;
735 state = JV_STATE_IN_PROGRESS;
736 _Jv_MonitorExit (this);
739 if (! isInterface () && superclass)
743 _Jv_InitClass (superclass);
745 catch (java::lang::Throwable *except)
747 // Caught an exception.
748 _Jv_MonitorEnter (this);
749 state = JV_STATE_ERROR;
751 _Jv_MonitorExit (this);
756 // Steps 8, 9, 10, 11.
759 _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
762 ((void (*) (void)) meth->ncode) ();
764 catch (java::lang::Throwable *except)
766 if (! ErrorClass.isInstance(except))
770 except = new ExceptionInInitializerError (except);
772 catch (java::lang::Throwable *t)
777 _Jv_MonitorEnter (this);
778 state = JV_STATE_ERROR;
780 _Jv_MonitorExit (this);
784 _Jv_MonitorEnter (this);
785 state = JV_STATE_DONE;
787 _Jv_MonitorExit (this);
793 // Some class-related convenience functions.
796 // Find a method declared in the class. If it is not declared locally
797 // (or if it is inherited), return NULL.
799 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
800 _Jv_Utf8Const *signature)
802 for (int i = 0; i < klass->method_count; ++i)
804 if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
805 && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
806 return &klass->methods[i];
812 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
813 _Jv_Utf8Const *signature)
815 for (; klass; klass = klass->getSuperclass())
817 _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
826 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
827 #define MCACHE_SIZE 1023
835 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
838 _Jv_FindMethodInCache (jclass klass,
840 _Jv_Utf8Const *signature)
842 int index = name->hash & MCACHE_SIZE;
843 _Jv_mcache *mc = method_cache + index;
844 _Jv_Method *m = mc->method;
846 if (mc->klass == klass
847 && m != NULL // thread safe check
848 && _Jv_equalUtf8Consts (m->name, name)
849 && _Jv_equalUtf8Consts (m->signature, signature))
850 return mc->method->ncode;
855 _Jv_AddMethodToCache (jclass klass,
858 _Jv_MonitorEnter (&ClassClass);
860 int index = method->name->hash & MCACHE_SIZE;
862 method_cache[index].method = method;
863 method_cache[index].klass = klass;
865 _Jv_MonitorExit (&ClassClass);
869 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
870 _Jv_Utf8Const *signature)
872 using namespace java::lang::reflect;
874 void *ncode = _Jv_FindMethodInCache (klass, name, signature);
878 for (; klass; klass = klass->getSuperclass())
880 _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
884 if (Modifier::isStatic(meth->accflags))
885 throw new java::lang::IncompatibleClassChangeError
886 (_Jv_GetMethodString (klass, meth->name));
887 if (Modifier::isAbstract(meth->accflags))
888 throw new java::lang::AbstractMethodError
889 (_Jv_GetMethodString (klass, meth->name));
890 if (! Modifier::isPublic(meth->accflags))
891 throw new java::lang::IllegalAccessError
892 (_Jv_GetMethodString (klass, meth->name));
894 _Jv_AddMethodToCache (klass, meth);
898 throw new java::lang::IncompatibleClassChangeError;
901 // Fast interface method lookup by index.
903 _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
905 _Jv_IDispatchTable *cldt = klass->idt;
906 int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
907 return cldt->cls.itable[idx];
911 _Jv_IsAssignableFrom (jclass target, jclass source)
913 if (source == target)
916 // If target is array, so must source be.
917 if (target->isArray ())
919 if (! source->isArray())
921 return _Jv_IsAssignableFrom(target->getComponentType(),
922 source->getComponentType());
925 if (target->isInterface())
927 // Abstract classes have no IDT, and IDTs provide no way to check
928 // two interfaces for assignability.
930 (source->idt == NULL || source->isInterface(), false))
931 return _Jv_InterfaceAssignableFrom (target, source);
933 _Jv_IDispatchTable *cl_idt = source->idt;
934 _Jv_IDispatchTable *if_idt = target->idt;
936 if (__builtin_expect ((if_idt == NULL), false))
937 return false; // No class implementing TARGET has been loaded.
938 jshort cl_iindex = cl_idt->cls.iindex;
939 if (cl_iindex < if_idt->iface.ioffsets[0])
941 jshort offset = if_idt->iface.ioffsets[cl_iindex];
942 if (offset < cl_idt->cls.itable_length
943 && cl_idt->cls.itable[offset] == target)
949 if ((target == &ObjectClass && !source->isPrimitive())
950 || (source->ancestors != NULL
951 && source->ancestors[source->depth - target->depth] == target))
957 // Interface type checking, the slow way. Returns TRUE if IFACE is a
958 // superinterface of SOURCE. This is used when SOURCE is also an interface,
959 // or a class with no interface dispatch table.
961 _Jv_InterfaceAssignableFrom (jclass iface, jclass source)
963 for (int i = 0; i < source->interface_count; i++)
965 jclass interface = source->interfaces[i];
966 if (iface == interface
967 || _Jv_InterfaceAssignableFrom (iface, interface))
971 if (!source->isInterface()
972 && source->superclass
973 && _Jv_InterfaceAssignableFrom (iface, source->superclass))
980 _Jv_IsInstanceOf(jobject obj, jclass cl)
982 if (__builtin_expect (!obj, false))
984 return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
988 _Jv_CheckCast (jclass c, jobject obj)
991 (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
992 throw new java::lang::ClassCastException
993 ((new java::lang::StringBuffer
994 (obj->getClass()->getName()))->append
995 (JvNewStringUTF(" cannot be cast to "))->append
996 (c->getName())->toString());
1002 _Jv_CheckArrayStore (jobject arr, jobject obj)
1006 JvAssert (arr != NULL);
1007 jclass elt_class = (JV_CLASS (arr))->getComponentType();
1008 jclass obj_class = JV_CLASS (obj);
1009 if (__builtin_expect
1010 (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
1011 throw new java::lang::ArrayStoreException;
1015 #define INITIAL_IOFFSETS_LEN 4
1016 #define INITIAL_IFACES_LEN 4
1018 static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
1020 // Generate tables for constant-time assignment testing and interface
1021 // method lookup. This implements the technique described by Per Bothner
1022 // <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
1023 // http://gcc.gnu.org/ml/java/1999-q3/msg00377.html
1025 _Jv_PrepareConstantTimeTables (jclass klass)
1027 if (klass->isPrimitive () || klass->isInterface ())
1030 // Short-circuit in case we've been called already.
1031 if ((klass->idt != NULL) || klass->depth != 0)
1034 // Calculate the class depth and ancestor table. The depth of a class
1035 // is how many "extends" it is removed from Object. Thus the depth of
1036 // java.lang.Object is 0, but the depth of java.io.FilterOutputStream
1037 // is 2. Depth is defined for all regular and array classes, but not
1038 // interfaces or primitive types.
1040 jclass klass0 = klass;
1041 jboolean has_interfaces = 0;
1042 while (klass0 != &ObjectClass)
1044 has_interfaces += klass0->interface_count;
1045 klass0 = klass0->superclass;
1049 // We do class member testing in constant time by using a small table
1050 // of all the ancestor classes within each class. The first element is
1051 // a pointer to the current class, and the rest are pointers to the
1052 // classes ancestors, ordered from the current class down by decreasing
1053 // depth. We do not include java.lang.Object in the table of ancestors,
1054 // since it is redundant.
1056 klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
1058 for (int index = 0; index < klass->depth; index++)
1060 klass->ancestors[index] = klass0;
1061 klass0 = klass0->superclass;
1064 if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
1067 // Optimization: If class implements no interfaces, use a common
1068 // predefined interface table.
1069 if (!has_interfaces)
1071 klass->idt = &null_idt;
1076 (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1081 ifaces.len = INITIAL_IFACES_LEN;
1082 ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
1084 int itable_size = _Jv_GetInterfaces (klass, &ifaces);
1086 if (ifaces.count > 0)
1088 klass->idt->cls.itable =
1089 (void **) _Jv_Malloc (itable_size * sizeof (void *));
1090 klass->idt->cls.itable_length = itable_size;
1092 jshort *itable_offsets =
1093 (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
1095 _Jv_GenerateITable (klass, &ifaces, itable_offsets);
1098 _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
1100 for (int i=0; i < ifaces.count; i++)
1102 ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
1106 klass->idt->cls.iindex = cls_iindex;
1108 _Jv_Free (ifaces.list);
1109 _Jv_Free (itable_offsets);
1113 klass->idt->cls.iindex = SHRT_MAX;
1117 // Return index of item in list, or -1 if item is not present.
1119 _Jv_IndexOf (void *item, void **list, jshort list_len)
1121 for (int i=0; i < list_len; i++)
1123 if (list[i] == item)
1129 // Find all unique interfaces directly or indirectly implemented by klass.
1130 // Returns the size of the interface dispatch table (itable) for klass, which
1131 // is the number of unique interfaces plus the total number of methods that
1132 // those interfaces declare. May extend ifaces if required.
1134 _Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
1138 for (int i=0; i < klass->interface_count; i++)
1140 jclass iface = klass->interfaces[i];
1141 if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
1143 if (ifaces->count + 1 >= ifaces->len)
1145 /* Resize ifaces list */
1146 ifaces->len = ifaces->len * 2;
1147 ifaces->list = (jclass *) _Jv_Realloc (ifaces->list,
1148 ifaces->len * sizeof(jclass));
1150 ifaces->list[ifaces->count] = iface;
1153 result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
1157 if (klass->isInterface())
1159 result += klass->method_count + 1;
1163 if (klass->superclass)
1165 result += _Jv_GetInterfaces (klass->superclass, ifaces);
1171 // Fill out itable in klass, resolving method declarations in each ifaces.
1172 // itable_offsets is filled out with the position of each iface in itable,
1173 // such that itable[itable_offsets[n]] == ifaces.list[n].
1175 _Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
1177 void **itable = klass->idt->cls.itable;
1178 jshort itable_pos = 0;
1180 for (int i=0; i < ifaces->count; i++)
1182 jclass iface = ifaces->list[i];
1183 itable_offsets[i] = itable_pos;
1184 itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos);
1186 /* Create interface dispatch table for iface */
1187 if (iface->idt == NULL)
1190 (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1192 // The first element of ioffsets is its length (itself included).
1194 (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
1195 ioffsets[0] = INITIAL_IOFFSETS_LEN;
1196 for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
1199 iface->idt->iface.ioffsets = ioffsets;
1204 // Format method name for use in error messages.
1206 _Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
1208 jstring r = JvNewStringUTF (klass->name->data);
1209 r = r->concat (JvNewStringUTF ("."));
1210 r = r->concat (JvNewStringUTF (name->data));
1215 _Jv_ThrowNoSuchMethodError ()
1217 throw new java::lang::NoSuchMethodError;
1220 // Each superinterface of a class (i.e. each interface that the class
1221 // directly or indirectly implements) has a corresponding "Partial
1222 // Interface Dispatch Table" whose size is (number of methods + 1) words.
1223 // The first word is a pointer to the interface (i.e. the java.lang.Class
1224 // instance for that interface). The remaining words are pointers to the
1225 // actual methods that implement the methods declared in the interface,
1226 // in order of declaration.
1228 // Append partial interface dispatch table for "iface" to "itable", at
1229 // position itable_pos.
1230 // Returns the offset at which the next partial ITable should be appended.
1232 _Jv_AppendPartialITable (jclass klass, jclass iface, void **itable,
1235 using namespace java::lang::reflect;
1237 itable[pos++] = (void *) iface;
1240 for (int j=0; j < iface->method_count; j++)
1243 for (jclass cl = klass; cl; cl = cl->getSuperclass())
1245 meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
1246 iface->methods[j].signature);
1252 if (meth && (meth->name->data[0] == '<'))
1254 // leave a placeholder in the itable for hidden init methods.
1259 if (Modifier::isStatic(meth->accflags))
1260 throw new java::lang::IncompatibleClassChangeError
1261 (_Jv_GetMethodString (klass, meth->name));
1262 if (Modifier::isAbstract(meth->accflags))
1263 throw new java::lang::AbstractMethodError
1264 (_Jv_GetMethodString (klass, meth->name));
1265 if (! Modifier::isPublic(meth->accflags))
1266 throw new java::lang::IllegalAccessError
1267 (_Jv_GetMethodString (klass, meth->name));
1269 itable[pos] = meth->ncode;
1273 // The method doesn't exist in klass. Binary compatibility rules
1274 // permit this, so we delay the error until runtime using a pointer
1275 // to a method which throws an exception.
1276 itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
1284 static _Jv_Mutex_t iindex_mutex;
1285 bool iindex_mutex_initialized = false;
1287 // We need to find the correct offset in the Class Interface Dispatch
1288 // Table for a given interface. Once we have that, invoking an interface
1289 // method just requires combining the Method's index in the interface
1290 // (known at compile time) to get the correct method. Doing a type test
1291 // (cast or instanceof) is the same problem: Once we have a possible Partial
1292 // Interface Dispatch Table, we just compare the first element to see if it
1293 // matches the desired interface. So how can we find the correct offset?
1294 // Our solution is to keep a vector of candiate offsets in each interface
1295 // (idt->iface.ioffsets), and in each class we have an index
1296 // (idt->cls.iindex) used to select the correct offset from ioffsets.
1298 // Calculate and return iindex for a new class.
1299 // ifaces is a vector of num interfaces that the class implements.
1300 // offsets[j] is the offset in the interface dispatch table for the
1301 // interface corresponding to ifaces[j].
1302 // May extend the interface ioffsets if required.
1304 _Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
1309 // Acquire a global lock to prevent itable corruption in case of multiple
1310 // classes that implement an intersecting set of interfaces being linked
1311 // simultaneously. We can assume that the mutex will be initialized
1313 if (! iindex_mutex_initialized)
1315 _Jv_MutexInit (&iindex_mutex);
1316 iindex_mutex_initialized = true;
1319 _Jv_MutexLock (&iindex_mutex);
1321 for (i=1;; i++) /* each potential position in ioffsets */
1323 for (j=0;; j++) /* each iface */
1327 if (i >= ifaces[j]->idt->iface.ioffsets[0])
1329 int ioffset = ifaces[j]->idt->iface.ioffsets[i];
1330 /* We can potentially share this position with another class. */
1331 if (ioffset >= 0 && ioffset != offsets[j])
1332 break; /* Nope. Try next i. */
1336 for (j = 0; j < num; j++)
1338 int len = ifaces[j]->idt->iface.ioffsets[0];
1341 /* Resize ioffsets. */
1342 int newlen = 2 * len;
1345 jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
1346 jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets,
1347 newlen * sizeof(jshort));
1348 new_ioffsets[0] = newlen;
1350 while (len < newlen)
1351 new_ioffsets[len++] = -1;
1353 ifaces[j]->idt->iface.ioffsets = new_ioffsets;
1355 ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
1358 _Jv_MutexUnlock (&iindex_mutex);
1363 // Only used by serialization
1364 java::lang::reflect::Field *
1365 java::lang::Class::getPrivateField (jstring name)
1367 int hash = name->hashCode ();
1369 java::lang::reflect::Field* rfield;
1370 for (int i = 0; i < field_count; i++)
1372 _Jv_Field *field = &fields[i];
1373 if (! _Jv_equal (field->name, name, hash))
1375 rfield = new java::lang::reflect::Field ();
1376 rfield->offset = (char*) field - (char*) fields;
1377 rfield->declaringClass = this;
1378 rfield->name = name;
1381 jclass superclass = getSuperclass();
1382 if (superclass == NULL)
1384 rfield = superclass->getPrivateField(name);
1385 for (int i = 0; i < interface_count && rfield == NULL; ++i)
1386 rfield = interfaces[i]->getPrivateField (name);
1390 // Only used by serialization
1391 java::lang::reflect::Method *
1392 java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
1394 jstring partial_sig = getSignature (param_types, false);
1395 jint p_len = partial_sig->length();
1396 _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
1397 for (Class *klass = this; klass; klass = klass->getSuperclass())
1399 int i = klass->isPrimitive () ? 0 : klass->method_count;
1402 // FIXME: access checks.
1403 if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1404 && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
1407 using namespace java::lang::reflect;
1409 Method *rmethod = new Method ();
1410 rmethod->offset = ((char *) (&klass->methods[i])
1411 - (char *) klass->methods);
1412 rmethod->declaringClass = klass;
1417 throw new java::lang::NoSuchMethodException;
1420 // Private accessor method for Java code to retrieve the protection domain.
1421 java::security::ProtectionDomain *
1422 java::lang::Class::getProtectionDomain0 ()
1424 return protectionDomain;