OSDN Git Service

* java/lang/natClass.cc (MCACHE_SIZE): Define as a power of 2
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natClass.cc
1 // natClass.cc - Implementation of java.lang.Class native methods.
2
3 /* Copyright (C) 1998, 1999  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
42 #include <java-cpool.h>
43
44 \f
45
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;
58
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);
63
64 \f
65
66 jclass
67 java::lang::Class::forName (jstring className)
68 {
69   if (! className)
70     JvThrow (new java::lang::NullPointerException);
71
72 #if 0
73   // FIXME: should check syntax of CLASSNAME and throw
74   // IllegalArgumentException on failure.
75
76   // FIXME: should use class loader from calling method.
77   jclass klass = _Jv_FindClass (className, NULL);
78 #else
79   jsize length = _Jv_GetStringUTFLength (className);
80   char buffer[length];
81   _Jv_GetStringUTFRegion (className, 0, length, buffer);
82
83   // FIXME: should check syntax of CLASSNAME and throw
84   // IllegalArgumentException on failure.
85   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
86
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));
91 #endif
92   if (! klass)
93     JvThrow (new java::lang::ClassNotFoundException (className));
94
95   return klass;
96 }
97
98 java::lang::reflect::Constructor *
99 java::lang::Class::getConstructor (JArray<jclass> *)
100 {
101   JvFail ("java::lang::Class::getConstructor not implemented");
102 }
103
104 JArray<java::lang::reflect::Constructor *> *
105 java::lang::Class::getConstructors (void)
106 {
107   JvFail ("java::lang::Class::getConstructors not implemented");
108 }
109
110 java::lang::reflect::Constructor *
111 java::lang::Class::getDeclaredConstructor (JArray<jclass> *)
112 {
113   JvFail ("java::lang::Class::getDeclaredConstructor not implemented");
114 }
115
116 JArray<java::lang::reflect::Constructor *> *
117 java::lang::Class::getDeclaredConstructors (void)
118 {
119   JvFail ("java::lang::Class::getDeclaredConstructors not implemented");
120 }
121
122 java::lang::reflect::Field *
123 java::lang::Class::getField (jstring name, jint hash)
124 {
125   java::lang::reflect::Field* rfield;
126   for (int i = 0;  i < field_count;  i++)
127     {
128       _Jv_Field *field = &fields[i];
129       if (! _Jv_equal (field->name, name, hash))
130         continue;
131       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
132         continue;
133       rfield = new java::lang::reflect::Field ();
134       rfield->offset = (char*) field - (char*) fields;
135       rfield->declaringClass = this;
136       rfield->name = name;
137       return rfield;
138     }
139   jclass superclass = getSuperclass();
140   if (superclass == NULL)
141     return 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);
145   return rfield;
146 }
147
148 java::lang::reflect::Field *
149 java::lang::Class::getDeclaredField (jstring name)
150 {
151   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
152   if (s != NULL)
153     s->checkMemberAccess (this, java::lang::reflect::Member::DECLARED);
154   int hash = name->hashCode();
155   for (int i = 0;  i < field_count;  i++)
156     {
157       _Jv_Field *field = &fields[i];
158       if (! _Jv_equal (field->name, name, hash))
159         continue;
160       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
161       rfield->offset = (char*) field - (char*) fields;
162       rfield->declaringClass = this;
163       rfield->name = name;
164       return rfield;
165     }
166   JvThrow (new java::lang::NoSuchFieldException (name));
167 }
168
169 JArray<java::lang::reflect::Field *> *
170 java::lang::Class::getDeclaredFields (void)
171 {
172   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
173   if (s != NULL)
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++)
180     {
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;
185       *fptr++ = rfield;
186     }
187   return result;
188 }
189
190 java::lang::reflect::Method *
191 java::lang::Class::getDeclaredMethod (jstring, JArray<jclass> *)
192 {
193   JvFail ("java::lang::Class::getDeclaredMethod not implemented");
194 }
195
196 JArray<java::lang::reflect::Method *> *
197 java::lang::Class::getDeclaredMethods (void)
198 {
199   int numMethods = 0;
200   int i;
201   for (i = method_count;  --i >= 0; )
202     {
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))
207         continue;
208       numMethods++;
209     }
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++)
215     {
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))
220         continue;
221       java::lang::reflect::Method* rmethod = new java::lang::reflect::Method ();
222       rmethod->offset = (char*) mptr - (char*) elements (result);
223       rmethod->declaringClass = this;
224       *mptr++ = rmethod;
225     }
226   return result;
227 }
228
229 jstring
230 java::lang::Class::getName (void)
231 {
232   char buffer[name->length + 1];  
233   memcpy (buffer, name->data, name->length); 
234   buffer[name->length] = '\0';
235   return _Jv_NewStringUTF (buffer);
236 }
237
238 JArray<jclass> *
239 java::lang::Class::getClasses (void)
240 {
241   // FIXME: implement.
242   return NULL;
243 }
244
245 JArray<jclass> *
246 java::lang::Class::getDeclaredClasses (void)
247 {
248   checkMemberAccess (java::lang::reflect::Member::DECLARED);
249   JvFail ("java::lang::Class::getDeclaredClasses not implemented");
250   return NULL;                  // Placate compiler.
251 }
252
253 // This is marked as unimplemented in the JCL book.
254 jclass
255 java::lang::Class::getDeclaringClass (void)
256 {
257   JvFail ("java::lang::Class::getDeclaringClass unimplemented");
258   return NULL;                  // Placate compiler.
259 }
260
261 JArray<java::lang::reflect::Field *> *
262 java::lang::Class::getFields (void)
263 {
264   JvFail ("java::lang::Class::getFields not implemented");
265 }
266
267 JArray<jclass> *
268 java::lang::Class::getInterfaces (void)
269 {
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);
275 }
276
277 java::lang::reflect::Method *
278 java::lang::Class::getMethod (jstring, JArray<jclass> *)
279 {
280   JvFail ("java::lang::Class::getMethod not implemented");
281 }
282
283 JArray<java::lang::reflect::Method *> *
284 java::lang::Class::getMethods (void)
285 {
286   JvFail ("java::lang::Class::getMethods not implemented");
287 }
288
289 jboolean
290 java::lang::Class::isAssignableFrom (jclass klass)
291 {
292   if (this == klass)
293     return true;
294   // Primitive types must be equal, which we just tested for.
295   if (isPrimitive () || ! klass || klass->isPrimitive())
296     return false;
297
298   // If target is array, so must source be.
299   if (isArray ())
300     {
301       if (! klass->isArray())
302         return false;
303       return getComponentType()->isAssignableFrom(klass->getComponentType());
304     }
305
306   if (isAssignableFrom (klass->getSuperclass()))
307     return true;
308
309   if (isInterface())
310     {
311       // See if source implements this interface.
312       for (int i = 0; i < klass->interface_count; ++i)
313         {
314           jclass interface = klass->interfaces[i];
315           // FIXME: ensure that class is prepared here.
316           // See Spec 12.3.2.
317           if (isAssignableFrom (interface))
318             return true;
319         }
320     }
321
322   return false;
323 }
324
325 jboolean
326 java::lang::Class::isInstance (jobject obj)
327 {
328   if (! obj || isPrimitive ())
329     return false;
330   return isAssignableFrom (obj->getClass());
331 }
332
333 jboolean
334 java::lang::Class::isInterface (void)
335 {
336   return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0;
337 }
338
339 jobject
340 java::lang::Class::newInstance (void)
341 {
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);
348
349   if (isPrimitive ()
350       || isInterface ()
351       || isArray ()
352       || java::lang::reflect::Modifier::isAbstract(accflags))
353     JvThrow (new java::lang::InstantiationException);
354
355   _Jv_InitClass (this);
356
357   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
358   if (! meth)
359     JvThrow (new java::lang::NoSuchMethodException);
360
361   jobject r = JvAllocObject (this);
362   ((void (*) (jobject)) meth->ncode) (r);
363   return r;
364 }
365
366 void
367 java::lang::Class::finalize (void)
368 {
369 #ifdef INTERPRETER
370   JvAssert (_Jv_IsInterpretedClass (this));
371   _Jv_UnregisterClass (this);
372 #endif
373 }
374
375 // FIXME.
376 void
377 java::lang::Class::hackRunInitializers (void)
378 {
379   _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, void_signature);
380   if (meth)
381     ((void (*) (void)) meth->ncode) ();
382 }
383
384 // This implements the initialization process for a class.  From Spec
385 // section 12.4.2.
386 void
387 java::lang::Class::initializeClass (void)
388 {
389   // Short-circuit to avoid needless locking.
390   if (state == JV_STATE_DONE)
391     return;
392
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)
397     {
398 #ifdef INTERPRETER
399       if (_Jv_IsInterpretedClass (this))
400         {
401           java::lang::ClassLoader::resolveClass0 (this);
402
403           // Step 1.
404           _Jv_MonitorEnter (this);
405         }
406       else
407 #endif
408         {
409           // Step 1.
410           _Jv_MonitorEnter (this);
411           _Jv_PrepareCompiledClass (this);
412         }
413     }
414   else
415     {
416       // Step 1.
417       _Jv_MonitorEnter (this);
418     }
419
420   // Step 2.
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)
425     wait ();
426
427   // Steps 3 &  4.
428   if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS || thread == self)
429     {
430       _Jv_MonitorExit (this);
431       return;
432     }
433
434   // Step 5.
435   if (state == JV_STATE_ERROR)
436     {
437       _Jv_MonitorExit (this);
438       JvThrow (new java::lang::NoClassDefFoundError);
439     }
440
441   // Step 6.
442   thread = self;
443   state = JV_STATE_IN_PROGRESS;
444   _Jv_MonitorExit (this);
445
446   // Step 7.
447   if (! isInterface () && superclass)
448     {
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);
453       if (except)
454         {
455           // Caught an exception.
456           _Jv_MonitorEnter (this);
457           state = JV_STATE_ERROR;
458           notifyAll ();
459           _Jv_MonitorExit (this);
460           JvThrow (except);
461         }
462     }
463
464   // Step 8.
465   // FIXME: once again we have to go through a trampoline.
466   java::lang::Throwable *except = hackTrampoline (1, NULL);
467
468   // Steps 9, 10, 11.
469   if (! except)
470     {
471       _Jv_MonitorEnter (this);
472       state = JV_STATE_DONE;
473     }
474   else
475     {
476       if (! ErrorClass.isInstance(except))
477         {
478           // Once again we must use the trampoline.  In this case we
479           // have to detect an OutOfMemoryError.
480           except = hackTrampoline(2, except);
481         }
482       _Jv_MonitorEnter (this);
483       state = JV_STATE_ERROR;
484     }
485   notifyAll ();
486   _Jv_MonitorExit (this);
487   if (except)
488     JvThrow (except);
489 }
490
491 \f
492
493 //
494 // Some class-related convenience functions.
495 //
496
497 _Jv_Method *
498 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
499                     _Jv_Utf8Const *signature)
500 {
501   for (int i = 0; i < klass->method_count; ++i)
502     {
503       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
504           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
505         return &klass->methods[i];
506     }
507   return NULL;
508 }
509
510 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
511 #define MCACHE_SIZE 1023
512
513 struct _Jv_mcache
514 {
515   jclass klass;
516   _Jv_Method *method;
517 };
518
519 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
520
521 static void *
522 _Jv_FindMethodInCache (jclass klass,
523                        _Jv_Utf8Const *name,
524                        _Jv_Utf8Const *signature)
525 {
526   int index = name->hash & MCACHE_SIZE;
527   _Jv_mcache *mc = method_cache + index;
528   _Jv_Method *m = mc->method;
529
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;
535   return NULL;
536 }
537
538 static void
539 _Jv_AddMethodToCache (jclass klass,
540                         _Jv_Method *method)
541 {
542   _Jv_MonitorEnter (&ClassClass); 
543
544   int index = method->name->hash & MCACHE_SIZE;
545
546   method_cache[index].method = method;
547   method_cache[index].klass = klass;
548
549   _Jv_MonitorExit (&ClassClass);
550 }
551
552 void *
553 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
554                            _Jv_Utf8Const *signature)
555 {
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);
561   // 
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).
565
566   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
567   if (ncode != 0)
568     return ncode;
569
570   for (; klass; klass = klass->getSuperclass())
571     {
572       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
573       if (! meth)
574         continue;
575
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);
582
583       _Jv_AddMethodToCache (klass, meth);
584
585       return meth->ncode;
586     }
587   JvThrow (new java::lang::IncompatibleClassChangeError);
588   return NULL;                  // Placate compiler.
589 }
590
591 void
592 _Jv_InitClass (jclass klass)
593 {
594   klass->initializeClass();
595 }
596
597 jboolean
598 _Jv_IsInstanceOf(jobject obj, jclass cl)
599 {
600   return cl->isInstance(obj);
601 }