OSDN Git Service

2007-04-02 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / reflect / natVMProxy.cc
1 // 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/VMClassLoader.h>
46 #include <java/lang/VMCompiler.h>
47 #include <java/lang/reflect/InvocationHandler.h>
48 #include <java/lang/reflect/Method.h>
49 #include <java/lang/reflect/Proxy$ClassFactory.h>
50 #include <java/lang/reflect/Proxy$ProxyData.h>
51 #include <java/lang/reflect/Proxy.h>
52 #include <java/lang/reflect/UndeclaredThrowableException.h>
53 #include <java/lang/reflect/VMProxy.h>
54
55 #include <java/lang/Byte.h>
56 #include <java/lang/Short.h>
57 #include <java/lang/Integer.h>
58 #include <java/lang/Long.h>
59 #include <java/lang/Float.h>
60 #include <java/lang/Double.h>
61 #include <java/lang/Boolean.h>
62 #include <java/lang/Character.h>
63
64
65 using namespace java::lang::reflect;
66 using namespace java::lang;
67
68 typedef void (*closure_fun) (ffi_cif*, void*, void**, void*);
69 static void *ncode (jclass klass, _Jv_Method *self, closure_fun fun);
70 static void run_proxy (ffi_cif*, void*, void**, void*);
71
72 typedef jobject invoke_t (jobject, Proxy *, Method *, JArray< jobject > *);
73
74 // True if pc points to a proxy frame.
75
76 bool 
77 _Jv_is_proxy (void *pc)
78 {
79   return pc == UNWRAP_FUNCTION_DESCRIPTOR ((void*)&run_proxy);
80 }
81
82 // Generate a proxy class by using libffi closures for each entry
83 // point.
84
85 jclass
86 java::lang::reflect::VMProxy::generateProxyClass 
87   (ClassLoader *loader, Proxy$ProxyData *d)
88 {
89   // If we're precompiling, generate bytecode and allow VMCompiler to
90   // precompile it.
91   if (VMCompiler::precompiles ())
92     return (new Proxy$ClassFactory(d))->generate(loader);
93
94   jclass klass = new Class ();
95   klass->superclass = &Proxy::class$;
96   klass->engine = &_Jv_soleIndirectCompiledEngine;
97   klass->size_in_bytes = Proxy::class$.size_in_bytes;
98   klass->vtable_method_count = -1;
99
100   // Synchronize on the class, so that it is not attempted initialized
101   // until we're done.
102   JvSynchronize sync (klass);
103
104   // Record the defining loader.  For the bootstrap class loader,
105   // we record NULL.
106   if (loader != VMClassLoader::bootLoader)
107     klass->loader = loader;
108
109   {
110     StringBuffer *sb = new StringBuffer();
111     sb->append(JvNewStringLatin1 ("$Proxy"));
112     sb->append(Integer::toString (d->id));
113     klass->name = _Jv_makeUtf8Const (sb->toString());
114   }
115
116   // Allocate space for the interfaces.
117   klass->interface_count = d->interfaces->length;
118   klass->interfaces = (jclass*) _Jv_AllocRawObj (klass->interface_count
119                                                  *sizeof (jclass));
120   for (int i = 0; i < klass->interface_count; i++)
121     klass->interfaces[i] = elements(d->interfaces)[i];
122
123   size_t count = d->methods->length;
124
125   {
126     size_t total_count = count + Proxy::class$.method_count + 1;
127     if (total_count >= 65536)
128       throw new IllegalArgumentException ();
129     // Allocate space for the methods.  This is a worst case
130     // estimate.
131     klass->methods 
132       = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method) 
133                                         * total_count);
134   }
135
136   jshort &method_count = klass->method_count;
137
138   // Copy all reachable methods from Proxy.
139   for (int i = 0; i < Proxy::class$.method_count; i++)
140     {
141       if (_Jv_CheckAccess (klass, &Proxy::class$,
142                            Proxy::class$.methods[i].accflags))
143         {
144           klass->methods[method_count] = Proxy::class$.methods[i];
145           method_count++;
146         }
147     }
148
149   _Jv_Method *init_method 
150     = (_Jv_Linker::search_method_in_class 
151        (klass, klass,
152         _Jv_makeUtf8Const ("<init>"),
153         _Jv_makeUtf8Const ("(Ljava.lang.reflect.InvocationHandler;)V"),
154         false));  
155   init_method->accflags |= Modifier::PUBLIC;
156
157   // Create the methods for all of the interfaces.
158   for (size_t i = 0; i < count; i++)
159     {
160       _Jv_Method &method = klass->methods[method_count++];
161       const _Jv_Method &imethod = *_Jv_FromReflectedMethod (elements(d->methods)[i]);
162       // We use a shallow copy of IMETHOD rather than a deep copy;
163       // this means that the pointer fields of METHOD point into the
164       // interface.  As long as this subclass of Proxy is reachable,
165       // the interfaces of which it is a proxy will also be reachable,
166       // so this is safe.
167       method = imethod;
168       method.ncode = ncode (klass, &method, run_proxy);
169       method.accflags &= ~Modifier::ABSTRACT;
170     }
171
172   _Jv_Linker::layout_vtable_methods (klass);
173   _Jv_RegisterInitiatingLoader (klass, klass->loader);
174
175   return klass;
176 }
177
178
179 // Box things with primitive types.
180 static inline jobject
181 box (void *thing, jclass klass, FFI_TYPE type)
182 {
183   jobject o;
184
185   switch (type)
186     {
187     case FFI_TYPE_VOID:
188       return NULL;
189       
190     case FFI_TYPE_POINTER:
191       o = *(jobject*)thing;
192       return o;
193
194     default:
195       ;
196     }
197
198   if (klass == JvPrimClass (byte))
199     o = new Byte (*(jbyte*)thing);
200   else if (klass == JvPrimClass (short))
201     o = new Short (*(jshort*)thing);
202   else if (klass == JvPrimClass (int))
203     o = new Integer (*(jint*)thing);
204   else if (klass == JvPrimClass (long))
205     o = new Long (*(jlong*)thing);
206   else if (klass == JvPrimClass (float))
207     o = new Float (*(jfloat*)thing);
208   else if (klass == JvPrimClass (double))
209     o = new Double (*(jdouble*)thing);
210   else if (klass == JvPrimClass (boolean))
211     o = new Boolean (*(jboolean*)thing);
212   else if (klass == JvPrimClass (char))
213     o = new Character (*(jchar*)thing);
214   else
215     JvFail ("Bad ffi type in proxy");
216
217   return o;
218 }  
219
220
221 // Unbox things with primitive types.
222 static inline void
223 unbox (jobject o, jclass klass, void *rvalue, FFI_TYPE type)
224 {
225   switch (type)
226     {
227     case FFI_TYPE_VOID:
228       return;
229       
230     case FFI_TYPE_POINTER:
231       _Jv_CheckCast (klass, o);
232       *(jobject*)rvalue = o;
233       return;
234
235     default:
236       ;
237     }
238
239   // If the value returned ... is null and the interface method's
240   // return type is primitive, then a NullPointerException will be
241   // thrown ...
242   if (klass == JvPrimClass (byte))
243     {
244       _Jv_CheckCast (&Byte::class$, o);
245       *(jbyte*)rvalue = ((Byte*)o)->byteValue();
246     }
247   else if (klass == JvPrimClass (short))
248     {
249       _Jv_CheckCast (&Short::class$, o);
250       *(jshort*)rvalue = ((Short*)o)->shortValue();
251     }
252   else if (klass == JvPrimClass (int))
253     {
254       _Jv_CheckCast (&Integer::class$, o);
255       *(jint*)rvalue = ((Integer*)o)->intValue();
256     }
257   else if (klass == JvPrimClass (long))
258     {
259       _Jv_CheckCast (&Long::class$, o);
260       *(jlong*)rvalue = ((Long*)o)->longValue();
261     }
262   else if (klass == JvPrimClass (float))
263     {
264       _Jv_CheckCast (&Float::class$, o);
265       *(jfloat*)rvalue = ((Float*)o)->floatValue();
266     }
267   else if (klass == JvPrimClass (double))
268     {
269       _Jv_CheckCast (&Double::class$, o);
270       *(jdouble*)rvalue = ((Double*)o)->doubleValue();
271     }
272   else if (klass == JvPrimClass (boolean))
273     {
274       _Jv_CheckCast (&Boolean::class$, o);
275       *(jboolean*)rvalue = ((Boolean*)o)->booleanValue();
276     }
277   else if (klass == JvPrimClass (char))
278     {
279       _Jv_CheckCast (&Character::class$, o);
280       *(jchar*)rvalue = ((Character*)o)->charValue();
281     }
282   else
283     JvFail ("Bad ffi type in proxy");
284 }
285
286 // run_proxy is the entry point for all proxy methods.  It boxes up
287 // all the arguments and then invokes the invocation handler's invoke()
288 // method.  Exceptions are caught and propagated.
289
290 typedef struct {
291   ffi_closure  closure;
292   _Jv_ClosureList list;
293   ffi_cif   cif;
294   _Jv_Method *self;
295   ffi_type *arg_types[0];
296 } ncode_closure;
297
298 static void
299 run_proxy (ffi_cif *cif,
300            void *rvalue,
301            void **args,
302            void*user_data)
303 {
304   using namespace java::lang::reflect;
305
306   Proxy *proxy = *(Proxy**)args[0];
307   ncode_closure *self = (ncode_closure *) user_data;
308
309   // FRAME_DESC registers this particular invocation as the top-most
310   // interpreter frame.  This lets the stack tracing code (for
311   // Throwable) print information about the Proxy being run rather
312   // than about Proxy.class itself.  FRAME_DESC has a destructor so it
313   // cleans up automatically when this proxy invocation returns.
314   Thread *thread = Thread::currentThread();
315   _Jv_InterpFrame frame_desc (self->self, thread, proxy->getClass());
316
317   Method *meth = _Jv_LookupProxyMethod (proxy->getClass(), 
318                                         self->self->name,
319                                         self->self->signature);
320   JArray<jclass> *parameter_types = meth->internalGetParameterTypes ();
321   JArray<jclass> *exception_types = meth->internalGetExceptionTypes ();
322
323   InvocationHandler *handler = proxy->h;
324   JArray<jobject> *argsArray = NULL;
325   jobject *jargs = NULL;
326   if (parameter_types->length)
327     {
328       void *poo 
329         = _Jv_NewObjectArray (parameter_types->length, &Object::class$, NULL);
330       argsArray = (JArray<jobject> *) poo;
331       jargs = elements(argsArray);
332     }
333
334   // FIXME: It must be possible to use fast interface dispatch here,
335   // but I've not quite figured out how to do it.
336   invoke_t *invoke
337     = (invoke_t *)(_Jv_LookupInterfaceMethod 
338                    (handler->getClass (), 
339                     _Jv_makeUtf8Const ("invoke"),
340                     (_Jv_makeUtf8Const 
341                      ("(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;)"
342                       "Ljava.lang.Object;"))));
343
344   // Copy and box all the args.
345   int index = 1;
346   for (int i = 0; i < parameter_types->length; i++, index++)
347     jargs[i] = box (args[index], elements(parameter_types)[i],
348                     cif->arg_types[index]->type);
349   
350   jobject ret;
351   try
352     {
353       ret = invoke (handler, proxy, meth, argsArray);
354     }
355   catch (Throwable *t)
356     {
357       if (_Jv_IsInstanceOf (t, &RuntimeException::class$)
358           || _Jv_IsInstanceOf (t, &Error::class$))
359         throw t;
360
361       Class **throwables = elements (exception_types);
362       for (int i = 0; i < exception_types->length; i++)
363         if (_Jv_IsInstanceOf (t, throwables[i]))
364           throw t;
365
366       throw new UndeclaredThrowableException (t);
367     }
368
369   unbox (ret, meth->return_type, rvalue, cif->rtype->type);
370 }
371
372
373 // Given a method and a closure function, create libffi CIF and return
374 // the address of its closure.
375
376 static void *
377 ncode (jclass klass, _Jv_Method *self, closure_fun fun)
378 {
379   using namespace java::lang::reflect;
380
381   jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
382   int arg_count = _Jv_count_arguments (self->signature, staticp);
383
384   void *code;
385   ncode_closure *closure =
386     (ncode_closure*)ffi_closure_alloc (sizeof (ncode_closure)
387                                        + arg_count * sizeof (ffi_type*),
388                                        &code);
389   closure->list.registerClosure (klass, closure);
390
391   _Jv_init_cif (self->signature,
392                 arg_count,
393                 staticp,
394                 &closure->cif,
395                 &closure->arg_types[0],
396                 NULL);
397   closure->self = self;
398
399   JvAssert ((self->accflags & Modifier::NATIVE) == 0);
400
401   ffi_prep_closure_loc (&closure->closure,
402                         &closure->cif,
403                         fun,
404                         code,
405                         code);
406
407   self->ncode = code;
408   return self->ncode;
409 }