OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [java/] [lang/] [reflect/] [natMethod.cc] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
// natMethod.cc - Native code for Method class.
2
 
3
/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004, 2005 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
#include <gcj/cni.h>
14
#include <jvm.h>
15
#include <jni.h>
16
#include <java-stack.h>
17
 
18
#include <java/lang/reflect/Method.h>
19
#include <java/lang/reflect/Constructor.h>
20
#include <java/lang/reflect/InvocationTargetException.h>
21
#include <java/lang/reflect/Modifier.h>
22
 
23
#include <java/lang/Void.h>
24
#include <java/lang/Byte.h>
25
#include <java/lang/Boolean.h>
26
#include <java/lang/Character.h>
27
#include <java/lang/Short.h>
28
#include <java/lang/Integer.h>
29
#include <java/lang/Long.h>
30
#include <java/lang/Float.h>
31
#include <java/lang/Double.h>
32
#include <java/lang/IllegalAccessException.h>
33
#include <java/lang/IllegalArgumentException.h>
34
#include <java/lang/IncompatibleClassChangeError.h>
35
#include <java/lang/NullPointerException.h>
36
#include <java/lang/ArrayIndexOutOfBoundsException.h>
37
#include <java/lang/VirtualMachineError.h>
38
#include <java/lang/Class.h>
39
#include <gcj/method.h>
40
#include <gnu/gcj/RawData.h>
41
#include <java/lang/NoClassDefFoundError.h>
42
 
43
#include <stdlib.h>
44
 
45
#if USE_LIBFFI
46
#include <ffi.h>
47
#else
48
#include <java/lang/UnsupportedOperationException.h>
49
#endif
50
 
51
struct cpair
52
{
53
  jclass prim;
54
  jclass wrap;
55
};
56
 
57
// This is used to determine when a primitive widening conversion is
58
// allowed.
59
static cpair primitives[] =
60
{
61
#define BOOLEAN 0
62
  { JvPrimClass (boolean), &java::lang::Boolean::class$ },
63
  { JvPrimClass (byte), &java::lang::Byte::class$ },
64
#define SHORT 2
65
  { JvPrimClass (short), &java::lang::Short::class$ },
66
#define CHAR 3
67
  { JvPrimClass (char), &java::lang::Character::class$ },
68
  { JvPrimClass (int), &java::lang::Integer::class$ },
69
  { JvPrimClass (long), &java::lang::Long::class$ },
70
  { JvPrimClass (float), &java::lang::Float::class$ },
71
  { JvPrimClass (double), &java::lang::Double::class$ },
72
  { NULL, NULL }
73
};
74
 
75
static inline jboolean
76
can_widen (jclass from, jclass to)
77
{
78
  int fromx = -1, tox = -1;
79
 
80
  for (int i = 0; primitives[i].prim; ++i)
81
    {
82
      if (primitives[i].wrap == from)
83
        fromx = i;
84
      if (primitives[i].prim == to)
85
        tox = i;
86
    }
87
 
88
  // Can't handle a miss.
89
  if (fromx == -1 || tox == -1)
90
    return false;
91
  // Boolean arguments may not be widened.
92
  if (fromx == BOOLEAN && tox != BOOLEAN)
93
    return false;
94
  // Nothing promotes to char.
95
  if (tox == CHAR && fromx != CHAR)
96
    return false;
97
 
98
  return fromx <= tox;
99
}
100
 
101
#ifdef USE_LIBFFI
102
static inline ffi_type *
103
get_ffi_type (jclass klass)
104
{
105
  // A special case.
106
  if (klass == NULL)
107
    return &ffi_type_pointer;
108
 
109
  ffi_type *r;
110
  if (klass == JvPrimClass (byte))
111
    r = &ffi_type_sint8;
112
  else if (klass == JvPrimClass (short))
113
    r = &ffi_type_sint16;
114
  else if (klass == JvPrimClass (int))
115
    r = &ffi_type_sint32;
116
  else if (klass == JvPrimClass (long))
117
    r = &ffi_type_sint64;
118
  else if (klass == JvPrimClass (float))
119
    r = &ffi_type_float;
120
  else if (klass == JvPrimClass (double))
121
    r = &ffi_type_double;
122
  else if (klass == JvPrimClass (boolean))
123
    {
124
      // On some platforms a bool is a byte, on others an int.
125
      if (sizeof (jboolean) == sizeof (jbyte))
126
        r = &ffi_type_sint8;
127
      else
128
        {
129
          JvAssert (sizeof (jboolean) == sizeof (jint));
130
          r = &ffi_type_sint32;
131
        }
132
    }
133
  else if (klass == JvPrimClass (char))
134
    r = &ffi_type_uint16;
135
  else
136
    {
137
      JvAssert (! klass->isPrimitive());
138
      r = &ffi_type_pointer;
139
    }
140
 
141
  return r;
142
}
143
#endif // USE_LIBFFI
144
 
