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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [java/] [lang/] [reflect/] [natVMProxy.cc] - Blame information for rev 766

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 758 jeremybenn
// natVMProxy.cc -- Implementation of VMProxy methods.
2
 
3
/* Copyright (C) 2006, 2007
4
   Free Software Foundation
5
 
6
   This file is part of libgcj.
7
 
8
This software is copyrighted work licensed under the terms of the
9
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
10
details.  */
11
 
12
// The idea of behind this code is to utilize libffi's ability to
13
// create closures to provide a fast "cut-through" way to generate
14
// proxy classes.  Instead of generating bytecode and then
15
// interpreting that, we copy the method definitions for each of the
16
// methods we're supposed to be prxying and generate a libffi closure
17
// for each one.
18
 
19
#include <config.h>
20
#include <platform.h>
21
#include <sysdep/descriptor.h>
22
 
23
#include <limits.h>
24
#include <string.h>
25
#include <stddef.h>
26
#include <stdio.h>
27
 
28
#include <gcj/cni.h>
29
#include <gcj/javaprims.h>
30
#include <jvm.h>
31
#include <jni.h>
32
#include <java-threads.h>
33
#include <java-interp.h>
34
#include <ffi.h>
35
#include <execution.h>
36
#include <gcj/method.h>
37
 
38
#include <gnu/gcj/runtime/BootClassLoader.h>
39
#include <java/lang/Class.h>
40
#include <java/lang/ClassCastException.h>
41
#include <java/lang/Error.h>
42
#include <java/lang/IllegalArgumentException.h>
43
#include <java/lang/Integer.h>
44
#include <java/lang/StringBuffer.h>
45
#include <java/lang/UnsupportedOperationException.h>
46
#include <java/lang/VMClassLoader.h>
47
#include <java/lang/VMCompiler.h>
48
#include <java/lang/reflect/InvocationHandler.h>
49
#include <java/lang/reflect/Method.h>
50
#include <java/lang/reflect/Proxy$ClassFactory.h>
51
#include <java/lang/reflect/Proxy$ProxyData.h>
52
#include <java/lang/reflect/Proxy.h>
53
#include <java/lang/reflect/UndeclaredThrowableException.h>
54
#include <java/lang/reflect/VMProxy.h>
55
 
56
#include <java/lang/Byte.h>
57
#include <java/lang/Short.h>
58
#include <java/lang/Integer.h>
59
#include <java/lang/Long.h>
60
#include <java/lang/Float.h>
61
#include <java/lang/Double.h>
62
#include <java/lang/Boolean.h>
63
#include <java/lang/Character.h>
64
 
65
 
66
using namespace java::lang::reflect;
67
using namespace java::lang;
68
 
69
#ifndef INTERPRETER
70
jclass
71
java::lang::reflect::VMProxy::generateProxyClass
72
  (ClassLoader *, Proxy$ProxyData *)
73
{
74
  throw new UnsupportedOperationException (
75
    JvNewStringLatin1 ("Interpreter not available"));
76
}
77
#else
78
typedef void (*closure_fun) (ffi_cif*, void*, void**, void*);
79
static void *ncode (int method_index, jclass klass, _Jv_Method *self, closure_fun fun);
80
static void run_proxy (ffi_cif*, void*, void**, void*);
81
 
82
typedef jobject
83
#if defined (X86_WIN32) && !defined (__CYGWIN__)
84
 __attribute__ ((thiscall))
85
#endif
86
 invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);
87
 
88
// True if pc points to a proxy frame.
89
 
90
bool
91
_Jv_is_proxy (void *pc)
92
{
93
  return pc == UNWRAP_FUNCTION_DESCRIPTOR ((void*)&run_proxy);
94
}
95
 
96
// Generate a proxy class by using libffi closures for each entry
97
// point.
98
 
99
jclass
100
java::lang::reflect::VMProxy::generateProxyClass
101
  (ClassLoader *loader, Proxy$ProxyData *d)
