OSDN Git Service

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