145
jobject
146
java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
147
{
148
  using namespace java::lang::reflect;
149
  jclass iface = NULL;
150
 
151
  if (parameter_types == NULL)
152
    getType ();
153
 
154
  jmethodID meth = _Jv_FromReflectedMethod (this);
155
 
156
  if (Modifier::isStatic(meth->accflags))
157
    {
158
      // We have to initialize a static class.  It is safe to do this
159
      // here and not in _Jv_CallAnyMethodA because JNI initializes a
160
      // class whenever a method lookup is done.
161
      _Jv_InitClass (declaringClass);
162
    }
163
  else
164
    {
165
      jclass objClass = JV_CLASS (obj);
166
      if (! _Jv_IsAssignableFrom (objClass, declaringClass))
167
        throw new java::lang::IllegalArgumentException;
168
    }
169
 
170
  // Check accessibility, if required.
171
  if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
172
    {
173
      Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$);
174
      if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
175
        throw new IllegalAccessException;
176
    }
177
 
178
  if (declaringClass->isInterface())
179
    iface = declaringClass;
180
 
181
  return _Jv_CallAnyMethodA (obj, return_type, meth, false,
182
                             parameter_types, args, iface);
183
}
184
 
185
jint
186
java::lang::reflect::Method::getModifiers ()
187
{
188
  // Ignore all unknown flags.
189
  return _Jv_FromReflectedMethod (this)->accflags & Modifier::ALL_FLAGS;
190
}
191
 
192
jstring
193
java::lang::reflect::Method::getName ()
194
{
195
  if (name == NULL)
196
    name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name);
197
  return name;
198
}
199
 
200
/* Internal method to set return_type and parameter_types fields. */
201
 
202
void
203
java::lang::reflect::Method::getType ()
204
{
205
  _Jv_Method *method = _Jv_FromReflectedMethod (this);
206
  _Jv_GetTypesFromSignature (method,
207
                             declaringClass,
208
                             &parameter_types,
209
                             &return_type);
210
 
211
  int count = 0;
212
  if (method->throws != NULL)
213
    {
214
      while (method->throws[count] != NULL)
215
        ++count;
216
    }
217
 
218
  exception_types
219
    = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$,
220
                                           NULL);
221
  jclass *elts = elements (exception_types);
222
  for (int i = 0; i < count; ++i)
223
    elts[i] = _Jv_FindClass (method->throws[i],
224
                             declaringClass->getClassLoaderInternal ());
225
}
226
 
227
void
228
_Jv_GetTypesFromSignature (jmethodID method,
229
                           jclass declaringClass,
230
                           JArray<jclass> **arg_types_out,
231
                           jclass *return_type_out)
232
{
233
 
234
  _Jv_Utf8Const* sig = method->signature;
235
  java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal();
236
  char *ptr = sig->chars();
237
  int numArgs = 0;
238
  /* First just count the number of parameters. */
239
  // FIXME: should do some validation here, e.g., that there is only
240
  // one return type.
241
  for (; ; ptr++)
242
    {
243
      switch (*ptr)
244
        {
245
        case 0:
246
        case ')':
247
        case 'V':
248
          break;
249
        case '[':
250
        case '(':
251
          continue;
252
        case 'B':
253
        case 'C':
254
        case 'D':
255
        case 'F':
256
        case 'S':
257
        case 'I':
258
        case 'J':
259
        case 'Z':
260
          numArgs++;
261
          continue;
262
        case 'L':
263
          numArgs++;
264
          do
265
            ptr++;
266
          while (*ptr != ';' && ptr[1] != '\0');
267
          continue;
268
        }
269
      break;
270
    }
271
 
272
  JArray<jclass> *args = (JArray<jclass> *)
273
    JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL);
274
  jclass* argPtr = elements (args);
275
  for (ptr = sig->chars(); *ptr != '\0'; ptr++)
