| 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
 |