Mon Apr 29 12:47:36 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / object.c
index aeef675dbf4eff38c03991e8addf23d8ee1ceb4e..a7f45a0a635b177922699ee6fb9432cb2cd5abde 100644 (file)
 #include <stdio.h>
 #include <signal.h>
 #include <string.h>
+#include <mono/metadata/mono-endian.h>
 #include <mono/metadata/tabledefs.h>
+#include <mono/metadata/tokentype.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/object.h>
+#include <mono/metadata/gc.h>
 #include <mono/metadata/appdomain.h>
 #if HAVE_BOEHM_GC
 #include <gc/gc.h>
 #endif
 
+MonoStats mono_stats;
+
+/* next object id for object hashcode */
+static guint32 uoid = 0;
+
 void
 mono_runtime_object_init (MonoObject *this)
 {
@@ -59,7 +67,234 @@ mono_runtime_class_init (MonoClass *klass)
                }
        }
        /* No class constructor found */
+}
+
+static gpointer
+default_trampoline (MonoMethod *method)
+{
+       return method;
+}
+
+static gpointer
+default_remoting_trampoline (MonoMethod *method)
+{
+       g_error ("remoting not installed");
+       return NULL;
+}
+
+static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
+static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
+
+void
+mono_install_trampoline (MonoTrampoline func) 
+{
+       arch_create_jit_trampoline = func? func: default_trampoline;
+}
+
+void
+mono_install_remoting_trampoline (MonoTrampoline func) 
+{
+       arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
+}
+
+#if 0 && HAVE_BOEHM_GC
+static void
+vtable_finalizer (void *obj, void *data) {
+       g_print ("%s finalized (%p)\n", (char*)data, obj);
+}
+#endif
+
+/**
+ * mono_class_vtable:
+ * @domain: the application domain
+ * @class: the class to initialize
+ *
+ * VTables are domain specific because we create domain specific code, and 
+ * they contain the domain specific static class data.
+ */
+MonoVTable *
+mono_class_vtable (MonoDomain *domain, MonoClass *class)
+{
+       MonoClass *k;
+       MonoVTable *vt;
+       MonoClassField *field;
+       guint32 cindex;
+       guint32 cols [MONO_CONSTANT_SIZE];
+       const char *p;
+       char *t;
+       int i, len;
+
+       g_assert (class);
+
+       /* can interfaces have static fields? */
+       if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
+               g_assert_not_reached ();
+
+       mono_domain_lock (domain);
+       if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
+               mono_domain_unlock (domain);
+               return vt;
+       }
+       
+       if (!class->inited)
+               mono_class_init (class);
+
+//     mono_stats.used_class_count++;
+//     mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+
+       vt = mono_mempool_alloc0 (domain->mp,  sizeof (MonoVTable) + 
+                                 class->vtable_size * sizeof (gpointer));
+       vt->klass = class;
+       vt->domain = domain;
+
+       if (class->class_size) {
+#if HAVE_BOEHM_GC
+               vt->data = GC_malloc (class->class_size + 8);
+               /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
+               /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
+               mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
+#else
+               vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
+               
+#endif
+//             mono_stats.class_static_data_size += class->class_size + 8;
+       }
+
+       for (i = class->field.first; i < class->field.last; ++i) {
+               field = &class->fields [i - class->field.first];
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+                       continue;
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
+                       continue;
+               cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
+               if (!cindex) {
+                       g_warning ("constant for field %s not found", field->name);
+                       continue;
+               }
+               mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
+               p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
+               len = mono_metadata_decode_blob_size (p, &p);
+               t = (char*)vt->data + field->offset;
+               /* should we check that the type matches? */
+               switch (cols [MONO_CONSTANT_TYPE]) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I1:
+                       *t = *p;
+                       break;
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I2: {
+                       guint16 *val = (guint16*)t;
+                       *val = read16 (p);
+                       break;
+               }
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I4: {
+                       guint32 *val = (guint32*)t;
+                       *val = read32 (p);
+                       break;
+               }
+               case MONO_TYPE_U8:
+               case MONO_TYPE_I8: {
+                       guint64 *val = (guint64*)t;
+                       *val = read64 (p);
+                       break;
+               }
+               case MONO_TYPE_R4: {
+                       float *val = (float*)t;
+                       readr4 (p, val);
+                       break;
+               }
+               case MONO_TYPE_R8: {
+                       double *val = (double*)t;
+                       readr8 (p, val);
+                       break;
+               }
+               case MONO_TYPE_STRING: {
+                       //gpointer *val = (gpointer*)t;
+                       //*val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
+                       break;
+               }
+               case MONO_TYPE_CLASS:
+                       /* nothing to do, we malloc0 the data and the value can be 0 only */
+                       break;
+               default:
+                       g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
+               }
+       }
 