276
    {
277
      if (*ptr == '(')
278
        continue;
279
      if (*ptr == ')')
280
        {
281
          argPtr = return_type_out;
282
          continue;
283
        }
284
 
285
      char *end_ptr;
286
      jclass type = _Jv_FindClassFromSignature (ptr, loader, &end_ptr);
287
      if (type == NULL)
288
        // FIXME: This isn't ideal.
289
        throw new java::lang::NoClassDefFoundError (sig->toString());
290
 
291
      // ARGPTR can be NULL if we are processing the return value of a
292
      // call from Constructor.
293
      if (argPtr)
294
        *argPtr++ = type;
295
 
296
      ptr = end_ptr;
297
    }
298
  *arg_types_out = args;
299
}
300
 
301
// This is a very rough analog of the JNI CallNonvirtual<type>MethodA
302
// functions.  It handles both Methods and Constructors, and it can
303
// handle any return type.  In the Constructor case, the `obj'
304
// argument is unused and should be NULL; also, the `return_type' is
305
// the class that the constructor will construct.  RESULT is a pointer
306
// to a `jvalue' (see jni.h); for a void method this should be NULL.
307
// This function returns an exception (if one was thrown), or NULL if
308
// the call went ok.
309
void
310
_Jv_CallAnyMethodA (jobject obj,
311
                    jclass return_type,
312
                    jmethodID meth,
313
                    jboolean is_constructor,
314
                    jboolean is_virtual_call,
315
                    JArray<jclass> *parameter_types,
316
                    jvalue *args,
317
                    jvalue *result,
318
                    jboolean is_jni_call,
319
                    jclass iface)
320
{
321
  using namespace java::lang::reflect;
322
 
323
#ifdef USE_LIBFFI
324
  JvAssert (! is_constructor || ! obj);
325
  JvAssert (! is_constructor || return_type);
326
 
327
  // See whether call needs an object as the first argument.  A
328
  // constructor does need a `this' argument, but it is one we create.
329
  jboolean needs_this = false;
330
  if (is_constructor
331
      || ! Modifier::isStatic(meth->accflags))
332
    needs_this = true;
333
 
334
  int param_count = parameter_types->length;
335
  if (needs_this)
336
    ++param_count;
337
 
338
  ffi_type *rtype;
339
  // A constructor itself always returns void.
340
  if (is_constructor || return_type == JvPrimClass (void))
341
    rtype = &ffi_type_void;
342
  else
343
    rtype = get_ffi_type (return_type);
344
  ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count
345
                                                        * sizeof (ffi_type *));
346
 
347
  jclass *paramelts = elements (parameter_types);
348
 
349
  // Special case for the `this' argument of a constructor.  Note that
350
  // the JDK 1.2 docs specify that the new object must be allocated
351
  // before argument conversions are done.
352
  if (is_constructor)
353
    obj = _Jv_AllocObject (return_type);
354
 
355
  const int size_per_arg = sizeof(jvalue);
356
  ffi_cif cif;
357
 
358
  char *p = (char *) __builtin_alloca (param_count * size_per_arg);
359
                // Overallocate to get correct alignment.
360
  void **values = (void **)
361
                        __builtin_alloca (param_count * sizeof (void *));
362
 
363
  int i = 0;
364
  if (needs_this)
365
    {
366
      // The `NULL' type is `Object'.
367
      argtypes[i] = get_ffi_type (NULL);
368
      values[i] = p;
369
      memcpy (p, &obj, sizeof (jobject));
370
      p += size_per_arg;
371
      ++i;
372
    }
373
 
374
  for (int arg = 0; i < param_count; ++i, ++arg)
375
    {
376
      int tsize;
377
 
378
      argtypes[i] = get_ffi_type (paramelts[arg]);
379
      if (paramelts[arg]->isPrimitive())
380
        tsize = paramelts[arg]->size();
381
      else
382
        tsize = sizeof (jobject);
383
 
384
      // Copy appropriate bits from the jvalue into the ffi array.
385
      // FIXME: we could do this copying all in one loop, above, by
386
      // over-allocating a bit.
387
      // How do we do this without breaking big-endian platforms?
388
      values[i] = p;
389
      memcpy (p, &args[arg], tsize);
390
      p += size_per_arg;
391
    }
392
 
393
  if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count,
394
                    rtype, argtypes) != FFI_OK)
395
    throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed"));
396
 
397
  using namespace java::lang;
398
  using namespace java::lang::reflect;
399
 
400
  union
401
  {
402
    ffi_arg i;
403
    jobject o;
404
    jlong l;
405
    jfloat f;
406
    jdouble d;
407
  } ffi_result;
408
 
409
  switch (rtype->type)
