OSDN Git Service

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