102
{
103
  // If we're precompiling, generate bytecode and allow VMCompiler to
104
  // precompile it.
105
  if (VMCompiler::precompiles ())
106
    return (new Proxy$ClassFactory(d))->generate(loader);
107
 
108
  jclass klass = new Class ();
109
 
110
  // Synchronize on the class, so that it is not attempted initialized
111
  // until we're done.
112
  JvSynchronize sync (klass);
113
 
114
  klass->superclass = &Proxy::class$;
115
  klass->engine = &_Jv_soleIndirectCompiledEngine;
116
  klass->size_in_bytes = -1;
117
  klass->vtable_method_count = -1;
118
 
119
  // Declare  private static transient java.lang.reflect.Method[] $Proxy0.m
120
  klass->field_count = klass->static_field_count = 1;
121
  klass->fields = (_Jv_Field*)_Jv_AllocRawObj (sizeof (_Jv_Field));
122
  klass->fields[0].name = _Jv_makeUtf8Const ("m");
123
  klass->fields[0].type = d->methods->getClass();
124
  klass->fields[0].flags = (Modifier::PRIVATE | Modifier::STATIC
125
                            | Modifier::TRANSIENT);
126
 
127
  // Record the defining loader.  For the bootstrap class loader,
128
  // we record NULL.
129
  if (loader != VMClassLoader::bootLoader)
130
    klass->loader = loader;
131
 
132
  {
133
    StringBuffer *sb = new StringBuffer();
134
    sb->append(JvNewStringLatin1 ("$Proxy"));
135
    sb->append(Integer::toString (d->id));
136
    klass->name = _Jv_makeUtf8Const (sb->toString());
137
  }
138
 
139
  // Allocate space for the interfaces.
140
  klass->interface_count = d->interfaces->length;
141
  klass->interfaces = (jclass*) _Jv_AllocRawObj (klass->interface_count
142
                                                 *sizeof (jclass));
143
  for (int i = 0; i < klass->interface_count; i++)
144
    klass->interfaces[i] = elements(d->interfaces)[i];
145
 
146
  size_t count = d->methods->length;
147
 
148
  {
149
    size_t total_count = count + Proxy::class$.method_count + 1;
150
    if (total_count >= 65536)
151
      throw new IllegalArgumentException ();
152
    // Allocate space for the methods.  This is a worst case
153
    // estimate.
154
    klass->methods
155
      = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method)
156
                                        * total_count);
157
  }
158
 
159
  jshort &method_count = klass->method_count;
160
 
161
  // Copy all reachable methods from Proxy.
162
  for (int i = 0; i < Proxy::class$.method_count; i++)
163
    {
164
      if (_Jv_CheckAccess (klass, &Proxy::class$,
165
                           Proxy::class$.methods[i].accflags))
166
        {
167
          klass->methods[method_count] = Proxy::class$.methods[i];
168
          method_count++;
169
        }
170
    }
171
 
172
  _Jv_Method *init_method
173
    = (_Jv_Linker::search_method_in_class
174
       (klass, klass,
175
        _Jv_makeUtf8Const ("<init>"),
176
        _Jv_makeUtf8Const ("(Ljava.lang.reflect.InvocationHandler;)V"),
177
        false));
178
  init_method->accflags |= Modifier::PUBLIC;
179
 
180
  // Create the methods for all of the interfaces.
181
  for (size_t i = 0; i < count; i++)
182
    {
183
      _Jv_Method &method = klass->methods[method_count++];
184
      const _Jv_Method &imethod
185
        = *_Jv_FromReflectedMethod (elements(d->methods)[i]);
186
      // We use a shallow copy of IMETHOD rather than a deep copy;
187
      // this means that the pointer fields of METHOD point into the
188
      // interface.  As long as this subclass of Proxy is reachable,
189
      // the interfaces of which it is a proxy will also be reachable,
190
      // so this is safe.
191
      method = imethod;
192
      method.ncode = ncode (i, klass, &method, run_proxy);
193
      method.accflags &= ~Modifier::ABSTRACT;
194
    }
195
 
196
  _Jv_Linker::layout_vtable_methods (klass);
197
  _Jv_RegisterInitiatingLoader (klass, klass->loader);
198
 
199
  // Set $Proxy0.m to point to the methods arrray
200
  java::lang::reflect::Field *f
201
    = klass->getDeclaredField (JvNewStringLatin1 ("m"));
202
  f->flag = true;
203
  f->set(NULL, d->methods);
204
 
205
  return klass;
206
}
207
 
208
 