410
    {
411
    case FFI_TYPE_VOID:
412
      break;
413
    case FFI_TYPE_SINT8:
414
      result->b = 0;
415
      break;
416
    case FFI_TYPE_SINT16:
417
      result->s = 0;
418
      break;
419
    case FFI_TYPE_UINT16:
420
      result->c = 0;
421
      break;
422
    case FFI_TYPE_SINT32:
423
      result->i = 0;
424
      break;
425
    case FFI_TYPE_SINT64:
426
      result->j = 0;
427
      break;
428
    case FFI_TYPE_FLOAT:
429
      result->f = 0;
430
      break;
431
    case FFI_TYPE_DOUBLE:
432
      result->d = 0;
433
      break;
434
    case FFI_TYPE_POINTER:
435
      result->l = 0;
436
      break;
437
    default:
438
      JvFail ("Unknown ffi_call return type");
439
      break;
440
    }
441
 
442
  void *ncode;
443
 
444
  // FIXME: If a vtable index is -1 at this point it is invalid, so we
445
  // have to use the ncode.  
446
  //
447
  // This can happen because methods in final classes don't have
448
  // vtable entries, but _Jv_isVirtualMethod() doesn't know that.  We
449
  // could solve this problem by allocating a vtable index for methods
450
  // in final classes.
451
  if (is_virtual_call
452
      && ! Modifier::isFinal (meth->accflags)
453
      && (_Jv_ushort)-1 != meth->index)
454
    {
455
      _Jv_VTable *vtable = *(_Jv_VTable **) obj;
456
      if (iface == NULL)
457
        {
458
          if (is_jni_call && Modifier::isAbstract (meth->accflags))
459
            {
460
              // With JNI we don't know if this is an interface call
461
              // or a call to an abstract method.  Look up the method
462
              // by name, the slow way.
463
              _Jv_Method *concrete_meth
464
                = _Jv_LookupDeclaredMethod (vtable->clas,
465
                                            meth->name,
466
                                            meth->signature,
467
                                            NULL);
468
              if (concrete_meth == NULL
469
                  || concrete_meth->ncode == NULL
470
                  || Modifier::isAbstract(concrete_meth->accflags))
471
                throw new java::lang::IncompatibleClassChangeError
472
                  (_Jv_GetMethodString (vtable->clas, meth));
473
              ncode = concrete_meth->ncode;
474
            }
475
          else
476
            ncode = vtable->get_method (meth->index);
477
        }
478
      else
479
        ncode = _Jv_LookupInterfaceMethodIdx (vtable->clas, iface,
480
                                              meth->index);
481
    }
482
  else
483
    {
484
      ncode = meth->ncode;
485
    }
486
 
487
  try
488
    {
489
      ffi_call (&cif, (void (*)()) ncode, &ffi_result, values);
490
    }
491
  catch (Throwable *ex)
492
    {
493
      // For JNI we just throw the real error.  For reflection, we
494
      // wrap the underlying method's exception in an
495
      // InvocationTargetException.
496
      if (! is_jni_call)
497
        ex = new InvocationTargetException (ex);
498
      throw ex;
499
    }
500
 
501
  // Since ffi_call returns integer values promoted to a word, use
502
  // a narrowing conversion for jbyte, jchar, etc. results.
503
  // Note that boolean is handled either by the FFI_TYPE_SINT8 or
504
  // FFI_TYPE_SINT32 case.
505
  if (is_constructor)
506
    result->l = obj;
507
  else
508
    {
509
      switch (rtype->type)
510
        {
511
        case FFI_TYPE_VOID:
512
          break;
513
        case FFI_TYPE_SINT8:
514
          result->b = (jbyte)ffi_result.i;
515
          break;
516
        case FFI_TYPE_SINT16:
517
          result->s = (jshort)ffi_result.i;
518
          break;
519
        case FFI_TYPE_UINT16:
520
          result->c = (jchar)ffi_result.i;
521
          break;
522
        case FFI_TYPE_SINT32:
523
          result->i = (jint)ffi_result.i;
524
          break;
525
        case FFI_TYPE_SINT64:
526
          result->j = (jlong)ffi_result.l;
527
          break;
528
        case FFI_TYPE_FLOAT:
529
          result->f = (jfloat)ffi_result.f;
530
          break;
531
        case FFI_TYPE_DOUBLE:
532
          result->d = (jdouble)ffi_result.d;
533
          break;
534
        case FFI_TYPE_POINTER:
535
          result->l = (jobject)ffi_result.o;
536
          break;
537
        default:
538
          JvFail ("Unknown ffi_call return type");
539
          break;
540
        }
541
    }
542
#else
543
  throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build"));
544
#endif // USE_LIBFFI
545
}
546
 
