OSDN Git Service

f7793a56d56e862b700971242c93f9512e201351
[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, 2000, 2001, 2002, 2003  Free Software Foundation
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 <limits.h>
14 #include <string.h>
15 #include <stddef.h>
16
17 #pragma implementation "Class.h"
18
19 #include <gcj/cni.h>
20 #include <jvm.h>
21 #include <java-threads.h>
22
23 #include <java/lang/Class.h>
24 #include <java/lang/ClassLoader.h>
25 #include <java/lang/String.h>
26 #include <java/lang/reflect/Modifier.h>
27 #include <java/lang/reflect/Member.h>
28 #include <java/lang/reflect/Method.h>
29 #include <java/lang/reflect/Field.h>
30 #include <java/lang/reflect/Constructor.h>
31 #include <java/lang/AbstractMethodError.h>
32 #include <java/lang/ArrayStoreException.h>
33 #include <java/lang/ClassCastException.h>
34 #include <java/lang/ClassNotFoundException.h>
35 #include <java/lang/ExceptionInInitializerError.h>
36 #include <java/lang/IllegalAccessException.h>
37 #include <java/lang/IllegalAccessError.h>
38 #include <java/lang/IllegalArgumentException.h>
39 #include <java/lang/IncompatibleClassChangeError.h>
40 #include <java/lang/NoSuchFieldError.h>
41 #include <java/lang/ArrayIndexOutOfBoundsException.h>
42 #include <java/lang/InstantiationException.h>
43 #include <java/lang/NoClassDefFoundError.h>
44 #include <java/lang/NoSuchFieldException.h>
45 #include <java/lang/NoSuchMethodError.h>
46 #include <java/lang/NoSuchMethodException.h>
47 #include <java/lang/Thread.h>
48 #include <java/lang/NullPointerException.h>
49 #include <java/lang/RuntimePermission.h>
50 #include <java/lang/System.h>
51 #include <java/lang/SecurityManager.h>
52 #include <java/lang/StringBuffer.h>
53 #include <java/lang/VMClassLoader.h>
54 #include <gnu/gcj/runtime/StackTrace.h>
55 #include <gcj/method.h>
56 #include <gnu/gcj/runtime/MethodRef.h>
57 #include <gnu/gcj/RawData.h>
58
59 #include <java-cpool.h>
60 #include <java-interp.h>
61 \f
62
63 using namespace gcj;
64
65 jclass
66 java::lang::Class::forName (jstring className, jboolean initialize,
67                             java::lang::ClassLoader *loader)
68 {
69   if (! className)
70     throw new java::lang::NullPointerException;
71
72   jsize length = _Jv_GetStringUTFLength (className);
73   char buffer[length];
74   _Jv_GetStringUTFRegion (className, 0, length, buffer);
75
76   _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length);
77
78   if (! _Jv_VerifyClassName (name))
79     throw new java::lang::ClassNotFoundException (className);
80
81   jclass klass = (buffer[0] == '[' 
82                   ? _Jv_FindClassFromSignature (name->data, loader)
83                   : _Jv_FindClass (name, loader));
84
85   if (klass == NULL)
86     throw new java::lang::ClassNotFoundException (className);
87
88   if (initialize)
89     _Jv_InitClass (klass);
90
91   return klass;
92 }
93
94 jclass
95 java::lang::Class::forName (jstring className)
96 {
97   java::lang::ClassLoader *loader = NULL;
98   gnu::gcj::runtime::StackTrace *t 
99     = new gnu::gcj::runtime::StackTrace(4);
100   java::lang::Class *klass = NULL;
101   try
102     {
103       for (int i = 1; !klass; i++)
104         {
105           klass = t->classAt (i);
106         }
107       loader = klass->getClassLoaderInternal();
108     }
109   catch (::java::lang::ArrayIndexOutOfBoundsException *e)
110     {
111     }
112
113   return forName (className, true, loader);
114 }
115
116 java::lang::ClassLoader *
117 java::lang::Class::getClassLoader (void)
118 {
119   java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
120   if (s != NULL)
121     {
122       gnu::gcj::runtime::StackTrace *t 
123         = new gnu::gcj::runtime::StackTrace(4);
124       Class *caller = NULL;
125       ClassLoader *caller_loader = NULL;
126       try
127         {
128           for (int i = 1; !caller; i++)
129             {
130               caller = t->classAt (i);
131             }
132           caller_loader = caller->getClassLoaderInternal();
133         }
134       catch (::java::lang::ArrayIndexOutOfBoundsException *e)
135         {
136         }
137
138       // If the caller has a non-null class loader, and that loader
139       // is not this class' loader or an ancestor thereof, then do a
140       // security check.
141       if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader))
142         s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader")));
143     }
144
145   // The spec requires us to return `null' for primitive classes.  In
146   // other cases we have the option of returning `null' for classes
147   // loaded with the bootstrap loader.  All gcj-compiled classes which
148   // are linked into the application used to return `null' here, but
149   // that confuses some poorly-written applications.  It is a useful
150   // and apparently harmless compatibility hack to simply never return
151   // `null' instead.
152   if (isPrimitive ())
153     return NULL;
154   return loader ? loader : ClassLoader::getSystemClassLoader ();
155 }
156
157 java::lang::reflect::Constructor *
158 java::lang::Class::getConstructor (JArray<jclass> *param_types)
159 {
160   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
161
162   jstring partial_sig = getSignature (param_types, true);
163   jint hash = partial_sig->hashCode ();
164
165   int i = isPrimitive () ? 0 : method_count;
166   while (--i >= 0)
167     {
168       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
169           && _Jv_equal (methods[i].signature, partial_sig, hash))
170         {
171           // Found it.  For getConstructor, the constructor must be
172           // public.
173           using namespace java::lang::reflect;
174           if (! Modifier::isPublic(methods[i].accflags))
175             break;
176           Constructor *cons = new Constructor ();
177           cons->offset = (char *) (&methods[i]) - (char *) methods;
178           cons->declaringClass = this;
179           return cons;
180         }
181     }
182   throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name));
183 }
184
185 JArray<java::lang::reflect::Constructor *> *
186 java::lang::Class::_getConstructors (jboolean declared)
187 {
188   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
189
190   int numConstructors = 0;
191   int max = isPrimitive () ? 0 : method_count;
192   int i;
193   for (i = max; --i >= 0; )
194     {
195       _Jv_Method *method = &methods[i];
196       if (method->name == NULL
197           || ! _Jv_equalUtf8Consts (method->name, init_name))
198         continue;
199       if (! declared
200           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
201         continue;
202       numConstructors++;
203     }
204   JArray<java::lang::reflect::Constructor *> *result
205     = (JArray<java::lang::reflect::Constructor *> *)
206     JvNewObjectArray (numConstructors,
207                       &java::lang::reflect::Constructor::class$,
208                       NULL);
209   java::lang::reflect::Constructor** cptr = elements (result);
210   for (i = 0;  i < max;  i++)
211     {
212       _Jv_Method *method = &methods[i];
213       if (method->name == NULL
214           || ! _Jv_equalUtf8Consts (method->name, init_name))
215         continue;
216       if (! declared
217           && ! java::lang::reflect::Modifier::isPublic(method->accflags))
218         continue;
219       java::lang::reflect::Constructor *cons
220         = new java::lang::reflect::Constructor ();
221       cons->offset = (char *) method - (char *) methods;
222       cons->declaringClass = this;
223       *cptr++ = cons;
224     }
225   return result;
226 }
227
228 java::lang::reflect::Constructor *
229 java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types)
230 {
231   memberAccessCheck(java::lang::reflect::Member::DECLARED);
232
233   jstring partial_sig = getSignature (param_types, true);
234   jint hash = partial_sig->hashCode ();
235
236   int i = isPrimitive () ? 0 : method_count;
237   while (--i >= 0)
238     {
239       if (_Jv_equalUtf8Consts (methods[i].name, init_name)
240           && _Jv_equal (methods[i].signature, partial_sig, hash))
241         {
242           // Found it.
243           using namespace java::lang::reflect;
244           Constructor *cons = new Constructor ();
245           cons->offset = (char *) (&methods[i]) - (char *) methods;
246           cons->declaringClass = this;
247           return cons;
248         }
249     }
250   throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name));
251 }
252
253 java::lang::reflect::Field *
254 java::lang::Class::getField (jstring name, jint hash)
255 {
256   java::lang::reflect::Field* rfield;
257   for (int i = 0;  i < field_count;  i++)
258     {
259       _Jv_Field *field = &fields[i];
260       if (! _Jv_equal (field->name, name, hash))
261         continue;
262       if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC))
263         continue;
264       rfield = new java::lang::reflect::Field ();
265       rfield->offset = (char*) field - (char*) fields;
266       rfield->declaringClass = this;
267       rfield->name = name;
268       return rfield;
269     }
270   jclass superclass = getSuperclass();
271   if (superclass == NULL)
272     return NULL;
273   rfield = superclass->getField(name, hash);
274   for (int i = 0; i < interface_count && rfield == NULL; ++i)
275     rfield = interfaces[i]->getField (name, hash);
276   return rfield;
277 }
278
279 java::lang::reflect::Field *
280 java::lang::Class::getDeclaredField (jstring name)
281 {
282   memberAccessCheck(java::lang::reflect::Member::DECLARED);
283   int hash = name->hashCode();
284   for (int i = 0;  i < field_count;  i++)
285     {
286       _Jv_Field *field = &fields[i];
287       if (! _Jv_equal (field->name, name, hash))
288         continue;
289       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
290       rfield->offset = (char*) field - (char*) fields;
291       rfield->declaringClass = this;
292       rfield->name = name;
293       return rfield;
294     }
295   throw new java::lang::NoSuchFieldException (name);
296 }
297
298 JArray<java::lang::reflect::Field *> *
299 java::lang::Class::getDeclaredFields (jboolean public_only)
300 {
301   int size;
302   if (public_only)
303     {
304       size = 0;
305       for (int i = 0; i < field_count; ++i)
306         {
307           _Jv_Field *field = &fields[i];
308           if ((field->flags & java::lang::reflect::Modifier::PUBLIC))
309             ++size;
310         }
311     }
312   else
313     size = field_count;
314
315   JArray<java::lang::reflect::Field *> *result
316     = (JArray<java::lang::reflect::Field *> *)
317     JvNewObjectArray (size, &java::lang::reflect::Field::class$, NULL);
318   java::lang::reflect::Field** fptr = elements (result);
319   for (int i = 0;  i < field_count;  i++)
320     {
321       _Jv_Field *field = &fields[i];
322       if (public_only
323           && ! (field->flags & java::lang::reflect::Modifier::PUBLIC))
324         continue;
325       java::lang::reflect::Field* rfield = new java::lang::reflect::Field ();
326       rfield->offset = (char*) field - (char*) fields;
327       rfield->declaringClass = this;
328       *fptr++ = rfield;
329     }
330   return result;
331 }
332
333 void
334 java::lang::Class::getSignature (java::lang::StringBuffer *buffer)
335 {
336   if (isPrimitive())
337     buffer->append((jchar) method_count);
338   else
339     {
340       jstring name = getName();
341       if (name->charAt(0) != '[')
342         buffer->append((jchar) 'L');
343       buffer->append(name);
344       if (name->charAt(0) != '[')
345         buffer->append((jchar) ';');
346     }
347 }
348
349 // This doesn't have to be native.  It is an implementation detail
350 // only called from the C++ code, though, so maybe this is clearer.
351 jstring
352 java::lang::Class::getSignature (JArray<jclass> *param_types,
353                                  jboolean is_constructor)
354 {
355   java::lang::StringBuffer *buf = new java::lang::StringBuffer ();
356   buf->append((jchar) '(');
357   // A NULL param_types means "no parameters".
358   if (param_types != NULL)
359     {
360       jclass *v = elements (param_types);
361       for (int i = 0; i < param_types->length; ++i)
362         v[i]->getSignature(buf);
363     }
364   buf->append((jchar) ')');
365   if (is_constructor)
366     buf->append((jchar) 'V');
367   return buf->toString();
368 }
369
370 java::lang::reflect::Method *
371 java::lang::Class::_getDeclaredMethod (jstring name,
372                                        JArray<jclass> *param_types)
373 {
374   jstring partial_sig = getSignature (param_types, false);
375   jint p_len = partial_sig->length();
376   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
377   int i = isPrimitive () ? 0 : method_count;
378   while (--i >= 0)
379     {
380       if (_Jv_equalUtf8Consts (methods[i].name, utf_name)
381           && _Jv_equaln (methods[i].signature, partial_sig, p_len)
382           && (methods[i].accflags
383               & java::lang::reflect::Modifier::INVISIBLE) == 0)
384         {
385           // Found it.
386           using namespace java::lang::reflect;
387           Method *rmethod = new Method ();
388           rmethod->offset = (char*) (&methods[i]) - (char*) methods;
389           rmethod->declaringClass = this;
390           return rmethod;
391         }
392     }
393   return NULL;
394 }
395
396 JArray<java::lang::reflect::Method *> *
397 java::lang::Class::getDeclaredMethods (void)
398 {
399   memberAccessCheck(java::lang::reflect::Member::DECLARED);
400
401   int numMethods = 0;
402   int max = isPrimitive () ? 0 : method_count;
403   int i;
404   for (i = max; --i >= 0; )
405     {
406       _Jv_Method *method = &methods[i];
407       if (method->name == NULL
408           || _Jv_equalUtf8Consts (method->name, clinit_name)
409           || _Jv_equalUtf8Consts (method->name, init_name)
410           || _Jv_equalUtf8Consts (method->name, finit_name)
411           || (methods[i].accflags
412               & java::lang::reflect::Modifier::INVISIBLE) != 0)
413         continue;
414       numMethods++;
415     }
416   JArray<java::lang::reflect::Method *> *result
417     = (JArray<java::lang::reflect::Method *> *)
418     JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL);
419   java::lang::reflect::Method** mptr = elements (result);
420   for (i = 0;  i < max;  i++)
421     {
422       _Jv_Method *method = &methods[i];
423       if (method->name == NULL
424           || _Jv_equalUtf8Consts (method->name, clinit_name)
425           || _Jv_equalUtf8Consts (method->name, init_name)
426           || _Jv_equalUtf8Consts (method->name, finit_name)
427           || (methods[i].accflags
428               & java::lang::reflect::Modifier::INVISIBLE) != 0)
429         continue;
430       java::lang::reflect::Method* rmethod
431         = new java::lang::reflect::Method ();
432       rmethod->offset = (char*) method - (char*) methods;
433       rmethod->declaringClass = this;
434       *mptr++ = rmethod;
435     }
436   return result;
437 }
438
439 jstring
440 java::lang::Class::getName (void)
441 {
442   char buffer[name->length + 1];  
443   memcpy (buffer, name->data, name->length); 
444   buffer[name->length] = '\0';
445   return _Jv_NewStringUTF (buffer);
446 }
447
448 JArray<jclass> *
449 java::lang::Class::getClasses (void)
450 {
451   // FIXME: security checking.
452
453   // Until we have inner classes, it always makes sense to return an
454   // empty array.
455   JArray<jclass> *result
456     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
457                                            NULL);
458   return result;
459 }
460
461 JArray<jclass> *
462 java::lang::Class::getDeclaredClasses (void)
463 {
464   memberAccessCheck (java::lang::reflect::Member::DECLARED);
465   // Until we have inner classes, it always makes sense to return an
466   // empty array.
467   JArray<jclass> *result
468     = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
469                                            NULL);
470   return result;
471 }
472
473 jclass
474 java::lang::Class::getDeclaringClass (void)
475 {
476   // Until we have inner classes, it makes sense to always return
477   // NULL.
478   return NULL;
479 }
480
481 JArray<jclass> *
482 java::lang::Class::getInterfaces (void)
483 {
484   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
485   jobject *data = elements (r);
486   for (int i = 0; i < interface_count; ++i)
487     data[i] = interfaces[i];
488   return reinterpret_cast<JArray<jclass> *> (r);
489 }
490
491 java::lang::reflect::Method *
492 java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types)
493 {
494   jstring partial_sig = getSignature (param_types, false);
495   jint p_len = partial_sig->length();
496   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
497   for (Class *klass = this; klass; klass = klass->getSuperclass())
498     {
499       int i = klass->isPrimitive () ? 0 : klass->method_count;
500       while (--i >= 0)
501         {
502           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
503               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)
504               && (klass->methods[i].accflags
505                   & java::lang::reflect::Modifier::INVISIBLE) == 0)
506             {
507               // Found it.
508               using namespace java::lang::reflect;
509
510               // Method must be public.
511               if (! Modifier::isPublic (klass->methods[i].accflags))
512                 break;
513
514               Method *rmethod = new Method ();
515               rmethod->offset = ((char *) (&klass->methods[i])
516                                  - (char *) klass->methods);
517               rmethod->declaringClass = klass;
518               return rmethod;
519             }
520         }
521     }
522
523   // If we haven't found a match, and this class is an interface, then
524   // check all the superinterfaces.
525   if (isInterface())
526     {
527       for (int i = 0; i < interface_count; ++i)
528         {
529           using namespace java::lang::reflect;
530           Method *rmethod = interfaces[i]->_getMethod (name, param_types);
531           if (rmethod != NULL)
532             return rmethod;
533         }
534     }
535
536   return NULL;
537 }
538
539 // This is a very slow implementation, since it re-scans all the
540 // methods we've already listed to make sure we haven't duplicated a
541 // method.  It also over-estimates the required size, so we have to
542 // shrink the result array later.
543 jint
544 java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result,
545                                 jint offset)
546 {
547   jint count = 0;
548
549   // First examine all local methods
550   for (int i = isPrimitive () ? 0 : method_count; --i >= 0; )
551     {
552       _Jv_Method *method = &methods[i];
553       if (method->name == NULL
554           || _Jv_equalUtf8Consts (method->name, clinit_name)
555           || _Jv_equalUtf8Consts (method->name, init_name)
556           || _Jv_equalUtf8Consts (method->name, finit_name)
557           || (method->accflags
558               & java::lang::reflect::Modifier::INVISIBLE) != 0)
559         continue;
560       // Only want public methods.
561       if (! java::lang::reflect::Modifier::isPublic (method->accflags))
562         continue;
563
564       // This is where we over-count the slots required if we aren't
565       // filling the result for real.
566       if (result != NULL)
567         {
568           jboolean add = true;
569           java::lang::reflect::Method **mp = elements (result);
570           // If we already have a method with this name and signature,
571           // then ignore this one.  This can happen with virtual
572           // methods.
573           for (int j = 0; j < offset; ++j)
574             {
575               _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]);
576               if (_Jv_equalUtf8Consts (method->name, meth_2->name)
577                   && _Jv_equalUtf8Consts (method->signature,
578                                           meth_2->signature))
579                 {
580                   add = false;
581                   break;
582                 }
583             }
584           if (! add)
585             continue;
586         }
587
588       if (result != NULL)
589         {
590           using namespace java::lang::reflect;
591           Method *rmethod = new Method ();
592           rmethod->offset = (char *) method - (char *) methods;
593           rmethod->declaringClass = this;
594           Method **mp = elements (result);
595           mp[offset + count] = rmethod;
596         }
597       ++count;
598     }
599   offset += count;
600
601   // Now examine superclasses.
602   if (getSuperclass () != NULL)
603     {
604       jint s_count = getSuperclass()->_getMethods (result, offset);
605       offset += s_count;
606       count += s_count;
607     }
608
609   // Finally, examine interfaces.
610   for (int i = 0; i < interface_count; ++i)
611     {
612       int f_count = interfaces[i]->_getMethods (result, offset);
613       count += f_count;
614       offset += f_count;
615     }
616
617   return count;
618 }
619
620 JArray<java::lang::reflect::Method *> *
621 java::lang::Class::getMethods (void)
622 {
623   using namespace java::lang::reflect;
624
625   memberAccessCheck(Member::PUBLIC);
626
627   // This will overestimate the size we need.
628   jint count = _getMethods (NULL, 0);
629
630   JArray<Method *> *result
631     = ((JArray<Method *> *) JvNewObjectArray (count,
632                                               &Method::class$,
633                                               NULL));
634
635   // When filling the array for real, we get the actual count.  Then
636   // we resize the array.
637   jint real_count = _getMethods (result, 0);
638
639   if (real_count != count)
640     {
641       JArray<Method *> *r2
642         = ((JArray<Method *> *) JvNewObjectArray (real_count,
643                                                   &Method::class$,
644                                                   NULL));
645       
646       Method **destp = elements (r2);
647       Method **srcp = elements (result);
648
649       for (int i = 0; i < real_count; ++i)
650         *destp++ = *srcp++;
651
652       result = r2;
653     }
654
655   return result;
656 }
657
658 jboolean
659 java::lang::Class::isAssignableFrom (jclass klass)
660 {
661   // Arguments may not have been initialized, given ".class" syntax.
662   _Jv_InitClass (this);
663   _Jv_InitClass (klass);
664   return _Jv_IsAssignableFrom (this, klass);
665 }
666
667 jboolean
668 java::lang::Class::isInstance (jobject obj)
669 {
670   if (! obj)
671     return false;
672   _Jv_InitClass (this);
673   return _Jv_IsAssignableFrom (this, JV_CLASS (obj));
674 }
675
676 jobject
677 java::lang::Class::newInstance (void)
678 {
679   memberAccessCheck(java::lang::reflect::Member::PUBLIC);
680
681   if (isPrimitive ()
682       || isInterface ()
683       || isArray ()
684       || java::lang::reflect::Modifier::isAbstract(accflags))
685     throw new java::lang::InstantiationException (getName ());
686
687   _Jv_InitClass (this);
688
689   _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature);
690   if (! meth)
691     throw new java::lang::InstantiationException (getName());
692
693   jobject r = JvAllocObject (this);
694   ((void (*) (jobject)) meth->ncode) (r);
695   return r;
696 }
697
698 void
699 java::lang::Class::finalize (void)
700 {
701 #ifdef INTERPRETER
702   JvAssert (_Jv_IsInterpretedClass (this));
703   _Jv_UnregisterClass (this);
704 #endif
705 }
706
707 // This implements the initialization process for a class.  From Spec
708 // section 12.4.2.
709 void
710 java::lang::Class::initializeClass (void)
711 {
712   // short-circuit to avoid needless locking.
713   if (state == JV_STATE_DONE)
714     return;
715
716   // Step 1.
717   _Jv_MonitorEnter (this);
718
719   if (state < JV_STATE_LINKED)
720     {    
721 #ifdef INTERPRETER
722       if (_Jv_IsInterpretedClass (this))
723         {
724           // this can throw exceptions, so exit the monitor as a precaution.
725           _Jv_MonitorExit (this);
726           java::lang::VMClassLoader::resolveClass (this);
727           _Jv_MonitorEnter (this);
728         }
729       else
730 #endif
731         {
732           _Jv_PrepareCompiledClass (this);
733         }
734     }
735
736   // Step 2.
737   java::lang::Thread *self = java::lang::Thread::currentThread();
738   // FIXME: `self' can be null at startup.  Hence this nasty trick.
739   self = (java::lang::Thread *) ((long) self | 1);
740   while (state == JV_STATE_IN_PROGRESS && thread && thread != self)
741     wait ();
742
743   // Steps 3 &  4.
744   if (state == JV_STATE_DONE)
745     {
746       _Jv_MonitorExit (this);
747       return;
748     }
749   if (state == JV_STATE_IN_PROGRESS)
750     {
751       _Jv_MonitorExit (this);
752
753       /* Initialization in progress.  The class is linked now,
754          so ensure internal tables are built.  */
755       _Jv_PrepareConstantTimeTables (this);
756       _Jv_MakeVTable(this);
757       _Jv_LinkSymbolTable(this);
758
759       return;
760     }
761
762   // Step 5.
763   if (state == JV_STATE_ERROR)
764     {
765       _Jv_MonitorExit (this);
766       throw new java::lang::NoClassDefFoundError (getName());
767     }
768
769   // Step 6.
770   thread = self;
771   state = JV_STATE_IN_PROGRESS;
772   _Jv_MonitorExit (this);
773
774   // Step 7.
775   if (! isInterface () && superclass)
776     {
777       try
778         {
779           _Jv_InitClass (superclass);
780         }
781       catch (java::lang::Throwable *except)
782         {
783           // Caught an exception.
784           _Jv_MonitorEnter (this);
785           state = JV_STATE_ERROR;
786           notifyAll ();
787           _Jv_MonitorExit (this);
788           throw except;
789         }
790     }
791
792   _Jv_PrepareConstantTimeTables (this);
793
794   if (vtable == NULL)
795     _Jv_MakeVTable(this);
796
797   if (otable || atable)
798     _Jv_LinkSymbolTable(this);
799
800   _Jv_linkExceptionClassTable (this);
801
802   // Steps 8, 9, 10, 11.
803   try
804     {
805       _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name,
806                                              void_signature);
807       if (meth)
808         ((void (*) (void)) meth->ncode) ();
809     }
810   catch (java::lang::Throwable *except)
811     {
812       if (! java::lang::Error::class$.isInstance(except))
813         {
814           try
815             {
816               except = new ExceptionInInitializerError (except);
817             }
818           catch (java::lang::Throwable *t)
819             {
820               except = t;
821             }
822         }
823       _Jv_MonitorEnter (this);
824       state = JV_STATE_ERROR;
825       notifyAll ();
826       _Jv_MonitorExit (this);
827       throw except;
828     }
829
830   _Jv_MonitorEnter (this);
831   state = JV_STATE_DONE;
832   notifyAll ();
833   _Jv_MonitorExit (this);
834 }
835
836 \f
837
838 //
839 // Some class-related convenience functions.
840 //
841
842 // Find a method declared in the class.  If it is not declared locally
843 // (or if it is inherited), return NULL.
844 _Jv_Method *
845 _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name,
846                     _Jv_Utf8Const *signature)
847 {
848   for (int i = 0; i < klass->method_count; ++i)
849     {
850       if (_Jv_equalUtf8Consts (name, klass->methods[i].name)
851           && _Jv_equalUtf8Consts (signature, klass->methods[i].signature))
852         return &klass->methods[i];
853     }
854   return NULL;
855 }
856
857 _Jv_Method *
858 _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
859                           _Jv_Utf8Const *signature)
860 {
861   for (; klass; klass = klass->getSuperclass())
862     {
863       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
864
865       if (meth)
866         return meth;
867     }
868
869   return NULL;
870 }
871
872 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
873 #define MCACHE_SIZE 1023
874
875 struct _Jv_mcache
876 {
877   jclass klass;
878   _Jv_Method *method;
879 };
880
881 static _Jv_mcache method_cache[MCACHE_SIZE + 1];
882
883 static void *
884 _Jv_FindMethodInCache (jclass klass,
885                        _Jv_Utf8Const *name,
886                        _Jv_Utf8Const *signature)
887 {
888   int index = name->hash & MCACHE_SIZE;
889   _Jv_mcache *mc = method_cache + index;
890   _Jv_Method *m = mc->method;
891
892   if (mc->klass == klass
893       && m != NULL             // thread safe check
894       && _Jv_equalUtf8Consts (m->name, name)
895       && _Jv_equalUtf8Consts (m->signature, signature))
896     return mc->method->ncode;
897   return NULL;
898 }
899
900 static void
901 _Jv_AddMethodToCache (jclass klass,
902                        _Jv_Method *method)
903 {
904   _Jv_MonitorEnter (&java::lang::Class::class$); 
905
906   int index = method->name->hash & MCACHE_SIZE;
907
908   method_cache[index].method = method;
909   method_cache[index].klass = klass;
910
911   _Jv_MonitorExit (&java::lang::Class::class$);
912 }
913
914 void *
915 _Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
916                            _Jv_Utf8Const *signature)
917 {
918   using namespace java::lang::reflect;
919
920   void *ncode = _Jv_FindMethodInCache (klass, name, signature);
921   if (ncode != 0)
922     return ncode;
923
924   for (; klass; klass = klass->getSuperclass())
925     {
926       _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
927       if (! meth)
928         continue;
929
930       if (Modifier::isStatic(meth->accflags))
931         throw new java::lang::IncompatibleClassChangeError
932           (_Jv_GetMethodString (klass, meth->name));
933       if (Modifier::isAbstract(meth->accflags))
934         throw new java::lang::AbstractMethodError
935           (_Jv_GetMethodString (klass, meth->name));
936       if (! Modifier::isPublic(meth->accflags))
937         throw new java::lang::IllegalAccessError
938           (_Jv_GetMethodString (klass, meth->name));
939
940       _Jv_AddMethodToCache (klass, meth);
941
942       return meth->ncode;
943     }
944   throw new java::lang::IncompatibleClassChangeError;
945 }
946
947 // Fast interface method lookup by index.
948 void *
949 _Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx)
950 {
951   _Jv_IDispatchTable *cldt = klass->idt;
952   int idx = iface->idt->iface.ioffsets[cldt->cls.iindex] + method_idx;
953   return cldt->cls.itable[idx];
954 }
955
956 jboolean
957 _Jv_IsAssignableFrom (jclass target, jclass source)
958 {
959   if (source == target)
960     return true;
961
962   // If target is array, so must source be.  
963   while (target->isArray ())
964     {
965       if (! source->isArray())
966         return false;
967       target = target->getComponentType();
968       source = source->getComponentType();
969     }
970
971   if (target->isInterface())
972     {
973       // Abstract classes have no IDT, and IDTs provide no way to check
974       // two interfaces for assignability.
975       if (__builtin_expect 
976           (source->idt == NULL || source->isInterface(), false))
977         return _Jv_InterfaceAssignableFrom (target, source);
978
979       _Jv_IDispatchTable *cl_idt = source->idt;
980       _Jv_IDispatchTable *if_idt = target->idt;
981
982       if (__builtin_expect ((if_idt == NULL), false))
983         return false; // No class implementing TARGET has been loaded.    
984       jshort cl_iindex = cl_idt->cls.iindex;
985       if (cl_iindex < if_idt->iface.ioffsets[0])
986         {
987           jshort offset = if_idt->iface.ioffsets[cl_iindex];
988           if (offset != -1 && offset < cl_idt->cls.itable_length
989               && cl_idt->cls.itable[offset] == target)
990             return true;
991         }
992       return false;
993     }
994
995   // Primitive TYPE classes are only assignable to themselves.
996   if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false))
997     return false;
998
999   if (target == &java::lang::Object::class$)
1000     return true;
1001   else if (source->ancestors == NULL || target->ancestors == NULL)
1002     {
1003       // We need this case when either SOURCE or TARGET has not has
1004       // its constant-time tables prepared.
1005
1006       // At this point we know that TARGET can't be Object, so it is
1007       // safe to use that as the termination point.
1008       while (source && source != &java::lang::Object::class$)
1009         {
1010           if (source == target)
1011             return true;
1012           source = source->getSuperclass();
1013         }
1014     }
1015   else if (source->depth >= target->depth
1016            && source->ancestors[source->depth - target->depth] == target)
1017     return true;
1018
1019   return false;
1020 }
1021
1022 // Interface type checking, the slow way. Returns TRUE if IFACE is a 
1023 // superinterface of SOURCE. This is used when SOURCE is also an interface,
1024 // or a class with no interface dispatch table.
1025 jboolean
1026 _Jv_InterfaceAssignableFrom (jclass iface, jclass source)
1027 {
1028   for (int i = 0; i < source->interface_count; i++)
1029     {
1030       jclass interface = source->interfaces[i];
1031       if (iface == interface
1032           || _Jv_InterfaceAssignableFrom (iface, interface))
1033         return true;      
1034     }
1035     
1036   if (!source->isInterface()
1037       && source->superclass 
1038       && _Jv_InterfaceAssignableFrom (iface, source->superclass))
1039     return true;
1040         
1041   return false;
1042 }
1043
1044 jboolean
1045 _Jv_IsInstanceOf(jobject obj, jclass cl)
1046 {
1047   if (__builtin_expect (!obj, false))
1048     return false;
1049   return (_Jv_IsAssignableFrom (cl, JV_CLASS (obj)));
1050 }
1051
1052 void *
1053 _Jv_CheckCast (jclass c, jobject obj)
1054 {
1055   if (__builtin_expect 
1056        (obj != NULL && ! _Jv_IsAssignableFrom(c, JV_CLASS (obj)), false))
1057     throw new java::lang::ClassCastException
1058       ((new java::lang::StringBuffer
1059         (obj->getClass()->getName()))->append
1060        (JvNewStringUTF(" cannot be cast to "))->append
1061        (c->getName())->toString());
1062
1063   return obj;
1064 }
1065
1066 void
1067 _Jv_CheckArrayStore (jobject arr, jobject obj)
1068 {
1069   if (obj)
1070     {
1071       JvAssert (arr != NULL);
1072       jclass elt_class = (JV_CLASS (arr))->getComponentType();
1073       if (elt_class == &java::lang::Object::class$)
1074         return;
1075       jclass obj_class = JV_CLASS (obj);
1076       if (__builtin_expect 
1077           (! _Jv_IsAssignableFrom (elt_class, obj_class), false))
1078         throw new java::lang::ArrayStoreException
1079                 ((new java::lang::StringBuffer
1080                  (JvNewStringUTF("Cannot store ")))->append
1081                  (obj_class->getName())->append
1082                  (JvNewStringUTF(" in array of type "))->append
1083                  (elt_class->getName())->toString());
1084     }
1085 }
1086
1087 #define INITIAL_IOFFSETS_LEN 4
1088 #define INITIAL_IFACES_LEN 4
1089
1090 static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
1091
1092 // Generate tables for constant-time assignment testing and interface
1093 // method lookup. This implements the technique described by Per Bothner
1094 // <per@bothner.com> on the java-discuss mailing list on 1999-09-02:
1095 // http://gcc.gnu.org/ml/java/1999-q3/msg00377.html
1096 void 
1097 _Jv_PrepareConstantTimeTables (jclass klass)
1098 {  
1099   if (klass->isPrimitive () || klass->isInterface ())
1100     return;
1101   
1102   // Short-circuit in case we've been called already.
1103   if ((klass->idt != NULL) || klass->depth != 0)
1104     return;
1105
1106   // Calculate the class depth and ancestor table. The depth of a class 
1107   // is how many "extends" it is removed from Object. Thus the depth of 
1108   // java.lang.Object is 0, but the depth of java.io.FilterOutputStream 
1109   // is 2. Depth is defined for all regular and array classes, but not 
1110   // interfaces or primitive types.
1111    
1112   jclass klass0 = klass;
1113   jboolean has_interfaces = 0;
1114   while (klass0 != &java::lang::Object::class$)
1115     {
1116       has_interfaces += klass0->interface_count;
1117       klass0 = klass0->superclass;
1118       klass->depth++;
1119     }
1120
1121   // We do class member testing in constant time by using a small table 
1122   // of all the ancestor classes within each class. The first element is 
1123   // a pointer to the current class, and the rest are pointers to the 
1124   // classes ancestors, ordered from the current class down by decreasing 
1125   // depth. We do not include java.lang.Object in the table of ancestors, 
1126   // since it is redundant.
1127         
1128   klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass));
1129   klass0 = klass;
1130   for (int index = 0; index < klass->depth; index++)
1131     {
1132       klass->ancestors[index] = klass0;
1133       klass0 = klass0->superclass;
1134     }
1135     
1136   if (java::lang::reflect::Modifier::isAbstract (klass->accflags))
1137     return;
1138   
1139   // Optimization: If class implements no interfaces, use a common
1140   // predefined interface table.
1141   if (!has_interfaces)
1142     {
1143       klass->idt = &null_idt;
1144       return;
1145     }
1146
1147   klass->idt = 
1148     (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1149     
1150   _Jv_ifaces ifaces;
1151
1152   ifaces.count = 0;
1153   ifaces.len = INITIAL_IFACES_LEN;
1154   ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
1155
1156   int itable_size = _Jv_GetInterfaces (klass, &ifaces);
1157
1158   if (ifaces.count > 0)
1159     {
1160       klass->idt->cls.itable = 
1161         (void **) _Jv_Malloc (itable_size * sizeof (void *));
1162       klass->idt->cls.itable_length = itable_size;
1163           
1164       jshort *itable_offsets = 
1165         (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
1166
1167       _Jv_GenerateITable (klass, &ifaces, itable_offsets);
1168
1169       jshort cls_iindex = 
1170         _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count);
1171
1172       for (int i=0; i < ifaces.count; i++)
1173         {
1174           ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
1175             itable_offsets[i];
1176         }
1177
1178       klass->idt->cls.iindex = cls_iindex;          
1179
1180       _Jv_Free (ifaces.list);
1181       _Jv_Free (itable_offsets);
1182     }
1183   else 
1184     {
1185       klass->idt->cls.iindex = SHRT_MAX;
1186     }
1187 }
1188
1189 // Return index of item in list, or -1 if item is not present.
1190 inline jshort
1191 _Jv_IndexOf (void *item, void **list, jshort list_len)
1192 {
1193   for (int i=0; i < list_len; i++)
1194     {
1195       if (list[i] == item)
1196         return i;
1197     }
1198   return -1;
1199 }
1200
1201 // Find all unique interfaces directly or indirectly implemented by klass.
1202 // Returns the size of the interface dispatch table (itable) for klass, which 
1203 // is the number of unique interfaces plus the total number of methods that 
1204 // those interfaces declare. May extend ifaces if required.
1205 jshort
1206 _Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces)
1207 {
1208   jshort result = 0;
1209   
1210   for (int i=0; i < klass->interface_count; i++)
1211     {
1212       jclass iface = klass->interfaces[i];
1213
1214       /* Make sure interface is linked.  */
1215       _Jv_WaitForState(iface, JV_STATE_LINKED);
1216
1217       if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1)
1218         {
1219           if (ifaces->count + 1 >= ifaces->len)
1220             {
1221               /* Resize ifaces list */
1222               ifaces->len = ifaces->len * 2;
1223               ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, 
1224                              ifaces->len * sizeof(jclass));
1225             }
1226           ifaces->list[ifaces->count] = iface;
1227           ifaces->count++;
1228
1229           result += _Jv_GetInterfaces (klass->interfaces[i], ifaces);
1230         }
1231     }
1232     
1233   if (klass->isInterface())
1234     {
1235       result += klass->method_count + 1;
1236     }
1237   else
1238     {
1239       if (klass->superclass)
1240         {
1241           result += _Jv_GetInterfaces (klass->superclass, ifaces);
1242         }
1243     }
1244   return result;
1245 }
1246
1247 // Fill out itable in klass, resolving method declarations in each ifaces.
1248 // itable_offsets is filled out with the position of each iface in itable,
1249 // such that itable[itable_offsets[n]] == ifaces.list[n].
1250 void
1251 _Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets)
1252 {
1253   void **itable = klass->idt->cls.itable;
1254   jshort itable_pos = 0;
1255
1256   for (int i=0; i < ifaces->count; i++)
1257     { 
1258       jclass iface = ifaces->list[i];
1259       itable_offsets[i] = itable_pos;
1260       itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos);
1261       
1262       /* Create interface dispatch table for iface */
1263       if (iface->idt == NULL)
1264         {
1265           iface->idt = 
1266             (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
1267
1268           // The first element of ioffsets is its length (itself included).
1269           jshort *ioffsets = 
1270             (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort));
1271           ioffsets[0] = INITIAL_IOFFSETS_LEN;
1272           for (int i=1; i < INITIAL_IOFFSETS_LEN; i++)
1273             ioffsets[i] = -1;
1274
1275           iface->idt->iface.ioffsets = ioffsets;            
1276         }
1277     }
1278 }
1279
1280 // Format method name for use in error messages.
1281 jstring
1282 _Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name)
1283 {
1284   jstring r = JvNewStringUTF (klass->name->data);
1285   r = r->concat (JvNewStringUTF ("."));
1286   r = r->concat (JvNewStringUTF (name->data));
1287   return r;
1288 }
1289
1290 void 
1291 _Jv_ThrowNoSuchMethodError ()
1292 {
1293   throw new java::lang::NoSuchMethodError;
1294 }
1295
1296 // Each superinterface of a class (i.e. each interface that the class
1297 // directly or indirectly implements) has a corresponding "Partial
1298 // Interface Dispatch Table" whose size is (number of methods + 1) words.
1299 // The first word is a pointer to the interface (i.e. the java.lang.Class
1300 // instance for that interface).  The remaining words are pointers to the
1301 // actual methods that implement the methods declared in the interface,
1302 // in order of declaration.
1303 //
1304 // Append partial interface dispatch table for "iface" to "itable", at
1305 // position itable_pos.
1306 // Returns the offset at which the next partial ITable should be appended.
1307 jshort
1308 _Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, 
1309                          jshort pos)
1310 {
1311   using namespace java::lang::reflect;
1312
1313   itable[pos++] = (void *) iface;
1314   _Jv_Method *meth;
1315   
1316   for (int j=0; j < iface->method_count; j++)
1317     {
1318       meth = NULL;
1319       for (jclass cl = klass; cl; cl = cl->getSuperclass())
1320         {
1321           meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
1322                                      iface->methods[j].signature);
1323                  
1324           if (meth)
1325             break;
1326         }
1327
1328       if (meth && (meth->name->data[0] == '<'))
1329         {
1330           // leave a placeholder in the itable for hidden init methods.
1331           itable[pos] = NULL;   
1332         }
1333       else if (meth)
1334         {
1335           if (Modifier::isStatic(meth->accflags))
1336             throw new java::lang::IncompatibleClassChangeError
1337               (_Jv_GetMethodString (klass, meth->name));
1338           if (Modifier::isAbstract(meth->accflags))
1339             throw new java::lang::AbstractMethodError
1340               (_Jv_GetMethodString (klass, meth->name));
1341           if (! Modifier::isPublic(meth->accflags))
1342             throw new java::lang::IllegalAccessError
1343               (_Jv_GetMethodString (klass, meth->name));
1344
1345           itable[pos] = meth->ncode;
1346         }
1347       else
1348         {
1349           // The method doesn't exist in klass. Binary compatibility rules
1350           // permit this, so we delay the error until runtime using a pointer
1351           // to a method which throws an exception.
1352           itable[pos] = (void *) _Jv_ThrowNoSuchMethodError;
1353         }
1354       pos++;
1355     }
1356     
1357   return pos;
1358 }
1359
1360 static _Jv_Mutex_t iindex_mutex;
1361 static bool iindex_mutex_initialized = false;
1362
1363 // We need to find the correct offset in the Class Interface Dispatch 
1364 // Table for a given interface. Once we have that, invoking an interface 
1365 // method just requires combining the Method's index in the interface 
1366 // (known at compile time) to get the correct method.  Doing a type test 
1367 // (cast or instanceof) is the same problem: Once we have a possible Partial 
1368 // Interface Dispatch Table, we just compare the first element to see if it 
1369 // matches the desired interface. So how can we find the correct offset?  
1370 // Our solution is to keep a vector of candiate offsets in each interface 
1371 // (idt->iface.ioffsets), and in each class we have an index 
1372 // (idt->cls.iindex) used to select the correct offset from ioffsets.
1373 //
1374 // Calculate and return iindex for a new class. 
1375 // ifaces is a vector of num interfaces that the class implements.
1376 // offsets[j] is the offset in the interface dispatch table for the
1377 // interface corresponding to ifaces[j].
1378 // May extend the interface ioffsets if required.
1379 jshort
1380 _Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num)
1381 {
1382   int i;
1383   int j;
1384   
1385   // Acquire a global lock to prevent itable corruption in case of multiple 
1386   // classes that implement an intersecting set of interfaces being linked
1387   // simultaneously. We can assume that the mutex will be initialized
1388   // single-threaded.
1389   if (! iindex_mutex_initialized)
1390     {
1391       _Jv_MutexInit (&iindex_mutex);
1392       iindex_mutex_initialized = true;
1393     }
1394   
1395   _Jv_MutexLock (&iindex_mutex);
1396   
1397   for (i=1;; i++)  /* each potential position in ioffsets */
1398     {
1399       for (j=0;; j++)  /* each iface */
1400         {
1401           if (j >= num)
1402             goto found;
1403           if (i >= ifaces[j]->idt->iface.ioffsets[0])
1404             continue;
1405           int ioffset = ifaces[j]->idt->iface.ioffsets[i];
1406           /* We can potentially share this position with another class. */
1407           if (ioffset >= 0 && ioffset != offsets[j])
1408             break; /* Nope. Try next i. */        
1409         }
1410     }
1411   found:
1412   for (j = 0; j < num; j++)
1413     {
1414       int len = ifaces[j]->idt->iface.ioffsets[0];
1415       if (i >= len) 
1416         {
1417           /* Resize ioffsets. */
1418           int newlen = 2 * len;
1419           if (i >= newlen)
1420             newlen = i + 3;
1421           jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
1422           jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, 
1423                                           newlen * sizeof(jshort));       
1424           new_ioffsets[0] = newlen;
1425
1426           while (len < newlen)
1427             new_ioffsets[len++] = -1;
1428           
1429           ifaces[j]->idt->iface.ioffsets = new_ioffsets;
1430         }
1431       ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
1432     }
1433
1434   _Jv_MutexUnlock (&iindex_mutex);
1435
1436   return i;
1437 }
1438
1439 // Only used by serialization
1440 java::lang::reflect::Field *
1441 java::lang::Class::getPrivateField (jstring name)
1442 {
1443   int hash = name->hashCode ();
1444
1445   java::lang::reflect::Field* rfield;
1446   for (int i = 0;  i < field_count;  i++)
1447     {
1448       _Jv_Field *field = &fields[i];
1449       if (! _Jv_equal (field->name, name, hash))
1450         continue;
1451       rfield = new java::lang::reflect::Field ();
1452       rfield->offset = (char*) field - (char*) fields;
1453       rfield->declaringClass = this;
1454       rfield->name = name;
1455       return rfield;
1456     }
1457   jclass superclass = getSuperclass();
1458   if (superclass == NULL)
1459     return NULL;
1460   rfield = superclass->getPrivateField(name);
1461   for (int i = 0; i < interface_count && rfield == NULL; ++i)
1462     rfield = interfaces[i]->getPrivateField (name);
1463   return rfield;
1464 }
1465
1466 // Only used by serialization
1467 java::lang::reflect::Method *
1468 java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types)
1469 {
1470   jstring partial_sig = getSignature (param_types, false);
1471   jint p_len = partial_sig->length();
1472   _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name);
1473   for (Class *klass = this; klass; klass = klass->getSuperclass())
1474     {
1475       int i = klass->isPrimitive () ? 0 : klass->method_count;
1476       while (--i >= 0)
1477         {
1478           if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name)
1479               && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len))
1480             {
1481               // Found it.
1482               using namespace java::lang::reflect;
1483
1484               Method *rmethod = new Method ();
1485               rmethod->offset = ((char *) (&klass->methods[i])
1486                                  - (char *) klass->methods);
1487               rmethod->declaringClass = klass;
1488               return rmethod;
1489             }
1490         }
1491     }
1492   throw new java::lang::NoSuchMethodException (name);
1493 }
1494
1495 // Private accessor method for Java code to retrieve the protection domain.
1496 java::security::ProtectionDomain *
1497 java::lang::Class::getProtectionDomain0 ()
1498 {
1499   return protectionDomain;
1500 }
1501
1502 JArray<jobject> *
1503 java::lang::Class::getSigners()
1504 {
1505   return signers;
1506 }
1507
1508 void
1509 java::lang::Class::setSigners(JArray<jobject> *s)
1510 {
1511   signers = s;
1512 }
1513
1514 // Functions for indirect dispatch (symbolic virtual binding) support.
1515
1516 // There are two tables, atable and otable.  atable is an array of
1517 // addresses, and otable is an array of offsets, and these are used
1518 // for static and virtual members respectively.
1519
1520 // {a,o}table_syms is an array of _Jv_MethodSymbols.  Each such symbol
1521 // is a tuple of {classname, member name, signature}.
1522 // _Jv_LinkSymbolTable() scans these two arrays and fills in the
1523 // corresponding atable and otable with the addresses of static
1524 // members and the offsets of virtual members.
1525
1526 // The offset (in bytes) for each resolved method or field is placed
1527 // at the corresponding position in the virtual method offset table
1528 // (klass->otable). 
1529
1530 // The same otable and atable may be shared by many classes.
1531
1532 void
1533 _Jv_LinkSymbolTable(jclass klass)
1534 {
1535   //// FIXME: Need to lock the tables ////
1536   
1537   int index = 0;
1538   _Jv_MethodSymbol sym;
1539   if (klass->otable == NULL
1540       || klass->otable->state != 0)
1541     goto atable;
1542    
1543   klass->otable->state = 1;
1544
1545   for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++)
1546     {
1547       // FIXME: Why are we passing NULL as the class loader?
1548       jclass target_class = _Jv_FindClass (sym.class_name, NULL);
1549       _Jv_Method *meth = NULL;            
1550
1551       const _Jv_Utf8Const *signature = sym.signature;
1552
1553       {
1554         static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
1555         ptrdiff_t offset = (char *)(klass->vtable) - bounce;
1556         klass->otable->offsets[index] = offset;
1557       }
1558
1559       if (target_class == NULL)
1560         continue;
1561
1562       if (target_class->isInterface())
1563         {
1564           // FIXME: This does not yet fully conform to binary compatibility
1565           // rules. It will break if a declaration is moved into a 
1566           // superinterface.
1567           for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
1568             {
1569               for (int i=0; i < cls->method_count; i++)
1570                 {
1571                   meth = &cls->methods[i];
1572                   if (_Jv_equalUtf8Consts (sym.name, meth->name)
1573                       && _Jv_equalUtf8Consts (signature, meth->signature))
1574                     {
1575                       klass->otable->offsets[index] = i + 1;
1576                       goto found;
1577                     }
1578                 }
1579             
1580             }
1581         found:
1582           continue;
1583         }
1584
1585       // We're looking for a field or a method, and we can tell
1586       // which is needed by looking at the signature.
1587       if (signature->length >= 2
1588           && signature->data[0] == '(')
1589         {
1590           // If the target class does not have a vtable_method_count yet, 
1591           // then we can't tell the offsets for its methods, so we must lay 
1592           // it out now.
1593           if (target_class->vtable_method_count == -1)
1594             {
1595               JvSynchronize sync (target_class);
1596               _Jv_LayoutVTableMethods (target_class);
1597             }
1598                 
1599           meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
1600                                           sym.signature);
1601                 
1602           if (meth != NULL)
1603             {
1604               klass->otable->offsets[index] = 
1605                 _Jv_VTable::idx_to_offset (meth->index);              
1606             }
1607
1608           continue;
1609         }
1610
1611       // try fields
1612       {
1613         _Jv_Field *the_field = NULL;
1614
1615         for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
1616           {
1617             for (int i = 0; i < cls->field_count; i++)
1618               {
1619                 _Jv_Field *field = &cls->fields[i];
1620                 if (! _Jv_equalUtf8Consts (field->name, sym.name))
1621                   continue;
1622
1623                 // FIXME: What access checks should we perform here?
1624 //              if (_Jv_CheckAccess (klass, cls, field->flags))
1625 //                {
1626
1627                 if (!field->isResolved ())
1628                   _Jv_ResolveField (field, cls->loader);
1629
1630 //              if (field_type != 0 && field->type != field_type)
1631 //                throw new java::lang::LinkageError
1632 //                  (JvNewStringLatin1 
1633 //                   ("field type mismatch with different loaders"));
1634
1635                 the_field = field;
1636                 goto end_of_field_search;
1637               }
1638           }
1639       end_of_field_search:
1640         if (the_field != NULL)
1641           {
1642             if (the_field->flags & 0x0008 /* Modifier::STATIC */)
1643               {       
1644                 throw new java::lang::IncompatibleClassChangeError;
1645               }
1646             else
1647               {
1648                 klass->otable->offsets[index] = the_field->u.boffset;
1649               }
1650           }
1651         else
1652           {
1653             throw new java::lang::NoSuchFieldError
1654               (_Jv_NewStringUtf8Const (sym.name));
1655           }
1656       }
1657     }
1658
1659  atable:
1660   if (klass->atable == NULL
1661       || klass->atable->state != 0)
1662     return;
1663
1664   klass->atable->state = 1;
1665
1666   for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++)
1667     {
1668       // FIXME: Why are we passing NULL as the class loader?
1669       jclass target_class = _Jv_FindClass (sym.class_name, NULL);
1670       _Jv_Method *meth = NULL;            
1671       const _Jv_Utf8Const *signature = sym.signature;
1672
1673       // ??? Setting this pointer to null will at least get us a
1674       // NullPointerException
1675       klass->atable->addresses[index] = NULL;
1676       
1677       if (target_class == NULL)
1678         continue;
1679       
1680       // We're looking for a static field or a static method, and we
1681       // can tell which is needed by looking at the signature.
1682       if (signature->length >= 2
1683           && signature->data[0] == '(')
1684         {
1685           // If the target class does not have a vtable_method_count yet, 
1686           // then we can't tell the offsets for its methods, so we must lay 
1687           // it out now.
1688           if (target_class->vtable_method_count == -1)
1689             {
1690               JvSynchronize sync (target_class);
1691               _Jv_LayoutVTableMethods (target_class);
1692             }
1693           
1694           meth = _Jv_LookupDeclaredMethod(target_class, sym.name, 
1695                                           sym.signature);
1696           
1697           if (meth != NULL)
1698             {
1699               if (meth->ncode) // Maybe abstract?
1700                 klass->atable->addresses[index] = meth->ncode;
1701 #ifdef INTERPRETER
1702               else if (_Jv_IsInterpretedClass (target_class))
1703                 _Jv_Defer_Resolution (target_class, meth, 
1704                                       &klass->atable->addresses[index]);
1705 #endif
1706             }
1707           else
1708             klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError;
1709
1710           continue;
1711         }
1712
1713       // try fields
1714       {
1715         _Jv_Field *the_field = NULL;
1716
1717         for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ())
1718           {
1719             for (int i = 0; i < cls->field_count; i++)
1720               {
1721                 _Jv_Field *field = &cls->fields[i];
1722                 if (! _Jv_equalUtf8Consts (field->name, sym.name))
1723                   continue;
1724
1725                 // FIXME: What access checks should we perform here?
1726 //              if (_Jv_CheckAccess (klass, cls, field->flags))
1727 //                {
1728
1729                 if (!field->isResolved ())
1730                   _Jv_ResolveField (field, cls->loader);
1731                 
1732 //              if (field_type != 0 && field->type != field_type)
1733 //                throw new java::lang::LinkageError
1734 //                  (JvNewStringLatin1 
1735 //                   ("field type mismatch with different loaders"));
1736
1737                 the_field = field;
1738                 goto end_of_static_field_search;
1739               }
1740           }
1741       end_of_static_field_search:
1742         if (the_field != NULL)
1743           {
1744             if (the_field->flags & 0x0008 /* Modifier::STATIC */)
1745               {       
1746                 klass->atable->addresses[index] = the_field->u.addr;
1747               }
1748             else
1749               {
1750                 throw new java::lang::IncompatibleClassChangeError;
1751               }
1752           }
1753         else
1754           {
1755             throw new java::lang::NoSuchFieldError
1756               (_Jv_NewStringUtf8Const (sym.name));
1757           }
1758       }
1759     }
1760 }
1761
1762
1763 // For each catch_record in the list of caught classes, fill in the
1764 // address field.
1765 void 
1766 _Jv_linkExceptionClassTable (jclass self)
1767 {
1768   struct _Jv_CatchClass *catch_record = self->catch_classes;
1769   if (!catch_record || catch_record->classname)
1770     return;  
1771   catch_record++;
1772   while (catch_record->classname)
1773     {
1774       jclass target_class = _Jv_FindClass (catch_record->classname,  
1775                                            self->getClassLoaderInternal ());
1776       *catch_record->address = target_class;
1777       catch_record++;
1778     }
1779   self->catch_classes->classname = (_Jv_Utf8Const *)-1;
1780 }
1781   
1782 // This is put in empty vtable slots.
1783 static void
1784 _Jv_abstractMethodError (void)
1785 {
1786   throw new java::lang::AbstractMethodError();
1787 }
1788
1789 // Prepare virtual method declarations in KLASS, and any superclasses as 
1790 // required, by determining their vtable index, setting method->index, and
1791 // finally setting the class's vtable_method_count. Must be called with the
1792 // lock for KLASS held.
1793 void
1794 _Jv_LayoutVTableMethods (jclass klass)
1795 {
1796   if (klass->vtable != NULL || klass->isInterface() 
1797       || klass->vtable_method_count != -1)
1798     return;
1799
1800   jclass superclass = klass->superclass;
1801
1802   typedef unsigned int uaddr __attribute__ ((mode (pointer)));
1803
1804   // If superclass looks like a constant pool entry,
1805   // resolve it now.
1806   if ((uaddr)superclass < (uaddr)klass->constants.size)
1807     {
1808       if (klass->state < JV_STATE_LINKED)
1809         {
1810           _Jv_Utf8Const *name = klass->constants.data[(int)superclass].utf8;
1811           superclass = _Jv_FindClass (name, klass->loader);
1812           if (! superclass)
1813             {
1814               jstring str = _Jv_NewStringUTF (name->data);
1815               throw new java::lang::NoClassDefFoundError (str);
1816             }
1817         }
1818       else
1819         superclass = klass->constants.data[(int)superclass].clazz;
1820     }
1821
1822   if (superclass != NULL && superclass->vtable_method_count == -1)
1823     {
1824       JvSynchronize sync (superclass);
1825       _Jv_LayoutVTableMethods (superclass);
1826     }
1827
1828   int index = (superclass == NULL ? 0 : superclass->vtable_method_count);
1829
1830   for (int i = 0; i < klass->method_count; ++i)
1831     {
1832       _Jv_Method *meth = &klass->methods[i];
1833       _Jv_Method *super_meth = NULL;
1834
1835       if (! _Jv_isVirtualMethod (meth))
1836         continue;
1837
1838       // FIXME: Must check that we don't override:
1839       // - Package-private method where superclass is in different package.
1840       // - Final or less-accessible declaration in superclass (check binary 
1841       //   spec, do we allocate new vtable entry or put throw node in vtable?)
1842       // - Static or private method in superclass.
1843
1844       if (superclass != NULL)
1845         {
1846           super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, 
1847                                                  meth->signature);
1848         }
1849
1850       if (super_meth)
1851         meth->index = super_meth->index;
1852       else
1853         meth->index = index++;
1854     }
1855
1856   klass->vtable_method_count = index;
1857 }
1858
1859 // Set entries in VTABLE for virtual methods declared in KLASS. If
1860 // KLASS has an immediate abstract parent, recursively do its methods
1861 // first.  FLAGS is used to determine which slots we've actually set.
1862 void
1863 _Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags)
1864 {
1865   using namespace java::lang::reflect;
1866
1867   jclass superclass = klass->getSuperclass();
1868
1869   if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
1870     _Jv_SetVTableEntries (superclass, vtable, flags);
1871
1872   for (int i = klass->method_count - 1; i >= 0; i--)
1873     {
1874       _Jv_Method *meth = &klass->methods[i];
1875       if (meth->index == (_Jv_ushort) -1)
1876         continue;
1877       if ((meth->accflags & Modifier::ABSTRACT))
1878         {
1879           vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError);
1880           flags[meth->index] = false;
1881         }
1882       else
1883         {
1884           vtable->set_method(meth->index, meth->ncode);
1885           flags[meth->index] = true;
1886         }
1887     }
1888 }
1889
1890 // Allocate and lay out the virtual method table for KLASS. This will also
1891 // cause vtables to be generated for any non-abstract superclasses, and
1892 // virtual method layout to occur for any abstract superclasses. Must be
1893 // called with monitor lock for KLASS held.
1894 void
1895 _Jv_MakeVTable (jclass klass)
1896 {
1897   using namespace java::lang::reflect;  
1898
1899   if (klass->vtable != NULL || klass->isInterface() 
1900       || (klass->accflags & Modifier::ABSTRACT))
1901     return;
1902
1903   //  out before we can create a vtable. 
1904   if (klass->vtable_method_count == -1)
1905     _Jv_LayoutVTableMethods (klass);
1906
1907   // Allocate the new vtable.
1908   _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
1909   klass->vtable = vtable;
1910
1911   jboolean flags[klass->vtable_method_count];
1912   for (int i = 0; i < klass->vtable_method_count; ++i)
1913     flags[i] = false;
1914
1915   // Copy the vtable of the closest non-abstract superclass.
1916   jclass superclass = klass->superclass;
1917   if (superclass != NULL)
1918     {
1919       while ((superclass->accflags & Modifier::ABSTRACT) != 0)
1920         superclass = superclass->superclass;
1921
1922       if (superclass->vtable == NULL)
1923         {
1924           JvSynchronize sync (superclass);
1925           _Jv_MakeVTable (superclass);
1926         }
1927
1928       for (int i = 0; i < superclass->vtable_method_count; ++i)
1929         {
1930           vtable->set_method (i, superclass->vtable->get_method (i));
1931           flags[i] = true;
1932         }
1933     }
1934
1935   // Set the class pointer and GC descriptor.
1936   vtable->clas = klass;
1937   vtable->gc_descr = _Jv_BuildGCDescr (klass);
1938
1939   // For each virtual declared in klass and any immediate abstract 
1940   // superclasses, set new vtable entry or override an old one.
1941   _Jv_SetVTableEntries (klass, vtable, flags);
1942
1943   // It is an error to have an abstract method in a concrete class.
1944   if (! (klass->accflags & Modifier::ABSTRACT))
1945     {
1946       for (int i = 0; i < klass->vtable_method_count; ++i)
1947         if (! flags[i])
1948           {
1949             using namespace java::lang;
1950             while (klass != NULL)
1951               {
1952                 for (int j = 0; j < klass->method_count; ++j)
1953                   {
1954                     if (klass->methods[i].index == i)
1955                       {
1956                         StringBuffer *buf = new StringBuffer ();
1957                         buf->append (_Jv_NewStringUtf8Const (klass->methods[i].name));
1958                         buf->append ((jchar) ' ');
1959                         buf->append (_Jv_NewStringUtf8Const (klass->methods[i].signature));
1960                         throw new AbstractMethodError (buf->toString ());
1961                       }
1962                   }
1963                 klass = klass->getSuperclass ();
1964               }
1965             // Couldn't find the name, which is weird.
1966             // But we still must throw the error.
1967             throw new AbstractMethodError ();
1968           }
1969     }
1970 }