source: branches/libc-0.6/src/gcc/libjava/resolve.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

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