OSDN Git Service

* resolve.cc: Include StringBuffer.
[pf3gnuchains/gcc-fork.git] / libjava / resolve.cc
1 // resolve.cc - Code for linking and resolving classes and pool entries.
2
3 /* Copyright (C) 1999, 2000, 2001 , 2002 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 /* Author: Kresten Krab Thorup <krab@gnu.org>  */
12
13 #include <config.h>
14
15 #include <java-interp.h>
16
17 #include <jvm.h>
18 #include <gcj/cni.h>
19 #include <string.h>
20 #include <java-cpool.h>
21 #include <java/lang/Class.h>
22 #include <java/lang/String.h>
23 #include <java/lang/StringBuffer.h>
24 #include <java/lang/Thread.h>
25 #include <java/lang/InternalError.h>
26 #include <java/lang/VirtualMachineError.h>
27 #include <java/lang/NoSuchFieldError.h>
28 #include <java/lang/NoSuchMethodError.h>
29 #include <java/lang/ClassFormatError.h>
30 #include <java/lang/IllegalAccessError.h>
31 #include <java/lang/AbstractMethodError.h>
32 #include <java/lang/ClassNotFoundException.h>
33 #include <java/lang/IncompatibleClassChangeError.h>
34 #include <java/lang/reflect/Modifier.h>
35
36 using namespace gcj;
37
38 void
39 _Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader)
40 {
41   if (! field->isResolved ())
42     {
43       _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type;
44       field->type = _Jv_FindClassFromSignature (sig->data, loader);
45       field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG;
46     }
47 }
48
49 #ifdef INTERPRETER
50
51 static void throw_internal_error (char *msg)
52         __attribute__ ((__noreturn__));
53 static void throw_class_format_error (jstring msg)
54         __attribute__ ((__noreturn__));
55 static void throw_class_format_error (char *msg)
56         __attribute__ ((__noreturn__));
57
58 // Exceptional return values for _Jv_DetermineVTableIndex
59 #define METHOD_NOT_THERE (-2)
60 #define METHOD_INACCESSIBLE (-1)
61
62 static int get_alignment_from_class (jclass);
63
64 static _Jv_ResolvedMethod* 
65 _Jv_BuildResolvedMethod (_Jv_Method*,
66                          jclass,
67                          jboolean,
68                          jint);
69
70
71 static void throw_incompatible_class_change_error (jstring msg)
72 {
73   throw new java::lang::IncompatibleClassChangeError (msg);
74 }
75
76 _Jv_word
77 _Jv_ResolvePoolEntry (jclass klass, int index)
78 {
79   using namespace java::lang::reflect;
80
81   _Jv_Constants *pool = &klass->constants;
82
83   if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
84     return pool->data[index];
85
86   switch (pool->tags[index]) {
87   case JV_CONSTANT_Class:
88     {
89       _Jv_Utf8Const *name = pool->data[index].utf8;
90
91       jclass found;
92       if (name->data[0] == '[')
93         found = _Jv_FindClassFromSignature (&name->data[0],
94                                             klass->loader);
95       else
96         found = _Jv_FindClass (name, klass->loader);
97
98       if (! found)
99         {
100           jstring str = _Jv_NewStringUTF (name->data);
101           throw new java::lang::ClassNotFoundException (str);
102         }
103
104       if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC
105           || (_Jv_ClassNameSamePackage (found->name,
106                                         klass->name)))
107         {
108           pool->data[index].clazz = found;
109           pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
110         }
111       else
112         {
113           throw new java::lang::IllegalAccessError (found->getName());
114         }
115     }
116     break;
117
118   case JV_CONSTANT_String:
119     {
120       jstring str;
121       str = _Jv_NewStringUtf8Const (pool->data[index].utf8);
122       pool->data[index].o = str;
123       pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
124     }
125     break;
126
127
128   case JV_CONSTANT_Fieldref:
129     {
130       _Jv_ushort class_index, name_and_type_index;
131       _Jv_loadIndexes (&pool->data[index],
132                        class_index,
133                        name_and_type_index);
134       jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz;
135
136       if (owner != klass)
137         _Jv_InitClass (owner);
138
139       _Jv_ushort name_index, type_index;
140       _Jv_loadIndexes (&pool->data[name_and_type_index],
141                        name_index,
142                        type_index);
143
144       _Jv_Utf8Const *field_name = pool->data[name_index].utf8;
145       _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8;
146
147       // FIXME: The implementation of this function
148       // (_Jv_FindClassFromSignature) will generate an instance of
149       // _Jv_Utf8Const for each call if the field type is a class name
150       // (Lxx.yy.Z;).  This may be too expensive to do for each and
151       // every fieldref being resolved.  For now, we fix the problem by
152       // only doing it when we have a loader different from the class
153       // declaring the field.
154
155       jclass field_type = 0;
156
157       if (owner->loader != klass->loader)
158         field_type = _Jv_FindClassFromSignature (field_type_name->data,
159                                                  klass->loader);
160       
161       _Jv_Field* the_field = 0;
162
163       for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ())
164         {
165           for (int i = 0;  i < cls->field_count;  i++)
166             {
167               _Jv_Field *field = &cls->fields[i];
168               if (! _Jv_equalUtf8Consts (field->name, field_name))
169                 continue;
170
171               // now, check field access. 
172
173               if (   (cls == klass)
174                   || ((field->flags & Modifier::PUBLIC) != 0)
175                   || (((field->flags & Modifier::PROTECTED) != 0)
176                       && cls->isAssignableFrom (klass))
177                   || (((field->flags & Modifier::PRIVATE) == 0)
178                       && _Jv_ClassNameSamePackage (cls->name,
179                                                    klass->name)))
180                 {
181                   /* resove the field using the class' own loader
182                      if necessary */
183
184                   if (!field->isResolved ())
185                     _Jv_ResolveField (field, cls->loader);
186
187                   if (field_type != 0 && field->type != field_type)
188                     throw new java::lang::LinkageError
189                       (JvNewStringLatin1 
190                        ("field type mismatch with different loaders"));
191
192                   the_field = field;
193                   goto end_of_field_search;
194                 }
195               else
196                 {
197                   throw new java::lang::IllegalAccessError;
198                 }
199             }
200         }
201
202     end_of_field_search:
203       if (the_field == 0)
204         {
205           java::lang::StringBuffer *sb = new java::lang::StringBuffer();
206           sb->append(JvNewStringLatin1("field "));
207           sb->append(owner->getName());
208           sb->append(JvNewStringLatin1("."));
209           sb->append(_Jv_NewStringUTF(field_name->data));
210           sb->append(JvNewStringLatin1(" was not found."));
211           throw_incompatible_class_change_error(sb->toString());
212         }
213
214       pool->data[index].field = the_field;
215       pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
216     }
217     break;
218
219   case JV_CONSTANT_Methodref:
220   case JV_CONSTANT_InterfaceMethodref:
221     {
222       _Jv_ushort class_index, name_and_type_index;
223       _Jv_loadIndexes (&pool->data[index],
224                        class_index,
225                        name_and_type_index);
226       jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz;
227
228       if (owner != klass)
229         _Jv_InitClass (owner);
230
231       _Jv_ushort name_index, type_index;
232       _Jv_loadIndexes (&pool->data[name_and_type_index],
233                        name_index,
234                        type_index);
235
236       _Jv_Utf8Const *method_name = pool->data[name_index].utf8;
237       _Jv_Utf8Const *method_signature = pool->data[type_index].utf8;
238
239       int vtable_index = -1;
240       _Jv_Method *the_method = 0;
241       jclass found_class = 0;
242
243       // First search the class itself.
244       the_method = _Jv_SearchMethodInClass (owner, klass, 
245                    method_name, method_signature);
246
247       if (the_method != 0)
248         {
249           found_class = owner;
250           goto end_of_method_search;
251         }
252
253       // If we are resolving an interface method, search the interface's 
254       // superinterfaces (A superinterface is not an interface's superclass - 
255       // a superinterface is implemented by the interface).
256       if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
257         {
258           _Jv_ifaces ifaces;
259           ifaces.count = 0;
260           ifaces.len = 4;
261           ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *));
262
263           _Jv_GetInterfaces (owner, &ifaces);     
264           
265           for (int i=0; i < ifaces.count; i++)
266             {
267               jclass cls = ifaces.list[i];
268               the_method = _Jv_SearchMethodInClass (cls, klass, method_name, 
269                                                     method_signature);
270               if (the_method != 0)
271                 {
272                   found_class = cls;
273                   break;
274                 }
275             }
276           
277           _Jv_Free (ifaces.list);
278           
279           if (the_method != 0)
280             goto end_of_method_search;
281         }
282
283       // Finally, search superclasses. 
284       for (jclass cls = owner->getSuperclass (); cls != 0; 
285            cls = cls->getSuperclass ())
286         {
287           the_method = _Jv_SearchMethodInClass (cls, klass, 
288                        method_name, method_signature);
289           if (the_method != 0)
290             {
291               found_class = cls;
292               break;
293             }
294         }
295
296     end_of_method_search:
297     
298       // FIXME: if (cls->loader != klass->loader), then we
299       // must actually check that the types of arguments
300       // correspond.  That is, for each argument type, and
301       // the return type, doing _Jv_FindClassFromSignature
302       // with either loader should produce the same result,
303       // i.e., exactly the same jclass object. JVMS 5.4.3.3    
304     
305       if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
306         vtable_index = -1;
307       else
308         vtable_index = _Jv_DetermineVTableIndex
309           (found_class, method_name, method_signature);
310
311       if (vtable_index == METHOD_NOT_THERE)
312         throw_incompatible_class_change_error
313           (JvNewStringLatin1 ("method not found"));
314
315       if (the_method == 0)
316         {
317           java::lang::StringBuffer *sb = new java::lang::StringBuffer();
318           sb->append(JvNewStringLatin1("method "));
319           sb->append(owner->getName());
320           sb->append(JvNewStringLatin1("."));
321           sb->append(_Jv_NewStringUTF(method_name->data));
322           sb->append(JvNewStringLatin1(" was not found."));
323           throw new java::lang::NoSuchMethodError (sb->toString());
324         }
325       
326       pool->data[index].rmethod = 
327         _Jv_BuildResolvedMethod(the_method,
328                                 found_class,
329                                 (the_method->accflags & Modifier::STATIC) != 0,
330                                 vtable_index);
331       pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
332     }
333     break;
334
335   }
336
337   return pool->data[index];
338 }
339
340 // Find a method declared in the cls that is referenced from klass and
341 // perform access checks.
342 _Jv_Method *
343 _Jv_SearchMethodInClass (jclass cls, jclass klass, 
344                          _Jv_Utf8Const *method_name, 
345                          _Jv_Utf8Const *method_signature)
346 {
347   using namespace java::lang::reflect;
348
349   for (int i = 0;  i < cls->method_count;  i++)
350     {
351       _Jv_Method *method = &cls->methods[i];
352       if (   (!_Jv_equalUtf8Consts (method->name,
353                                     method_name))
354           || (!_Jv_equalUtf8Consts (method->signature,
355                                     method_signature)))
356         continue;
357
358       if (cls == klass 
359           || ((method->accflags & Modifier::PUBLIC) != 0)
360           || (((method->accflags & Modifier::PROTECTED) != 0)
361               && cls->isAssignableFrom (klass))
362           || (((method->accflags & Modifier::PRIVATE) == 0)
363               && _Jv_ClassNameSamePackage (cls->name,
364                                            klass->name)))
365         {
366           return method;
367         }
368       else
369         {
370           throw new java::lang::IllegalAccessError;
371         }
372     }
373   return 0;
374 }
375
376 /** FIXME: this is a terribly inefficient algorithm!  It would improve
377     things if compiled classes to know vtable offset, and _Jv_Method had
378     a field for this.
379
380     Returns METHOD_NOT_THERE if this class does not declare the given method.
381     Returns METHOD_INACCESSIBLE if the given method does not appear in the
382                 vtable, i.e., it is static, private, final or a constructor.
383     Otherwise, returns the vtable index.  */
384 int 
385 _Jv_DetermineVTableIndex (jclass klass,
386                           _Jv_Utf8Const *name,
387                           _Jv_Utf8Const *signature)
388 {
389   using namespace java::lang::reflect;
390
391   jclass super_class = klass->getSuperclass ();
392
393   if (super_class != NULL)
394     {
395       int prev = _Jv_DetermineVTableIndex (super_class,
396                                            name,
397                                            signature);
398       if (prev != METHOD_NOT_THERE)
399         return prev;
400     }
401
402   /* at this point, we know that the super-class does not declare
403    * the method.  Otherwise, the above call would have found it, and
404    * determined the result of this function (-1 or some positive
405    * number).
406    */
407
408   _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
409
410   /* now, if we do not declare this method, return zero */
411   if (meth == NULL)
412     return METHOD_NOT_THERE;
413
414   /* so now, we know not only that the super class does not declare the
415    * method, but we do!  So, this is a first declaration of the method. */
416
417   /* now, the checks for things that are declared in this class, but do
418    * not go into the vtable.  There are three cases.  
419    * 1) the method is static, private or final
420    * 2) the class itself is final, or
421    * 3) it is the method <init>
422    */
423
424   if ((meth->accflags & (Modifier::STATIC
425                          | Modifier::PRIVATE
426                          | Modifier::FINAL)) != 0
427       || (klass->accflags & Modifier::FINAL) != 0
428       || _Jv_equalUtf8Consts (name, init_name))
429     return METHOD_INACCESSIBLE;
430
431   /* reaching this point, we know for sure, that the method in question
432    * will be in the vtable.  The question is where. */
433
434   /* the base offset, is where we will start assigning vtable
435    * indexes for this class.  It is 0 for base classes
436    * and for non-base classes it is the
437    * number of entries in the super class' vtable. */
438
439   int base_offset;
440   if (super_class == 0)
441     base_offset = 0;
442   else
443     base_offset = super_class->vtable_method_count;
444
445   /* we will consider methods 0..this_method_index-1.  And for each one,
446    * determine if it is new (i.e., if it appears in the super class),
447    * and if it should go in the vtable.  If so, increment base_offset */
448
449   int this_method_index = meth - (&klass->methods[0]);
450
451   for (int i = 0; i < this_method_index; i++)
452     {
453       _Jv_Method *m = &klass->methods[i];
454
455       /* fist some checks for things that surely do not go in the
456        * vtable */
457
458       if ((m->accflags & (Modifier::STATIC | Modifier::PRIVATE)) != 0)
459         continue;
460       if (_Jv_equalUtf8Consts (m->name, init_name))
461         continue;
462       
463       /* Then, we need to know if this method appears in the
464          superclass. (This is where this function gets expensive) */
465       _Jv_Method *sm = _Jv_LookupDeclaredMethod (super_class,
466                                                  m->name,
467                                                  m->signature);
468       
469       /* if it was somehow declared in the superclass, skip this */
470       if (sm != NULL)
471         continue;
472
473       /* but if it is final, and not declared in the super class,
474        * then we also skip it */
475       if ((m->accflags & Modifier::FINAL) != 0)
476         continue;
477
478       /* finally, we can assign the index of this method */
479       /* m->vtable_index = base_offset */
480       base_offset += 1;
481     }
482
483   return base_offset;
484 }
485
486 /* this is installed in place of abstract methods */
487 static void
488 _Jv_abstractMethodError ()
489 {
490   throw new java::lang::AbstractMethodError;
491 }
492
493 void 
494 _Jv_PrepareClass(jclass klass)
495 {
496   using namespace java::lang::reflect;
497
498  /*
499   * The job of this function is to: 1) assign storage to fields, and 2)
500   * build the vtable.  static fields are assigned real memory, instance
501   * fields are assigned offsets.
502   *
503   * NOTE: we have a contract with the garbage collector here.  Static
504   * reference fields must not be resolved, until after they have storage
505   * assigned which is the check used by the collector to see if it
506   * should indirect the static field reference and mark the object
507   * pointed to. 
508   *
509   * Most fields are resolved lazily (i.e. have their class-type
510   * assigned) when they are accessed the first time by calling as part
511   * of _Jv_ResolveField, which is allways called after _Jv_PrepareClass.
512   * Static fields with initializers are resolved as part of this
513   * function, as are fields with primitive types.
514   */
515
516   if (! _Jv_IsInterpretedClass (klass))
517     return;
518
519   if (klass->state >= JV_STATE_PREPARED)
520     return;
521
522   // Make sure super-class is linked.  This involves taking a lock on
523   // the super class, so we use the Java method resolveClass, which
524   // will unlock it properly, should an exception happen.  If there's
525   // no superclass, do nothing -- Object will already have been
526   // resolved.
527
528   if (klass->superclass)
529     java::lang::ClassLoader::resolveClass0 (klass->superclass);
530
531   _Jv_InterpClass *clz = (_Jv_InterpClass*)klass;
532
533   /************ PART ONE: OBJECT LAYOUT ***************/
534
535   int instance_size;
536   int static_size;
537
538   // Although java.lang.Object is never interpreted, an interface can
539   // have a null superclass.
540   if (clz->superclass)
541     instance_size = clz->superclass->size();
542   else
543     instance_size = java::lang::Object::class$.size();
544   static_size   = 0;
545
546   for (int i = 0; i < clz->field_count; i++)
547     {
548       int field_size;
549       int field_align;
550
551       _Jv_Field *field = &clz->fields[i];
552
553       if (! field->isRef ())
554         {
555           // it's safe to resolve the field here, since it's 
556           // a primitive class, which does not cause loading to happen.
557           _Jv_ResolveField (field, clz->loader);
558
559           field_size = field->type->size ();
560           field_align = get_alignment_from_class (field->type);
561         }
562       else 
563         {
564           field_size = sizeof (jobject);
565           field_align = __alignof__ (jobject);
566         }
567
568 #ifndef COMPACT_FIELDS
569       field->bsize = field_size;
570 #endif
571
572       if (field->flags & Modifier::STATIC)
573         {
574           /* this computes an offset into a region we'll allocate 
575              shortly, and then add this offset to the start address */
576
577           static_size        = ROUND (static_size, field_align);
578           field->u.boffset   = static_size;
579           static_size       += field_size;
580         }
581       else
582         {
583           instance_size      = ROUND (instance_size, field_align);
584           field->u.boffset   = instance_size;
585           instance_size     += field_size;
586         }
587     }
588
589   // set the instance size for the class
590   clz->size_in_bytes = instance_size;
591
592   // allocate static memory
593   if (static_size != 0)
594     {
595       char *static_data = (char*)_Jv_AllocBytes (static_size);
596
597       memset (static_data, 0, static_size);
598
599       for (int i = 0; i < clz->field_count; i++)
600         {
601           _Jv_Field *field = &clz->fields[i];
602
603           if ((field->flags & Modifier::STATIC) != 0)
604             {
605               field->u.addr  = static_data + field->u.boffset;
606                             
607               if (clz->field_initializers[i] != 0)
608                 {
609                   _Jv_ResolveField (field, clz->loader);
610                   _Jv_InitField (0, clz, i);
611                 }
612             }
613         }
614
615       // now we don't need the field_initializers anymore, so let the
616       // collector get rid of it!
617
618       clz->field_initializers = 0;
619     }
620
621   /************ PART TWO: VTABLE LAYOUT ***************/
622
623   /* preparation: build the vtable stubs (even interfaces can)
624      have code -- for static constructors. */
625   for (int i = 0; i < clz->method_count; i++)
626     {
627       _Jv_MethodBase *imeth = clz->interpreted_methods[i];
628
629       if ((clz->methods[i].accflags & Modifier::NATIVE) != 0)
630         {
631           // You might think we could use a virtual `ncode' method in
632           // the _Jv_MethodBase and unify the native and non-native
633           // cases.  Well, we can't, because we don't allocate these
634           // objects using `new', and thus they don't get a vtable.
635           _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth);
636           clz->methods[i].ncode = jnim->ncode ();
637         }
638       else if (imeth != 0)              // it could be abstract
639         {
640           _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
641           _Jv_VerifyMethod (im);
642           clz->methods[i].ncode = im->ncode ();
643         }
644     }
645
646   if (clz->accflags & Modifier::INTERFACE)
647     {
648       clz->state = JV_STATE_PREPARED;
649       clz->notifyAll ();
650       return;
651     }
652
653   /* Now onto the actual job: vtable layout.  First, count how many new
654      methods we have */
655   int new_method_count = 0;
656
657   jclass super_class = clz->getSuperclass ();
658
659   for (int i = 0; i < clz->method_count; i++)
660     {
661       _Jv_Method *this_meth = &clz->methods[i];
662
663       if ((this_meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) != 0
664           || _Jv_equalUtf8Consts (this_meth->name, init_name))
665         {
666           /* skip this, it doesn't go in the vtable */
667           continue;
668         }
669           
670       _Jv_Method *orig_meth = _Jv_LookupDeclaredMethod (super_class,
671                                                         this_meth->name,
672                                                         this_meth->signature);
673
674       if (orig_meth == 0)
675         {
676           // new methods that are final, also don't go in the vtable
677           if ((this_meth->accflags & Modifier::FINAL) != 0)
678             continue;
679
680           new_method_count += 1;
681           continue;
682         }
683
684       if ((orig_meth->accflags & (Modifier::STATIC
685                                   | Modifier::PRIVATE
686                                   | Modifier::FINAL)) != 0
687           || ((orig_meth->accflags & Modifier::ABSTRACT) == 0
688               && (this_meth->accflags & Modifier::ABSTRACT) != 0
689               && (klass->accflags & Modifier::ABSTRACT) == 0))
690         {
691           clz->state = JV_STATE_ERROR;
692           clz->notifyAll ();
693           throw new java::lang::IncompatibleClassChangeError (clz->getName ());
694         }
695
696       /* FIXME: At this point, if (loader != super_class->loader), we
697        * need to "impose class loader constraints" for the types
698        * involved in the signature of this method */
699     }
700   
701   /* determine size */
702   int vtable_count = (super_class->vtable_method_count) + new_method_count;
703   clz->vtable_method_count = vtable_count;
704
705   /* allocate vtable structure */
706   _Jv_VTable *vtable = _Jv_VTable::new_vtable (vtable_count);
707   vtable->clas = clz;
708   vtable->gc_descr = _Jv_BuildGCDescr(clz);
709
710   {
711     jclass effective_superclass = super_class;
712
713     /* If super_class is abstract or an interface it has no vtable.
714        We need to find a real one... */
715     while (effective_superclass && effective_superclass->vtable == NULL)
716       effective_superclass = effective_superclass->superclass;
717
718     /* If we ended up without a superclass, use Object.  */
719     if (! effective_superclass)
720       effective_superclass = &java::lang::Object::class$;
721
722     /* copy super class' vtable entries. */
723     if (effective_superclass && effective_superclass->vtable)
724       for (int i = 0; i < effective_superclass->vtable_method_count; ++i)
725         vtable->set_method (i, effective_superclass->vtable->get_method (i));
726   }
727
728   /* now, install our own vtable entries, reprise... */
729   for (int i = 0; i < clz->method_count; i++)
730     {
731       _Jv_Method *this_meth = &clz->methods[i];
732
733       int index = _Jv_DetermineVTableIndex (clz, 
734                                             this_meth->name,
735                                             this_meth->signature);
736
737       if (index == METHOD_NOT_THERE)
738         throw_internal_error ("method now found in own class");
739
740       if (index != METHOD_INACCESSIBLE)
741         {
742           if (index > clz->vtable_method_count)
743             throw_internal_error ("vtable problem...");
744
745           if (clz->interpreted_methods[i] == 0)
746             vtable->set_method(index, (void*)&_Jv_abstractMethodError);
747           else
748             vtable->set_method(index, this_meth->ncode);
749         }
750     }
751
752   /* finally, assign the vtable! */
753   clz->vtable = vtable;
754
755   /* wooha! we're done. */
756   clz->state = JV_STATE_PREPARED;
757   clz->notifyAll ();
758 }
759
760 /** Do static initialization for fields with a constant initializer */
761 void
762 _Jv_InitField (jobject obj, jclass klass, int index)
763 {
764   using namespace java::lang::reflect;
765
766   if (obj != 0 && klass == 0)
767     klass = obj->getClass ();
768
769   if (!_Jv_IsInterpretedClass (klass))
770     return;
771
772   _Jv_InterpClass *clz = (_Jv_InterpClass*)klass;
773
774   _Jv_Field * field = (&clz->fields[0]) + index;
775
776   if (index > clz->field_count)
777     throw_internal_error ("field out of range");
778
779   int init = clz->field_initializers[index];
780   if (init == 0)
781     return;
782
783   _Jv_Constants *pool = &clz->constants;
784   int tag = pool->tags[init];
785
786   if (! field->isResolved ())
787     throw_internal_error ("initializing unresolved field");
788
789   if (obj==0 && ((field->flags & Modifier::STATIC) == 0))
790     throw_internal_error ("initializing non-static field with no object");
791
792   void *addr = 0;
793
794   if ((field->flags & Modifier::STATIC) != 0)
795     addr = (void*) field->u.addr;
796   else
797     addr = (void*) (((char*)obj) + field->u.boffset);
798
799   switch (tag)
800     {
801     case JV_CONSTANT_String:
802       {
803         _Jv_MonitorEnter (clz);
804         jstring str;
805         str = _Jv_NewStringUtf8Const (pool->data[init].utf8);
806         pool->data[init].string = str;
807         pool->tags[init] = JV_CONSTANT_ResolvedString;
808         _Jv_MonitorExit (clz);
809       }
810       /* fall through */
811
812     case JV_CONSTANT_ResolvedString:
813       if (! (field->type == &StringClass
814              || field->type == &java::lang::Class::class$))
815         throw_class_format_error ("string initialiser to non-string field");
816
817       *(jstring*)addr = pool->data[init].string;
818       break;
819
820     case JV_CONSTANT_Integer:
821       {
822         int value = pool->data[init].i;
823
824         if (field->type == JvPrimClass (boolean))
825           *(jboolean*)addr = (jboolean)value;
826         
827         else if (field->type == JvPrimClass (byte))
828           *(jbyte*)addr = (jbyte)value;
829         
830         else if (field->type == JvPrimClass (char))
831           *(jchar*)addr = (jchar)value;
832
833         else if (field->type == JvPrimClass (short))
834           *(jshort*)addr = (jshort)value;
835         
836         else if (field->type == JvPrimClass (int))
837           *(jint*)addr = (jint)value;
838
839         else
840           throw_class_format_error ("erroneous field initializer");
841       }  
842       break;
843
844     case JV_CONSTANT_Long:
845       if (field->type != JvPrimClass (long))
846         throw_class_format_error ("erroneous field initializer");
847
848       *(jlong*)addr = _Jv_loadLong (&pool->data[init]);
849       break;
850
851     case JV_CONSTANT_Float:
852       if (field->type != JvPrimClass (float))
853         throw_class_format_error ("erroneous field initializer");
854
855       *(jfloat*)addr = pool->data[init].f;
856       break;
857
858     case JV_CONSTANT_Double:
859       if (field->type != JvPrimClass (double))
860         throw_class_format_error ("erroneous field initializer");
861
862       *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]);
863       break;
864
865     default:
866       throw_class_format_error ("erroneous field initializer");
867     }
868 }
869
870 static int
871 get_alignment_from_class (jclass klass)
872 {
873   if (klass == JvPrimClass (byte))
874     return  __alignof__ (jbyte);
875   else if (klass == JvPrimClass (short))
876     return  __alignof__ (jshort);
877   else if (klass == JvPrimClass (int)) 
878     return  __alignof__ (jint);
879   else if (klass == JvPrimClass (long))
880     return  __alignof__ (jlong);
881   else if (klass == JvPrimClass (boolean))
882     return  __alignof__ (jboolean);
883   else if (klass == JvPrimClass (char))
884     return  __alignof__ (jchar);
885   else if (klass == JvPrimClass (float))
886     return  __alignof__ (jfloat);
887   else if (klass == JvPrimClass (double))
888     return  __alignof__ (jdouble);
889   else
890     return __alignof__ (jobject);
891 }
892
893
894 inline static unsigned char*
895 skip_one_type (unsigned char* ptr)
896 {
897   int ch = *ptr++;
898
899   while (ch == '[')
900     { 
901       ch = *ptr++;
902     }
903   
904   if (ch == 'L')
905     {
906       do { ch = *ptr++; } while (ch != ';');
907     }
908
909   return ptr;
910 }
911
912 static ffi_type*
913 get_ffi_type_from_signature (unsigned char* ptr)
914 {
915   switch (*ptr) 
916     {
917     case 'L':
918     case '[':
919       return &ffi_type_pointer;
920       break;
921
922     case 'Z':
923       // On some platforms a bool is a byte, on others an int.
924       if (sizeof (jboolean) == sizeof (jbyte))
925         return &ffi_type_sint8;
926       else
927         {
928           JvAssert (sizeof (jbyte) == sizeof (jint));
929           return &ffi_type_sint32;
930         }
931       break;
932
933     case 'B':
934       return &ffi_type_sint8;
935       break;
936       
937     case 'C':
938       return &ffi_type_uint16;
939       break;
940           
941     case 'S': 
942       return &ffi_type_sint16;
943       break;
944           
945     case 'I':
946       return &ffi_type_sint32;
947       break;
948           
949     case 'J':
950       return &ffi_type_sint64;
951       break;
952           
953     case 'F':
954       return &ffi_type_float;
955       break;
956           
957     case 'D':
958       return &ffi_type_double;
959       break;
960
961     case 'V':
962       return &ffi_type_void;
963       break;
964     }
965
966   throw_internal_error ("unknown type in signature");
967 }
968
969 /* this function yields the number of actual arguments, that is, if the
970  * function is non-static, then one is added to the number of elements
971  * found in the signature */
972
973 int 
974 _Jv_count_arguments (_Jv_Utf8Const *signature,
975                      jboolean staticp)
976 {
977   unsigned char *ptr = (unsigned char*) signature->data;
978   int arg_count = staticp ? 0 : 1;
979
980   /* first, count number of arguments */
981
982   // skip '('
983   ptr++;
984
985   // count args
986   while (*ptr != ')')
987     {
988       ptr = skip_one_type (ptr);
989       arg_count += 1;
990     }
991
992   return arg_count;
993 }
994
995 /* This beast will build a cif, given the signature.  Memory for
996  * the cif itself and for the argument types must be allocated by the
997  * caller.
998  */
999
1000 static int 
1001 init_cif (_Jv_Utf8Const* signature,
1002           int arg_count,
1003           jboolean staticp,
1004           ffi_cif *cif,
1005           ffi_type **arg_types,
1006           ffi_type **rtype_p)
1007 {
1008   unsigned char *ptr = (unsigned char*) signature->data;
1009
1010   int arg_index = 0;            // arg number
1011   int item_count = 0;           // stack-item count
1012
1013   // setup receiver
1014   if (!staticp)
1015     {
1016       arg_types[arg_index++] = &ffi_type_pointer;
1017       item_count += 1;
1018     }
1019
1020   // skip '('
1021   ptr++;
1022
1023   // assign arg types
1024   while (*ptr != ')')
1025     {
1026       arg_types[arg_index++] = get_ffi_type_from_signature (ptr);
1027
1028       if (*ptr == 'J' || *ptr == 'D')
1029         item_count += 2;
1030       else
1031         item_count += 1;
1032
1033       ptr = skip_one_type (ptr);
1034     }
1035
1036   // skip ')'
1037   ptr++;
1038   ffi_type *rtype = get_ffi_type_from_signature (ptr);
1039
1040   ptr = skip_one_type (ptr);
1041   if (ptr != (unsigned char*)signature->data + signature->length)
1042     throw_internal_error ("did not find end of signature");
1043
1044   if (ffi_prep_cif (cif, FFI_DEFAULT_ABI,
1045                     arg_count, rtype, arg_types) != FFI_OK)
1046     throw_internal_error ("ffi_prep_cif failed");
1047
1048   if (rtype_p != NULL)
1049     *rtype_p = rtype;
1050
1051   return item_count;
1052 }
1053
1054 #if FFI_NATIVE_RAW_API
1055 #   define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure
1056 #   define FFI_RAW_SIZE ffi_raw_size
1057 #else
1058 #   define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure
1059 #   define FFI_RAW_SIZE ffi_java_raw_size
1060 #endif
1061
1062 /* we put this one here, and not in interpret.cc because it
1063  * calls the utility routines _Jv_count_arguments 
1064  * which are static to this module.  The following struct defines the
1065  * layout we use for the stubs, it's only used in the ncode method. */
1066
1067 typedef struct {
1068   ffi_raw_closure  closure;
1069   ffi_cif   cif;
1070   ffi_type *arg_types[0];
1071 } ncode_closure;
1072
1073 typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*);
1074
1075 void *
1076 _Jv_InterpMethod::ncode ()
1077 {
1078   using namespace java::lang::reflect;
1079
1080   if (self->ncode != 0)
1081     return self->ncode;
1082
1083   jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
1084   int arg_count = _Jv_count_arguments (self->signature, staticp);
1085
1086   ncode_closure *closure =
1087     (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
1088                                         + arg_count * sizeof (ffi_type*));
1089
1090   init_cif (self->signature,
1091             arg_count,
1092             staticp,
1093             &closure->cif,
1094             &closure->arg_types[0],
1095             NULL);
1096
1097   ffi_closure_fun fun;
1098
1099   args_raw_size = FFI_RAW_SIZE (&closure->cif);
1100
1101   JvAssert ((self->accflags & Modifier::NATIVE) == 0);
1102
1103   if ((self->accflags & Modifier::SYNCHRONIZED) != 0)
1104     {
1105       if (staticp)
1106         fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
1107       else
1108         fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; 
1109     }
1110   else
1111     {
1112       fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
1113     }
1114
1115   FFI_PREP_RAW_CLOSURE (&closure->closure,
1116                         &closure->cif, 
1117                         fun,
1118                         (void*)this);
1119
1120   self->ncode = (void*)closure;
1121   return self->ncode;
1122 }
1123
1124
1125 void *
1126 _Jv_JNIMethod::ncode ()
1127 {
1128   using namespace java::lang::reflect;
1129
1130   if (self->ncode != 0)
1131     return self->ncode;
1132
1133   jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
1134   int arg_count = _Jv_count_arguments (self->signature, staticp);
1135
1136   ncode_closure *closure =
1137     (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
1138                                     + arg_count * sizeof (ffi_type*));
1139
1140   ffi_type *rtype;
1141   init_cif (self->signature,
1142             arg_count,
1143             staticp,
1144             &closure->cif,
1145             &closure->arg_types[0],
1146             &rtype);
1147
1148   ffi_closure_fun fun;
1149
1150   args_raw_size = FFI_RAW_SIZE (&closure->cif);
1151
1152   // Initialize the argument types and CIF that represent the actual
1153   // underlying JNI function.
1154   int extra_args = 1;
1155   if ((self->accflags & Modifier::STATIC))
1156     ++extra_args;
1157   jni_arg_types = (ffi_type **) _Jv_Malloc ((extra_args + arg_count)
1158                                             * sizeof (ffi_type *));
1159   int offset = 0;
1160   jni_arg_types[offset++] = &ffi_type_pointer;
1161   if ((self->accflags & Modifier::STATIC))
1162     jni_arg_types[offset++] = &ffi_type_pointer;
1163   memcpy (&jni_arg_types[offset], &closure->arg_types[0],
1164           arg_count * sizeof (ffi_type *));
1165
1166   if (ffi_prep_cif (&jni_cif, FFI_DEFAULT_ABI,
1167                     extra_args + arg_count, rtype,
1168                     jni_arg_types) != FFI_OK)
1169     throw_internal_error ("ffi_prep_cif failed for JNI function");
1170
1171   JvAssert ((self->accflags & Modifier::NATIVE) != 0);
1172
1173   // FIXME: for now we assume that all native methods for
1174   // interpreted code use JNI.
1175   fun = (ffi_closure_fun) &_Jv_JNIMethod::call;
1176
1177   FFI_PREP_RAW_CLOSURE (&closure->closure,
1178                         &closure->cif, 
1179                         fun,
1180                         (void*) this);
1181
1182   self->ncode = (void *) closure;
1183   return self->ncode;
1184 }
1185
1186
1187 /* A _Jv_ResolvedMethod is what is put in the constant pool for a
1188  * MethodRef or InterfacemethodRef.  */
1189 static _Jv_ResolvedMethod*
1190 _Jv_BuildResolvedMethod (_Jv_Method* method,
1191                          jclass      klass,
1192                          jboolean staticp,
1193                          jint vtable_index)
1194 {
1195   int arg_count = _Jv_count_arguments (method->signature, staticp);
1196
1197   _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*)
1198     _Jv_AllocBytes (sizeof (_Jv_ResolvedMethod)
1199                     + arg_count*sizeof (ffi_type*));
1200
1201   result->stack_item_count
1202     = init_cif (method->signature,
1203                 arg_count,
1204                 staticp,
1205                 &result->cif,
1206                 &result->arg_types[0],
1207                 NULL);
1208
1209   result->vtable_index        = vtable_index;
1210   result->method              = method;
1211   result->klass               = klass;
1212
1213   return result;
1214 }
1215
1216
1217 static void
1218 throw_class_format_error (jstring msg)
1219 {
1220   throw (msg
1221          ? new java::lang::ClassFormatError (msg)
1222          : new java::lang::ClassFormatError);
1223 }
1224
1225 static void
1226 throw_class_format_error (char *msg)
1227 {
1228   throw_class_format_error (JvNewStringLatin1 (msg));
1229 }
1230
1231 static void
1232 throw_internal_error (char *msg)
1233 {
1234   throw new java::lang::InternalError (JvNewStringLatin1 (msg));
1235 }
1236
1237
1238 #endif /* INTERPRETER */