+       vt->max_interface_id = class->max_interface_id;
+       
+       vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
+               sizeof (gpointer) * (class->max_interface_id + 1));
+
+       /* initialize interface offsets */
+       for (k = class; k ; k = k->parent) {
+               for (i = 0; i < k->interface_count; i++) {
+                       int slot;
+                       MonoClass *ic = k->interfaces [i];
+                       slot = class->interface_offsets [ic->interface_id];
+                       vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
+               }
+       }
+
+       /* initialize vtable */
+       for (i = 0; i < class->vtable_size; ++i) {
+               MonoMethod *cm;
+              
+               if ((cm = class->vtable [i]))
+                       vt->vtable [i] = arch_create_jit_trampoline (cm);
+       }
+
+       mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
+       mono_domain_unlock (domain);
+
+       mono_runtime_class_init (class);
+
+       return vt;
+}
+
+/**
+ * mono_class_proxy_vtable:
+ * @domain: the application domain
+ * @class: the class to proxy
+ *
+ * Creates a vtable for transparent proxies. It is basically
+ * a copy of the real vtable of @class, but all function pointers invoke
+ * the remoting functions, and vtable->klass points to the 
+ * transparent proxy class, and not to @class.
+ */
+MonoVTable *
+mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
+{
+       MonoVTable *vt, *pvt;
+       int i, vtsize;
+
+       if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
+               return pvt;
+
+       vt = mono_class_vtable (domain, class);
+       vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+
+//     mono_stats.class_vtable_size += vtsize;
+
+       pvt = mono_mempool_alloc (domain->mp, vtsize);
+       memcpy (pvt, vt, vtsize);
+
+       pvt->klass = mono_defaults.transparent_proxy_class;
+
+       /* initialize vtable */
+       for (i = 0; i < class->vtable_size; ++i) {
+               MonoMethod *cm;
+              
+               if ((cm = class->vtable [i]))
+                       pvt->vtable [i] = arch_create_remoting_trampoline (cm);
+       }
+
+       mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
+
+       return pvt;
 }
 
 static MonoInvokeFunc default_mono_runtime_invoke = NULL;
