source: trunk/third/gcc/libjava/resolve.cc @ 18474

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