547
// This is another version of _Jv_CallAnyMethodA, but this one does
548
// more checking and is used by the reflection (and not JNI) code.
549
jobject
550
_Jv_CallAnyMethodA (jobject obj,
551
                    jclass return_type,
552
                    jmethodID meth,
553
                    jboolean is_constructor,
554
                    JArray<jclass> *parameter_types,
555
                    jobjectArray args,
556
                    jclass iface)
557
{
558
  if (parameter_types->length == 0 && args == NULL)
559
    {
560
      // The JDK accepts this, so we do too.
561
    }
562
  else if (parameter_types->length != args->length)
563
    throw new java::lang::IllegalArgumentException;
564
 
565
  int param_count = parameter_types->length;
566
 
567
  jclass *paramelts = elements (parameter_types);
568
  jobject *argelts = args == NULL ? NULL : elements (args);
569
  jvalue argvals[param_count];
570
 
571
#define COPY(Where, What, Type) \
572
  do { \
573
    Type val = (What); \
574
    memcpy ((Where), &val, sizeof (Type)); \
575
  } while (0)
576
 
577
  for (int i = 0; i < param_count; ++i)
578
    {
579
      jclass k = argelts[i] ? argelts[i]->getClass() : NULL;
580
      if (paramelts[i]->isPrimitive())
581
        {
582
          if (! argelts[i]
583
              || ! k
584
              || ! can_widen (k, paramelts[i]))
585
            throw new java::lang::IllegalArgumentException;
586
 
587
          if (paramelts[i] == JvPrimClass (boolean))
588
            COPY (&argvals[i],
589
                  ((java::lang::Boolean *) argelts[i])->booleanValue(),
590
                  jboolean);
591
          else if (paramelts[i] == JvPrimClass (char))
592
            COPY (&argvals[i],
593
                  ((java::lang::Character *) argelts[i])->charValue(),
594
                  jchar);
595
          else
596
            {
597
              java::lang::Number *num = (java::lang::Number *) argelts[i];
598
              if (paramelts[i] == JvPrimClass (byte))
599
                COPY (&argvals[i], num->byteValue(), jbyte);
600
              else if (paramelts[i] == JvPrimClass (short))
601
                COPY (&argvals[i], num->shortValue(), jshort);
602
              else if (paramelts[i] == JvPrimClass (int))
603
                COPY (&argvals[i], num->intValue(), jint);
604
              else if (paramelts[i] == JvPrimClass (long))
605
                COPY (&argvals[i], num->longValue(), jlong);
606
              else if (paramelts[i] == JvPrimClass (float))
607
                COPY (&argvals[i], num->floatValue(), jfloat);
608
              else if (paramelts[i] == JvPrimClass (double))
609
                COPY (&argvals[i], num->doubleValue(), jdouble);
610
            }
611
        }
612
      else
613
        {
614
          if (argelts[i] && ! paramelts[i]->isAssignableFrom (k))
615
            throw new java::lang::IllegalArgumentException;
616
          COPY (&argvals[i], argelts[i], jobject);
617
        }
618
    }
619
 
620
  jvalue ret_value;
621
  _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor,
622
                      _Jv_isVirtualMethod (meth),
623
                      parameter_types, argvals, &ret_value,
624
                      false, iface);
625
 
626
  jobject r;
627
#define VAL(Wrapper, Field)  (new Wrapper (ret_value.Field))
628
  if (is_constructor)
629
    r = ret_value.l;
630
  else  if (return_type == JvPrimClass (byte))
631
    r = VAL (java::lang::Byte, b);
632
  else if (return_type == JvPrimClass (short))
633
    r = VAL (java::lang::Short, s);
634
  else if (return_type == JvPrimClass (int))
635
    r = VAL (java::lang::Integer, i);
636
  else if (return_type == JvPrimClass (long))
637
    r = VAL (java::lang::Long, j);
638
  else if (return_type == JvPrimClass (float))
639
    r = VAL (java::lang::Float, f);
640
  else if (return_type == JvPrimClass (double))
641
    r = VAL (java::lang::Double, d);
642
  else if (return_type == JvPrimClass (boolean))
643
    r = VAL (java::lang::Boolean, z);
644
  else if (return_type == JvPrimClass (char))
645
    r = VAL (java::lang::Character, c);
646
  else if (return_type == JvPrimClass (void))
647
    r = NULL;
648
  else
649
    {
650
      JvAssert (return_type == NULL || ! return_type->isPrimitive());
651
      r = ret_value.l;
652
    }
653
 
654
  return r;
655
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.