@@ -101,39 +336,40 @@ MonoObject*
 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
 {
        MonoMethodSignature *sig = method->signature;
-       gpointer *pa;
+       gpointer *pa = NULL;
        int i;
+               
+       if (NULL != params) {
+               pa = alloca (sizeof (gpointer) * mono_array_length (params));
+               for (i = 0; i < mono_array_length (params); i++) {
+                       if (sig->params [i]->byref) {
+                               /* nothing to do */
+                       }
 
-       pa = alloca (sizeof (gpointer) * params->bounds->length);
-
-       for (i = 0; i < params->bounds->length; i++) {
-               if (sig->params [i]->byref) {
-                       /* nothing to do */
-               }
-
-               switch (sig->params [i]->type) {
-               case MONO_TYPE_U1:
-               case MONO_TYPE_I1:
-               case MONO_TYPE_BOOLEAN:
-               case MONO_TYPE_U2:
-               case MONO_TYPE_I2:
-               case MONO_TYPE_CHAR:
-               case MONO_TYPE_U:
-               case MONO_TYPE_I:
-               case MONO_TYPE_U4:
-               case MONO_TYPE_I4:
-               case MONO_TYPE_U8:
-               case MONO_TYPE_I8:
-               case MONO_TYPE_VALUETYPE:
-                       pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
-                       break;
-               case MONO_TYPE_STRING:
-               case MONO_TYPE_OBJECT:
-               case MONO_TYPE_CLASS:
-                       pa [i] = (char *)(((gpointer *)params->vector)[i]);
-                       break;
-               default:
-                       g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+                       switch (sig->params [i]->type) {
+                       case MONO_TYPE_U1:
+                       case MONO_TYPE_I1:
+                       case MONO_TYPE_BOOLEAN:
+                       case MONO_TYPE_U2:
+                       case MONO_TYPE_I2:
+                       case MONO_TYPE_CHAR:
+                       case MONO_TYPE_U:
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_U4:
+                       case MONO_TYPE_I4:
+                       case MONO_TYPE_U8:
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_VALUETYPE:
+                               pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
+                               break;
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_CLASS:
+                               pa [i] = (char *)(((gpointer *)params->vector)[i]);
+                               break;
+                       default:
+                               g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+                       }
                }
        }
 
@@ -158,7 +394,8 @@ void *
 mono_object_allocate (size_t size)
 {
 #if HAVE_BOEHM_GC
-       void *o = GC_debug_malloc (size, "object", 1);
+       /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
+       void *o = GC_malloc (size);
 #else
        void *o = calloc (1, size);
 #endif
@@ -195,24 +432,38 @@ mono_object_free (MonoObject *o)
 MonoObject *
 mono_object_new (MonoDomain *domain, MonoClass *klass)
 {
-       static guint32 uoid = 0;
-       MonoObject *o;
+       return mono_object_new_specific (mono_class_vtable (domain, klass));
+}
 
-       if (!klass->inited)
-               mono_class_init (klass);
+/**
+ * mono_object_new_specific:
+ * @vtable: the vtable of the object that we want to create
+ *
+ * Returns: A newly created object with class and domain specified
+ * by @vtable
+ */
+MonoObject *
+mono_object_new_specific (MonoVTable *vtable)
+{
+       MonoObject *o;
 
+       mono_stats.new_object_count++;          /* thread safe? */
 
-       if (klass->ghcimpl) {
-               o = mono_object_allocate (klass->instance_size);
-               o->vtable = mono_class_vtable (domain, klass);
-       } else {
+       /* if the returned pointer is not the same as the address returned by GC_malloc(), 
+        * we need to change also metadata/gc.c to take into account the new offset.
+        */
+       if (vtable->klass->ghcimpl)
+               o = mono_object_allocate (vtable->klass->instance_size);
+       else {
                guint32 *t;
-               t = mono_object_allocate (klass->instance_size + 4);
+               t = mono_object_allocate (vtable->klass->instance_size + 4);
                *t = ++uoid;
                o = (MonoObject *)(++t);
-               o->vtable = mono_class_vtable (domain, klass);
        }
-
+       o->vtable = vtable;
+       if (vtable->klass->has_finalize)
+               mono_object_register_finalizer (o);
+       
        return o;
 }
 
@@ -252,6 +503,8 @@ mono_object_clone (MonoObject *obj)
 
        memcpy (o, obj, size);
 
+       if (obj->vtable->klass->has_finalize)
+               mono_object_register_finalizer (o);
        return o;
 }
 
@@ -268,6 +521,17 @@ mono_array_clone (MonoArray *array)
        int size, i;
        guint32 *sizes;
        MonoClass *klass = array->obj.vtable->klass;
+
+       if (array->bounds == NULL) {
+               size = mono_array_length (array);
+               o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
+                                        klass, &size, NULL);
+
+               size *= mono_array_element_size (klass);
+               memcpy (o, array, sizeof (MonoArray) + size);
+
+               return o;
+       }
        
        sizes = alloca (klass->rank * sizeof(guint32) * 2);
        size = mono_array_element_size (klass);
@@ -297,7 +561,7 @@ MonoArray*
 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
                     guint32 *lengths, guint32 *lower_bounds)
 {
-       guint32 byte_len;
+       guint32 byte_len, len;
        MonoObject *o;
        MonoArray *array;
        MonoArrayBounds *bounds;
@@ -307,20 +571,29 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
                mono_class_init (array_class);
 
        byte_len = mono_array_element_size (array_class);
+       len = 1;
 
-#if HAVE_BOEHM_GC
-       bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
-#else
-       bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
-#endif
-       for (i = 0; i < array_class->rank; ++i) {
-               bounds [i].length = lengths [i];
-               byte_len *= lengths [i];
+       if (array_class->rank == 1 &&
+           (lower_bounds == NULL || lower_bounds [0] == 0)) {
+               bounds = NULL;
+               len = lengths [0];
+       } else {
+       #if HAVE_BOEHM_GC
+               bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
+       #else
+               bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
+       #endif
+               for (i = 0; i < array_class->rank; ++i) {
+                       bounds [i].length = lengths [i];
+                       len *= lengths [i];
+               }
+
+               if (lower_bounds)
+                       for (i = 0; i < array_class->rank; ++i)
+                               bounds [i].lower_bound = lower_bounds [i];
        }
 
-       if (lower_bounds)
-               for (i = 0; i < array_class->rank; ++i)
-                       bounds [i].lower_bound = lower_bounds [i];
+       byte_len *= len;
        /* 
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
@@ -333,7 +606,7 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
        array = (MonoArray*)o;
 
        array->bounds = bounds;
-       array->max_length = bounds [0].length;
+       array->max_length = len;
 
        return array;
 }
@@ -354,7 +627,35 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
        ac = mono_array_class_get (&eclass->byval_arg, 1);
        g_assert (ac != NULL);
 
-       return mono_array_new_full (domain, ac, &n, NULL);
+       return mono_array_new_specific (mono_class_vtable (domain, ac), n);
+}
+
+/*
+ * mono_array_new_specific:
+ * @vtable: a vtable in the appropriate domain for an initialized class
+ * @n: number of array elements
+ *
+ * This routine is a fast alternative to mono_array_new() for code which
+ * can be sure about the domain it operates in.
+ */
+MonoArray *
+mono_array_new_specific (MonoVTable *vtable, guint32 n)
+{
+       MonoObject *o;
+       MonoArray *ao;
+       gsize byte_len;
+
+       byte_len = n * mono_array_element_size (vtable->klass);
+       o = mono_object_allocate (sizeof (MonoArray) + byte_len);
+       if (!o)
+               G_BREAKPOINT ();
+       o->vtable = vtable;
+
+       ao = (MonoArray *)o;
+       ao->bounds = NULL;
+       ao->max_length = n;
+
+       return ao;
 }
 
 /**
@@ -368,18 +669,43 @@ MonoString *
 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
 {
        MonoString *s;
-       MonoArray *ca;
-
-       s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
+       
+       s = mono_string_new_size (domain, len);
        g_assert (s != NULL);
 
-       ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
-       g_assert (ca != NULL);
-       
-       s->c_str = ca;
-       s->length = len;
+       memcpy (mono_string_chars (s), text, len * 2);
 
-       memcpy (ca->vector, text, len * 2);
+       return s;
+}
+
+/**
+ * mono_string_new_size:
+ * @text: a pointer to an utf16 string
+ * @len: the length of the string
+ *
+ * Returns: A newly created string object of @len
+ */
+MonoString *
+mono_string_new_size (MonoDomain *domain, gint32 len)
+{
+       MonoString *s;
+
+       /* 
+        * enable to get a good speedup: we still need to figure out
+        * how the sync structure is freed.
+        */
+#ifdef 0 && HAVE_BOEHM_GC
+       s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
+       s->object.synchronisation = 0;
+       mono_string_chars (s) [len] = 0;
+#else
+       s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+#endif
+       if (!s)
+               G_BREAKPOINT ();
+
+       s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
+       s->length = len;
 
        return s;
 }
@@ -478,6 +804,8 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 
        memcpy ((char *)res + sizeof (MonoObject), value, size);
 
+       if (class->has_finalize)
+               mono_object_register_finalizer (res);
        return res;
 }
 
@@ -510,15 +838,14 @@ mono_object_isinst (MonoObject *obj, MonoClass *klass)
        } else {
                if (oklass == mono_defaults.transparent_proxy_class) {
                        /* fixme: add check for IRemotingTypeInfo */
-                       MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp;
-                       MonoType *type;
-                       type = ((MonoReflectionType *)rp->class_to_proxy)->type;
-                       oklass = mono_class_from_mono_type (type);
+                       oklass = ((MonoTransparentProxy *)obj)->klass;
                }
-               if (oklass->rank && oklass->rank == klass->rank) {
-                       if ((oklass->element_class->baseval - klass->element_class->baseval) <= 
+               if (klass->rank) {
+                       if (oklass->rank == klass->rank && 
+                           (oklass->element_class->baseval - klass->element_class->baseval) <= 
                            klass->element_class->diffval)
                                return obj;
+                       
                } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
                        return obj;
        }
@@ -531,6 +858,7 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
 {
        MonoGHashTable *ldstr_table;
        MonoString *res;
+       MonoDomain *domain;
        char *ins = g_malloc (4 + str->length * 2);
        char *p;
        int bloblen;
@@ -550,7 +878,7 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
        {
                int i;
-               char *p2 = mono_array_addr (str->c_str, char, 0);
+               char *p2 = mono_string_chars (str);
                for (i = 0; i < str->length; ++i) {
                        *p++ = p2 [1];
                        *p++ = p2 [0];
@@ -558,17 +886,22 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
                }
        }
 #else
-       memcpy (p, str->c_str->vector, str->length * 2);
+       memcpy (p, mono_string_chars (str), str->length * 2);
 #endif
-       ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
+       domain = ((MonoObject *)str)->vtable->domain;
+       ldstr_table = domain->ldstr_table;
+       mono_domain_lock (domain);
        if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
+               mono_domain_unlock (domain);
                g_free (ins);
                return res;
        }
        if (insert) {
                mono_g_hash_table_insert (ldstr_table, ins, str);
+               mono_domain_unlock (domain);
                return str;
        }
+       mono_domain_unlock (domain);
        g_free (ins);
        return NULL;
 }
@@ -601,9 +934,12 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
        size_t len2;
                
        sig = str = mono_metadata_user_string (image, idx);
-       
-       if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig)))
+
+       mono_domain_lock (domain);
+       if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
+               mono_domain_unlock (domain);
                return o;
