OSDN Git Service

In gcc/java:
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / reflect / natMethod.cc
1 // natMethod.cc - Native code for Method class.
2
3 /* Copyright (C) 1998, 1999, 2000  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 #include <config.h>
12
13 #if HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16
17 #include <gcj/cni.h>
18 #include <jvm.h>
19 #include <jni.h>
20
21 #include <java/lang/reflect/Method.h>
22 #include <java/lang/reflect/Constructor.h>
23 #include <java/lang/reflect/InvocationTargetException.h>
24 #include <java/lang/reflect/Modifier.h>
25
26 #include <java/lang/Void.h>
27 #include <java/lang/Byte.h>
28 #include <java/lang/Boolean.h>
29 #include <java/lang/Character.h>
30 #include <java/lang/Short.h>
31 #include <java/lang/Integer.h>
32 #include <java/lang/Long.h>
33 #include <java/lang/Float.h>
34 #include <java/lang/Double.h>
35 #include <java/lang/IllegalArgumentException.h>
36 #include <java/lang/NullPointerException.h>
37 #include <java/lang/Class.h>
38 #include <gcj/method.h>
39 #include <gnu/gcj/RawData.h>
40
41 // FIXME: remove these
42 #define ObjectClass java::lang::Object::class$
43 #define ClassClass java::lang::Class::class$
44
45 #include <stdlib.h>
46
47 #include <ffi.h>
48
49 // FIXME: remove these.
50 #define BooleanClass java::lang::Boolean::class$
51 #define VoidClass java::lang::Void::class$
52 #define ByteClass java::lang::Byte::class$
53 #define ShortClass java::lang::Short::class$
54 #define CharacterClass java::lang::Character::class$
55 #define IntegerClass java::lang::Integer::class$
56 #define LongClass java::lang::Long::class$
57 #define FloatClass java::lang::Float::class$
58 #define DoubleClass java::lang::Double::class$
59
60 struct cpair
61 {
62   jclass prim;
63   jclass wrap;
64 };
65
66 // This is used to determine when a primitive widening conversion is
67 // allowed.
68 static cpair primitives[] =
69 {
70 #define BOOLEAN 0
71   { JvPrimClass (boolean), &BooleanClass },
72   { JvPrimClass (byte), &ByteClass },
73 #define SHORT 2
74   { JvPrimClass (short), &ShortClass },
75 #define CHAR 3
76   { JvPrimClass (char), &CharacterClass },
77   { JvPrimClass (int), &IntegerClass },
78   { JvPrimClass (long), &LongClass },
79   { JvPrimClass (float), &FloatClass },
80   { JvPrimClass (double), &DoubleClass },
81   { NULL, NULL }
82 };
83
84 static inline jboolean
85 can_widen (jclass from, jclass to)
86 {
87   int fromx = -1, tox = -1;
88
89   for (int i = 0; primitives[i].prim; ++i)
90     {
91       if (primitives[i].wrap == from)
92         fromx = i;
93       if (primitives[i].prim == to)
94         tox = i;
95     }
96
97   // Can't handle a miss.
98   if (fromx == -1 || tox == -1)
99     return false;
100   // Boolean arguments may not be widened.
101   if (fromx == BOOLEAN && tox != BOOLEAN)
102     return false;
103   // Special-case short->char conversions.
104   if (fromx == SHORT && tox == CHAR)
105     return false;
106
107   return fromx <= tox;
108 }
109
110 static inline ffi_type *
111 get_ffi_type (jclass klass)
112 {
113   // A special case.
114   if (klass == NULL)
115     return &ffi_type_pointer;
116
117   ffi_type *r;
118   if (klass == JvPrimClass (byte))
119     r = &ffi_type_sint8;
120   else if (klass == JvPrimClass (short))
121     r = &ffi_type_sint16;
122   else if (klass == JvPrimClass (int))
123     r = &ffi_type_sint32;
124   else if (klass == JvPrimClass (long))
125     r = &ffi_type_sint64;
126   else if (klass == JvPrimClass (float))
127     r = &ffi_type_float;
128   else if (klass == JvPrimClass (double))
129     r = &ffi_type_double;
130   else if (klass == JvPrimClass (boolean))
131     {
132       // On some platforms a bool is a byte, on others an int.
133       if (sizeof (jboolean) == sizeof (jbyte))
134         r = &ffi_type_sint8;
135       else
136         {
137           JvAssert (sizeof (jboolean) == sizeof (jint));
138           r = &ffi_type_sint32;
139         }
140     }
141   else if (klass == JvPrimClass (char))
142     r = &ffi_type_uint16;
143   else
144     {
145       JvAssert (! klass->isPrimitive());
146       r = &ffi_type_pointer;
147     }
148
149   return r;
150 }
151
152 jobject
153 java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
154 {
155   if (parameter_types == NULL)
156     getType ();
157
158   jmethodID meth = _Jv_FromReflectedMethod (this);
159   if (! java::lang::reflect::Modifier::isStatic(meth->accflags))
160     {
161       jclass k = obj ? obj->getClass() : NULL;
162       if (! obj)
163         JvThrow (new java::lang::NullPointerException);
164       if (! declaringClass->isAssignableFrom(k))
165         JvThrow (new java::lang::IllegalArgumentException);
166       // FIXME: access checks.
167
168       // Find the possibly overloaded method based on the runtime type
169       // of the object.
170       meth = _Jv_LookupDeclaredMethod (k, meth->name, meth->signature);
171     }
172
173   return _Jv_CallAnyMethodA (obj, return_type, meth, false,
174                              parameter_types, args);
175 }
176
177 jint
178 java::lang::reflect::Method::getModifiers ()
179 {
180   // Ignore all unknown flags.
181   return _Jv_FromReflectedMethod (this)->accflags & Modifier::ALL_FLAGS;
182 }
183
184 jstring
185 java::lang::reflect::Method::getName ()
186 {
187   if (name == NULL)
188     name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name);
189   return name;
190 }
191
192 /* Internal method to set return_type and parameter_types fields. */
193
194 void
195 java::lang::reflect::Method::getType ()
196 {
197   _Jv_GetTypesFromSignature (_Jv_FromReflectedMethod (this),
198                              declaringClass,
199                              &parameter_types,
200                              &return_type);
201
202   // FIXME: for now we have no way to get exception information.
203   exception_types = (JArray<jclass> *) JvNewObjectArray (0, &ClassClass,
204                                                          NULL);
205 }
206
207 void
208 _Jv_GetTypesFromSignature (jmethodID method,
209                            jclass declaringClass,
210                            JArray<jclass> **arg_types_out,
211                            jclass *return_type_out)
212 {
213
214   _Jv_Utf8Const* sig = method->signature;
215   java::lang::ClassLoader *loader = declaringClass->getClassLoader();
216   char *ptr = sig->data;
217   int numArgs = 0;
218   /* First just count the number of parameters. */
219   for (; ; ptr++)
220     {
221       switch (*ptr)
222         {
223         case 0:
224         case ')':
225         case 'V':
226           break;
227         case '[':
228         case '(':
229           continue;
230         case 'B':
231         case 'C':
232         case 'D':
233         case 'F':
234         case 'S':
235         case 'I':
236         case 'J':
237         case 'Z':
238           numArgs++;
239           continue;
240         case 'L':
241           numArgs++;
242           do 
243             ptr++;
244           while (*ptr != ';' && ptr[1] != '\0');
245           continue;
246         }
247       break;
248     }
249
250   JArray<jclass> *args = (JArray<jclass> *)
251     JvNewObjectArray (numArgs, &ClassClass, NULL);
252   jclass* argPtr = elements (args);
253   for (ptr = sig->data; *ptr != '\0'; ptr++)
254     {
255       int num_arrays = 0;
256       jclass type;
257       for (; *ptr == '[';  ptr++)
258         num_arrays++;
259       switch (*ptr)
260         {
261         default:
262           return;
263         case ')':
264           argPtr = return_type_out;
265           continue;
266         case '(':
267           continue;
268         case 'V':
269         case 'B':
270         case 'C':
271         case 'D':
272         case 'F':
273         case 'S':
274         case 'I':
275         case 'J':
276         case 'Z':
277           type = _Jv_FindClassFromSignature(ptr, loader);
278           break;
279         case 'L':
280           type = _Jv_FindClassFromSignature(ptr, loader);
281           do 
282             ptr++;
283           while (*ptr != ';' && ptr[1] != '\0');
284           break;
285         }
286
287       // FIXME: 2'nd argument should be "current loader"
288       while (--num_arrays >= 0)
289         type = _Jv_GetArrayClass (type, 0);
290       // ARGPTR can be NULL if we are processing the return value of a
291       // call from Constructor.
292       if (argPtr)
293         *argPtr++ = type;
294     }
295   *arg_types_out = args;
296 }
297
298 // This is a very rough analog of the JNI CallNonvirtual<type>MethodA
299 // functions.  It handles both Methods and Constructors, and it can
300 // handle any return type.  In the Constructor case, the `obj'
301 // argument is unused and should be NULL; also, the `return_type' is
302 // the class that the constructor will construct.  RESULT is a pointer
303 // to a `jvalue' (see jni.h); for a void method this should be NULL.
304 // This function returns an exception (if one was thrown), or NULL if
305 // the call went ok.
306 jthrowable
307 _Jv_CallAnyMethodA (jobject obj,
308                     jclass return_type,
309                     jmethodID meth,
310                     jboolean is_constructor,
311                     JArray<jclass> *parameter_types,
312                     jvalue *args,
313                     jvalue *result)
314 {
315   JvAssert (! is_constructor || ! obj);
316   JvAssert (! is_constructor || return_type);
317
318   // See whether call needs an object as the first argument.  A
319   // constructor does need a `this' argument, but it is one we create.
320   jboolean needs_this = false;
321   if (is_constructor
322       || ! java::lang::reflect::Modifier::isStatic(meth->accflags))
323     needs_this = true;
324
325   int param_count = parameter_types->length;
326   if (needs_this)
327     ++param_count;
328
329   ffi_type *rtype;
330   // A constructor itself always returns void.
331   if (is_constructor || return_type == JvPrimClass (void))
332     rtype = &ffi_type_void;
333   else
334     rtype = get_ffi_type (return_type);
335   ffi_type **argtypes = (ffi_type **) alloca (param_count
336                                               * sizeof (ffi_type *));
337
338   jclass *paramelts = elements (parameter_types);
339
340   // FIXME: at some point the compiler is going to add extra arguments
341   // to some functions.  In particular we are going to do this for
342   // handling access checks in reflection.  We must add these hidden
343   // arguments here.
344
345   // Special case for the `this' argument of a constructor.  Note that
346   // the JDK 1.2 docs specify that the new object must be allocated
347   // before argument conversions are done.
348   if (is_constructor)
349     {
350       // FIXME: must special-case String, arrays, maybe others here.
351       obj = JvAllocObject (return_type);
352     }
353
354   int i = 0;
355   int size = 0;
356   if (needs_this)
357     {
358       // The `NULL' type is `Object'.
359       argtypes[i++] = get_ffi_type (NULL);
360       size += sizeof (jobject);
361     }
362
363   for (int arg = 0; i < param_count; ++i, ++arg)
364     {
365       argtypes[i] = get_ffi_type (paramelts[arg]);
366       if (paramelts[arg]->isPrimitive())
367         size += paramelts[arg]->size();
368       else
369         size += sizeof (jobject);
370     }
371
372   ffi_cif cif;
373   if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count,
374                     rtype, argtypes) != FFI_OK)
375     {
376       // FIXME: throw some kind of VirtualMachineError here.
377     }
378
379   char *p = (char *) alloca (size);
380   void **values = (void **) alloca (param_count * sizeof (void *));
381
382   i = 0;
383   if (needs_this)
384     {
385       values[i] = p;
386       memcpy (p, &obj, sizeof (jobject));
387       p += sizeof (jobject);
388       ++i;
389     }
390
391   for (int arg = 0; i < param_count; ++i, ++arg)
392     {
393       int tsize;
394       if (paramelts[arg]->isPrimitive())
395         tsize = paramelts[arg]->size();
396       else
397         tsize = sizeof (jobject);
398
399       // Copy appropriate bits from the jvalue into the ffi array.
400       // FIXME: we could do this copying all in one loop, above, by
401       // over-allocating a bit.
402       values[i] = p;
403       memcpy (p, &args[arg], tsize);
404       p += tsize;
405     }
406
407   // FIXME: initialize class here.
408
409   using namespace java::lang;
410   using namespace java::lang::reflect;
411
412   Throwable *ex = NULL;
413
414   try
415     {
416       ffi_call (&cif, (void (*)()) meth->ncode, result, values);
417     }
418   catch (Throwable *ex2)
419     {
420       // FIXME: this is wrong for JNI.  But if we just return the
421       // exception, then the non-JNI cases won't be able to
422       // distinguish it from exceptions we might generate ourselves.
423       // Sigh.
424       ex = new InvocationTargetException (ex2);
425     }
426
427   if (is_constructor)
428     result->l = obj;
429
430   return ex;
431 }
432
433 // This is another version of _Jv_CallAnyMethodA, but this one does
434 // more checking and is used by the reflection (and not JNI) code.
435 jobject
436 _Jv_CallAnyMethodA (jobject obj,
437                     jclass return_type,
438                     jmethodID meth,
439                     jboolean is_constructor,
440                     JArray<jclass> *parameter_types,
441                     jobjectArray args)
442 {
443   // FIXME: access checks.
444
445   if (parameter_types->length == 0 && args == NULL)
446     {
447       // The JDK accepts this, so we do too.
448     }
449   else if (parameter_types->length != args->length)
450     JvThrow (new java::lang::IllegalArgumentException);
451
452   int param_count = parameter_types->length;
453
454   jclass *paramelts = elements (parameter_types);
455   jobject *argelts = args == NULL ? NULL : elements (args);
456   jvalue argvals[param_count];
457
458 #define COPY(Where, What, Type) \
459   do { \
460     Type val = (What); \
461     memcpy ((Where), &val, sizeof (Type)); \
462   } while (0)
463
464   for (int i = 0; i < param_count; ++i)
465     {
466       jclass k = argelts[i] ? argelts[i]->getClass() : NULL;
467       if (paramelts[i]->isPrimitive())
468         {
469           if (! argelts[i]
470               || ! k
471               || ! can_widen (k, paramelts[i]))
472             JvThrow (new java::lang::IllegalArgumentException);
473             
474           if (paramelts[i] == JvPrimClass (boolean))
475             COPY (&argvals[i],
476                   ((java::lang::Boolean *) argelts[i])->booleanValue(),
477                   jboolean);
478           else if (paramelts[i] == JvPrimClass (char))
479             COPY (&argvals[i],
480                   ((java::lang::Character *) argelts[i])->charValue(),
481                   jchar);
482           else
483             {
484               java::lang::Number *num = (java::lang::Number *) argelts[i];
485               if (paramelts[i] == JvPrimClass (byte))
486                 COPY (&argvals[i], num->byteValue(), jbyte);
487               else if (paramelts[i] == JvPrimClass (short))
488                 COPY (&argvals[i], num->shortValue(), jshort);
489               else if (paramelts[i] == JvPrimClass (int))
490                 COPY (&argvals[i], num->intValue(), jint);
491               else if (paramelts[i] == JvPrimClass (long))
492                 COPY (&argvals[i], num->longValue(), jlong);
493               else if (paramelts[i] == JvPrimClass (float))
494                 COPY (&argvals[i], num->floatValue(), jfloat);
495               else if (paramelts[i] == JvPrimClass (double))
496                 COPY (&argvals[i], num->doubleValue(), jdouble);
497             }
498         }
499       else
500         {
501           if (argelts[i] && ! paramelts[i]->isAssignableFrom (k))
502             JvThrow (new java::lang::IllegalArgumentException);
503           COPY (&argvals[i], argelts[i], jobject);
504         }
505     }
506
507   jvalue ret_value;
508   java::lang::Throwable *ex = _Jv_CallAnyMethodA (obj,
509                                                   return_type,
510                                                   meth,
511                                                   is_constructor,
512                                                   parameter_types,
513                                                   argvals,
514                                                   &ret_value);
515
516   if (ex)
517     JvThrow (ex);
518
519   jobject r;
520 #define VAL(Wrapper, Field)  (new Wrapper (ret_value.Field))
521   if (is_constructor)
522     r = ret_value.l;
523   else  if (return_type == JvPrimClass (byte))
524     r = VAL (java::lang::Byte, b);
525   else if (return_type == JvPrimClass (short))
526     r = VAL (java::lang::Short, s);
527   else if (return_type == JvPrimClass (int))
528     r = VAL (java::lang::Integer, i);
529   else if (return_type == JvPrimClass (long))
530     r = VAL (java::lang::Long, j);
531   else if (return_type == JvPrimClass (float))
532     r = VAL (java::lang::Float, f);
533   else if (return_type == JvPrimClass (double))
534     r = VAL (java::lang::Double, d);
535   else if (return_type == JvPrimClass (boolean))
536     r = VAL (java::lang::Boolean, z);
537   else if (return_type == JvPrimClass (char))
538     r = VAL (java::lang::Character, c);
539   else if (return_type == JvPrimClass (void))
540     r = NULL;
541   else
542     {
543       JvAssert (return_type == NULL || ! return_type->isPrimitive());
544       r = ret_value.l;
545     }
546
547   return r;
548 }