1 // natClass.cc - Implementation of java.lang.Class native methods.
3 /* Copyright (C) 1998, 1999 Cygnus Solutions
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/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>
42 #include <java-cpool.h>
46 #define CloneableClass _CL_Q34java4lang9Cloneable
47 extern java::lang::Class CloneableClass;
48 #define ObjectClass _CL_Q34java4lang6Object
49 extern java::lang::Class ObjectClass;
50 #define ErrorClass _CL_Q34java4lang5Error
51 extern java::lang::Class ErrorClass;
52 #define ClassClass _CL_Q34java4lang5Class
53 extern java::lang::Class ClassClass;
54 #define MethodClass _CL_Q44java4lang7reflect6Method
55 extern java::lang::Class MethodClass;
56 #define FieldClass _CL_Q44java4lang7reflect5Field
57 extern java::lang::Class FieldClass;
59 // Some constants we use to look up the class initializer.
60 static _Jv_Utf8Const *void_signature = _Jv_makeUtf8Const ("()V", 3);
61 static _Jv_Utf8Const *clinit_name = _Jv_makeUtf8Const ("<clinit>", 8);
62 static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6);
67 java::lang::Class::forName (jstring className)
70 JvThrow (new java::lang::NullPointerException);
73 // FIXME: should check syntax of CLASSNAME and throw
74 // IllegalArgumentException on failure.
76 // FIXME: should use class loader from calling method.
77 jclass klass = _Jv_FindClass (className, NULL);
79 jsize length = _Jv_GetStringUTFLength (className);
81 _Jv_GetStringUTFRegion (className, 0, length, buffer);
83 // FIXME: should check syntax of CLASSNAME and throw
84 // IllegalArgumentException on failure.
85 _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
87 // FIXME: should use class loader from calling method.
88 jclass klass = (buffer[0] == '['
89 ? _Jv_FindClassFromSignature (name->data, NULL)
90 : _Jv_FindClass (name, NULL));
93 JvThrow (new java::lang::ClassNotFoundException (className));
98 java::lang::reflect::Constructor *
99 java::lang::Class::getConstructor (JArray<jclass> *)
101 JvFail ("java::lang::Class::getConstructor not implemented");
104 JArray<java::lang::reflect::Constructor *> *
105 java::lang::Class::getConstructors (void)
107 JvFail ("java::lang::Class::getConstructors not implemented");
110 java::lang::reflect::Constructor *
111 java::lang::Class::getDeclaredConstructor (JArray<jclass> *)
113 JvFail ("java::lang::Class::getDeclaredConstructor not implemented");
116 JArray<java::lang::reflect::Constructor *> *
117 java::lang::Class::getDeclaredConstructors (void)
119 JvFail ("java::lang::Class::getDeclaredConstructors not implemented");
122 java::lang::reflect::Field *
123 java::lang::Class::getField (jstring name, jint hash)
125 java::lang::reflect::Field* rfield;
126 for (int i = 0; i < field_count; i++)
128 _Jv_Field *field = &fields[i];
129 if (! _Jv_equal (field->name, name, hash))
131 if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
133 rfield = new java::lang::reflect::Field ();
134 rfield->offset = (char*) field - (char*) fields;
135 rfield->declaringClass = this;
139 jclass superclass = getSuperclass();
140 if (superclass == NULL)
142 rfield = superclass->getField(name, hash);
143 for (int i = 0; i < interface_count && rfield == NULL; ++i)
144 rfield = interfaces[i]->getField (name, hash);
148 java::lang::reflect::Field *
149 java::lang::Class::getDeclaredField (jstring name)
151 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
153 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
154 int hash = name->hashCode();
155 for (int i = 0; i < field_count; i++)
157 _Jv_Field *field = &fields[i];
158 if (! _Jv_equal (field->name, name, hash))
160 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
161 rfield->offset = (char*) field - (char*) fields;
162 rfield->declaringClass = this;
166 JvThrow (new java::lang::NoSuchFieldException (name));
169 JArray<java::lang::reflect::Field *> *
170 java::lang::Class::getDeclaredFields (void)
172 java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
174 s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
175 JArray<java::lang::reflect::Field *> *result
176 = (JArray<java::lang::reflect::Field *> *)
177 JvNewObjectArray (field_count, &FieldClass, NULL);
178 java::lang::reflect::Field** fptr = elements (result);
179 for (int i = 0; i < field_count; i++)
181 _Jv_Field *field = &fields[i];
182 java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
183 rfield->offset = (char*) field - (char*) fields;
184 rfield->declaringClass = this;
190 java::lang::reflect::Method *
191 java::lang::Class::getDeclaredMethod (jstring, JArray<jclass> *)
193 JvFail ("java::lang::Class::getDeclaredMethod not implemented");
196 JArray<java::lang::reflect::Method *> *
197 java::lang::Class::getDeclaredMethods (void)
201 for (i = method_count; --i >= 0; )
203 _Jv_Method *method = &methods[i];
204 if (method->name == NULL
205 || _Jv_equalUtf8Consts (method->name, clinit_name)
206 || _Jv_equalUtf8Consts (method->name, init_name))
210 JArray<java::lang::reflect::Method *> *result
211 = (JArray<java::lang::reflect::Method *> *)
212 JvNewObjectArray (numMethods, &MethodClass, NULL);
213 java::lang::reflect::Method** mptr = elements (result);
214 for (i = 0; i < method_count; i++)
216 _Jv_Method *method = &methods[i];
217 if (method->name == NULL
218 || _Jv_equalUtf8Consts (method->name, clinit_name)
219 || _Jv_equalUtf8Consts (method->name, init_name))
221 java::lang::reflect::Method* rmethod = new java::lang::reflect::Method ();
222 rmethod->offset = (char*) mptr - (char*) elements (result);
223 rmethod->declaringClass = this;
230 java::lang::Class::getName (void)
232 char buffer[name->length + 1];
233 memcpy (buffer, name->data, name->length);
234 buffer[name->length] = '\0';
235 return _Jv_NewStringUTF (buffer);
239 java::lang::Class::getClasses (void)
246 java::lang::Class::getDeclaredClasses (void)
248 checkMemberAccess (java::lang::reflect::Member::DECLARED);
249 JvFail ("java::lang::Class::getDeclaredClasses not implemented");
250 return NULL; // Placate compiler.
253 // This is marked as unimplemented in the JCL book.
255 java::lang::Class::getDeclaringClass (void)
257 JvFail ("java::lang::Class::getDeclaringClass unimplemented");
258 return NULL; // Placate compiler.
261 JArray<java::lang::reflect::Field *> *
262 java::lang::Class::getFields (void)
264 JvFail ("java::lang::Class::getFields not implemented");
268 java::lang::Class::getInterfaces (void)
270 jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
271 jobject *data = elements (r);
272 for (int i = 0; i < interface_count; ++i)
273 data[i] = interfaces[i];
274 return reinterpret_cast<JArray<jclass> *> (r);
277 java::lang::reflect::Method *
278 java::lang::Class::getMethod (jstring, JArray<jclass> *)
280 JvFail ("java::lang::Class::getMethod not implemented");
283 JArray<java::lang::reflect::Method *> *
284 java::lang::Class::getMethods (void)
286 JvFail ("java::lang::Class::getMethods not implemented");
290 java::lang::Class::isAssignableFrom (jclass klass)
294 // Primitive types must be equal, which we just tested for.
295 if (isPrimitive () || ! klass || klass->isPrimitive())
298 // If target is array, so must source be.
301 if (! klass->isArray())
303 return getComponentType()->isAssignableFrom(klass->getComponentType());
306 if (isAssignableFrom (klass->getSuperclass()))
311 // See if source implements this interface.
312 for (int i = 0; i < klass->interface_count; ++i)
314 jclass interface = klass->interfaces[i];
315 // FIXME: ensure that class is prepared here.
317 if (isAssignableFrom (interface))
326 java::lang::Class::isInstance (jobject obj)
328 if (! obj || isPrimitive ())
330 return isAssignableFrom (obj->getClass());
334 java::lang::Class::isInterface (void)
336 return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
340 java::lang::Class::newInstance (void)
342 // FIXME: do accessibility checks here. There currently doesn't
343 // seem to be any way to do these.
344 // FIXME: we special-case one check here just to pass a Plum Hall
345 // test. Once access checking is implemented, remove this.
346 if (this == &ClassClass)
347 JvThrow (new java::lang::IllegalAccessException);
352 || java::lang::reflect::Modifier::isAbstract(accflags))
353 JvThrow (new java::lang::InstantiationException);
355 _Jv_InitClass (this);
357 _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
359 JvThrow (new java::lang::NoSuchMethodException);
361 jobject r = JvAllocObject (this);
362 ((void (*) (jobject)) meth->ncode) (r);
367 java::lang::Class::finalize (void)
370 JvAssert (_Jv_IsInterpretedClass (this));
371 _Jv_UnregisterClass (this);
377 java::lang::Class::hackRunInitializers (void)
379 _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, void_signature);
381 ((void (*) (void)) meth->ncode) ();
384 // This implements the initialization process for a class. From Spec
387 java::lang::Class::initializeClass (void)
389 // Short-circuit to avoid needless locking.
390 if (state == JV_STATE_DONE)
393 // do this before we enter the monitor below, since this can cause
394 // exceptions. Here we assume, that reading "state" is an atomic
395 // operation, I pressume that is true? --Kresten
396 if (state < JV_STATE_LINKED)
399 if (_Jv_IsInterpretedClass (this))
401 java::lang::ClassLoader::resolveClass0 (this);
404 _Jv_MonitorEnter (this);
410 _Jv_MonitorEnter (this);
411 _Jv_PrepareCompiledClass (this);
417 _Jv_MonitorEnter (this);
421 java::lang::Thread *self = java::lang::Thread::currentThread();
422 // FIXME: `self' can be null at startup. Hence this nasty trick.
423 self = (java::lang::Thread *) ((long) self | 1);
424 while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
428 if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self)
430 _Jv_MonitorExit (this);
435 if (state == JV_STATE_ERROR)
437 _Jv_MonitorExit (this);
438 JvThrow (new java::lang::NoClassDefFoundError);
443 state = JV_STATE_IN_PROGRESS;
444 _Jv_MonitorExit (this);
447 if (! isInterface () && superclass)
449 // FIXME: We can't currently catch a Java exception in C++ code.
450 // So instead we call a Java trampoline. It returns an
451 // exception, or null.
452 jobject except = superclass->hackTrampoline(0, NULL);
455 // Caught an exception.
456 _Jv_MonitorEnter (this);
457 state = JV_STATE_ERROR;
459 _Jv_MonitorExit (this);
465 // FIXME: once again we have to go through a trampoline.
466 java::lang::Throwable *except = hackTrampoline (1, NULL);
471 _Jv_MonitorEnter (this);
472 state = JV_STATE_DONE;
476 if (! ErrorClass.isInstance(except))
478 // Once again we must use the trampoline. In this case we
479 // have to detect an OutOfMemoryError.
480 except = hackTrampoline(2, except);
482 _Jv_MonitorEnter (this);
483 state = JV_STATE_ERROR;
486 _Jv_MonitorExit (this);
494 // Some class-related convenience functions.
498 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
499 _Jv_Utf8Const *signature)
501 for (int i = 0; i < klass->method_count; ++i)
503 if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
504 && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
505 return &klass->methods[i];
510 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
511 #define MCACHE_SIZE 1023
519 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
522 _Jv_FindMethodInCache (jclass klass,
524 _Jv_Utf8Const *signature)
526 int index = name->hash & MCACHE_SIZE;
527 _Jv_mcache *mc = method_cache + index;
528 _Jv_Method *m = mc->method;
530 if (mc->klass == klass
531 && m != NULL // thread safe check
532 && _Jv_equalUtf8Consts (m->name, name)
533 && _Jv_equalUtf8Consts (m->signature, signature))
534 return mc->method->ncode;
539 _Jv_AddMethodToCache (jclass klass,
542 _Jv_MonitorEnter (&ClassClass);
544 int index = method->name->hash & MCACHE_SIZE;
546 method_cache[index].method = method;
547 method_cache[index].klass = klass;
549 _Jv_MonitorExit (&ClassClass);
553 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
554 _Jv_Utf8Const *signature)
556 // FIXME: can't do this until we have a working class loader.
557 // This probably isn't the right thing to do anyway, since we can't
558 // call a method of a class until the class is linked. But this
559 // captures the general idea.
560 // klass->getClassLoader()->resolveClass(klass);
562 // KKT: This is unnessecary, exactly for the reason you present:
563 // _Jv_LookupInterfaceMethod is only called on object instances, and
564 // such have already been initialized (which includes resolving).
566 void *ncode = _Jv_FindMethodInCache (klass, name, signature);
570 for (; klass; klass = klass->getSuperclass())
572 _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
576 if (java::lang::reflect::Modifier::isStatic(meth->accflags))
577 JvThrow (new java::lang::IncompatibleClassChangeError);
578 if (java::lang::reflect::Modifier::isAbstract(meth->accflags))
579 JvThrow (new java::lang::AbstractMethodError);
580 if (! java::lang::reflect::Modifier::isPublic(meth->accflags))
581 JvThrow (new java::lang::IllegalAccessError);
583 _Jv_AddMethodToCache (klass, meth);
587 JvThrow (new java::lang::IncompatibleClassChangeError);
588 return NULL; // Placate compiler.
592 _Jv_InitClass (jclass klass)
594 klass->initializeClass();
598 _Jv_IsInstanceOf(jobject obj, jclass cl)
600 return cl->isInstance(obj);