+       }
        
        len2 = mono_metadata_decode_blob_size (str, &str);
        len2 >>= 1;
@@ -620,6 +956,7 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
        }
 #endif
        mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
+       mono_domain_unlock (domain);
 
        return o;
 }
@@ -634,19 +971,15 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
 char *
 mono_string_to_utf8 (MonoString *s)
 {
-       char *as, *vector;
+       char *as;
        GError *error = NULL;
 
        g_assert (s != NULL);
 
-       if (!s->length || !s->c_str)
+       if (!s->length)
                return g_strdup ("");
 
-       vector = (char*)s->c_str->vector;
-
-       g_assert (vector != NULL);
-
-       as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
+       as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
        if (error)
                g_warning (error->message);
 
@@ -673,7 +1006,7 @@ mono_string_to_utf16 (MonoString *s)
        as [(s->length * 2)] = '\0';
        as [(s->length * 2) + 1] = '\0';
 
-       if (!s->length || !s->c_str) {
+       if (!s->length) {
                return (gunichar2 *)(as);
        }
        
@@ -846,7 +1179,6 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
                MonoDomain *domain = mono_domain_get (); 
                MonoMethod *method = msg->method->method;
                MonoMethodSignature *sig = method->signature;
-               MonoObject *res;
                int i, j, outarg_count = 0;
 
                for (i = 0; i < sig->param_count; i++) {