209
// Box things with primitive types.
210
static inline jobject
211
box (void *thing, jclass klass, FFI_TYPE type)
212
{
213
  jobject o;
214
 
215
  switch (type)
216
    {
217
    case FFI_TYPE_VOID:
218
      return NULL;
219
 
220
    case FFI_TYPE_POINTER:
221
      o = *(jobject*)thing;
222
      return o;
223
 
224
    default:
225
      ;
226
    }
227
 
228
  if (klass == JvPrimClass (byte))
229
    o = new Byte (*(jbyte*)thing);
230
  else if (klass == JvPrimClass (short))
231
    o = new Short (*(jshort*)thing);
232
  else if (klass == JvPrimClass (int))
233
    o = new Integer (*(jint*)thing);
234
  else if (klass == JvPrimClass (long))
235
    o = new Long (*(jlong*)thing);
236
  else if (klass == JvPrimClass (float))
237
    o = new Float (*(jfloat*)thing);
238
  else if (klass == JvPrimClass (double))
239
    o = new Double (*(jdouble*)thing);
240
  else if (klass == JvPrimClass (boolean))
241
    o = new Boolean (*(jboolean*)thing);
242
  else if (klass == JvPrimClass (char))
243
    o = new Character (*(jchar*)thing);
244
  else
245
    JvFail ("Bad ffi type in proxy");
246
 
247
  return o;
248
}
249
 
250
 
251
// Unbox things with primitive types.
252
static inline void
253
unbox (jobject o, jclass klass, void *rvalue, FFI_TYPE type)
254
{
255
  switch (type)
256
    {
257
    case FFI_TYPE_VOID:
258
      return;
259
 
260
    case FFI_TYPE_POINTER:
261
      _Jv_CheckCast (klass, o);
262
      *(jobject*)rvalue = o;
263
      return;
264
 
265
    default:
266
      ;
267
    }
268
 
269
  // If the value returned ... is null and the interface method's
270
  // return type is primitive, then a NullPointerException will be
271
  // thrown ...
272
  if (klass == JvPrimClass (byte))
273
    {
274
      _Jv_CheckCast (&Byte::class$, o);
275
      *(jbyte*)rvalue = ((Byte*)o)->byteValue();
276
    }
277
  else if (klass == JvPrimClass (short))
278
    {
279
      _Jv_CheckCast (&Short::class$, o);
280
      *(jshort*)rvalue = ((Short*)o)->shortValue();
281
    }
282
  else if (klass == JvPrimClass (int))
283
    {
284
      _Jv_CheckCast (&Integer::class$, o);
285
      *(jint*)rvalue = ((Integer*)o)->intValue();
286
    }
287
  else if (klass == JvPrimClass (long))
288
    {
289
      _Jv_CheckCast (&Long::class$, o);
290
      *(jlong*)rvalue = ((Long*)o)->longValue();
291
    }
292
  else if (klass == JvPrimClass (float))
293
    {
294
      _Jv_CheckCast (&Float::class$, o);
295
      *(jfloat*)rvalue = ((Float*)o)->floatValue();
296
    }
297
  else if (klass == JvPrimClass (double))
298
    {
299
      _Jv_CheckCast (&Double::class$, o);
300
      *(jdouble*)rvalue = ((Double*)o)->doubleValue();
301
    }
302
  else if (klass == JvPrimClass (boolean))
303
    {
304
      _Jv_CheckCast (&Boolean::class$, o);
305
      *(jboolean*)rvalue = ((Boolean*)o)->booleanValue();
306
    }
307
  else if (klass == JvPrimClass (char))
308
    {
309
      _Jv_CheckCast (&Character::class$, o);
310
      *(jchar*)rvalue = ((Character*)o)->charValue();
311
    }
312
  else
313
    JvFail ("Bad ffi type in proxy");
314
}
315
 
316
// _Jv_getFieldInternal is declared as a friend of reflect.Field in
317
// libjava/headers.txt.  This gives us a way to call the private
318
// method Field.get (Class caller, Object obj).
319
extern inline jobject
320
_Jv_getFieldInternal (java::lang::reflect::Field *f, jclass c, jobject o)
321
{
322
  return f->get(c, o);
323
}
324
 
325
// run_proxy is the entry point for all proxy methods.  It boxes up
326
// all the arguments and then invokes the invocation handler's invoke()
327
// method.  Exceptions are caught and propagated.
328
 
329
typedef struct {
330
  ffi_closure  closure;
331
  _Jv_ClosureList list;
332
  ffi_cif   cif;
333
  _Jv_Method *self;
334
  int method_index;
335
  ffi_type *arg_types[0];
336
} ncode_closure;
337
 
338
static void
339
run_proxy (ffi_cif *cif,
340
           void *rvalue,
341
           void **args,
342
           void*user_data)
343
{
344
  using namespace java::lang::reflect;
345
 
346
  Proxy *proxy = *(Proxy**)args[0];
347
  ncode_closure *self = (ncode_closure *) user_data;
348
 
349
  jclass proxyClass = proxy->getClass();
350
 
351
  // FRAME_DESC registers this particular invocation as the top-most
352
  // interpreter frame.  This lets the stack tracing code (for
353
  // Throwable) print information about the Proxy being run rather
354
  // than about Proxy.class itself.  FRAME_DESC has a destructor so it
355
  // cleans up automatically when this proxy invocation returns.
356
  Thread *thread = Thread::currentThread();
357
  _Jv_InterpFrame frame_desc (self->self, thread, proxyClass,
358
                              NULL, frame_proxy);
359
 
360
  // The method to invoke is saved in $Proxy0.m[method_index].
361
  // FIXME: We could somewhat improve efficiency by storing a pointer
362
  // to the method (rather than its index) in ncode_closure.  This
363
  // would avoid the lookup, but it probably wouldn't make a huge
364
  // difference.  We'd still have to save the method array because
365
  // ncode structs are not scanned by the gc.
366
  Field *f = proxyClass->getDeclaredField (JvNewStringLatin1 ("m"));
367
  JArray<Method*> *methods
368
    = (JArray<Method*>*)_Jv_getFieldInternal (f, proxyClass, NULL);
369
  Method *meth = elements(methods)[self->method_index];
370
 
371
  JArray<jclass> *parameter_types = meth->internalGetParameterTypes ();
372
  JArray<jclass> *exception_types = meth->internalGetExceptionTypes ();
373
 
374
  InvocationHandler *handler = proxy->h;
375
  JArray<jobject> *argsArray = NULL;
376
  jobject *jargs = NULL;
377
  if (parameter_types->length)
378
    {
379
      void *poo
380
        = _Jv_NewObjectArray (parameter_types->length, &Object::class$, NULL);
381
      argsArray = (JArray<jobject> *) poo;
382
      jargs = elements(argsArray);
383
    }
384
 
385
  // FIXME: It must be possible to use fast interface dispatch here,
386
  // but I've not quite figured out how to do it.
387
  invoke_t *invoke
388
    = (invoke_t *)(_Jv_LookupInterfaceMethod
389
                   (handler->getClass (),
390
                    _Jv_makeUtf8Const ("invoke"),
391
                    (_Jv_makeUtf8Const
392
                     ("(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;)"
393
                      "Ljava.lang.Object;"))));
394
 
395
  // Copy and box all the args.
396
  int index = 1;
397
  for (int i = 0; i < parameter_types->length; i++, index++)
398
    jargs[i] = box (args[index], elements(parameter_types)[i],
399
                    cif->arg_types[index]->type);
400
 
401
  jobject ret;
402
  try
403
    {
404
      ret = invoke (handler, proxy, meth, argsArray);
405
    }
406
  catch (Throwable *t)
407
    {
408
      if (_Jv_IsInstanceOf (t, &RuntimeException::class$)
409
          || _Jv_IsInstanceOf (t, &Error::class$))
410
        throw t;
411
 
412
      Class **throwables = elements (exception_types);
413
      for (int i = 0; i < exception_types->length; i++)
414
        if (_Jv_IsInstanceOf (t, throwables[i]))
415
          throw t;
416
 
417
      throw new UndeclaredThrowableException (t);
418
    }
419
 
420
  unbox (ret, meth->return_type, rvalue, cif->rtype->type);
421
}
422
 
423
 
424
// Given a method and a closure function, create libffi CIF and return
425
// the address of its closure.
426
 
427
static void *
428
ncode (int method_index, jclass klass, _Jv_Method *self, closure_fun fun)
429
{
430
  using namespace java::lang::reflect;
431
 
432
  jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
433
  int arg_count = _Jv_count_arguments (self->signature, staticp);
434
 
435
  void *code;
436
  ncode_closure *closure =
437
    (ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure)
438
                                       + arg_count * sizeof (ffi_type*),
439
                                       &code);
440
  closure->method_index = method_index;
441
  closure->list.registerClosure (klass, closure);
442
 
443
  _Jv_init_cif (self->signature,
444
                arg_count,
445
                staticp,
446
                &closure->cif,
447
                &closure->arg_types[0],
448
                NULL);
449
  closure->self = self;
450
 
451
  JvAssert ((self->accflags & Modifier::NATIVE) == 0);
452
 
453
  ffi_prep_closure_loc (&closure->closure,
454
                        &closure->cif,
455
                        fun,
456
                        code,
457
                        code);
458
 
459
  self->ncode = code;
460
  return self->ncode;
461
}
462
 
463
#endif // INTERPRETER

powered by: WebSVN 2.1.0

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