2009-09-10 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / metadata / object.c
index 2d2c51c675664ca401537a4af0f67b8c314fea03..e0b30b70ed1d84e4bd24401ba2a4d4d233b03dc6 100644 (file)
@@ -40,6 +40,7 @@
 #include <mono/metadata/gc-internal.h>
 #include <mono/utils/strenc.h>
 #include <mono/utils/mono-counters.h>
+#include "cominterop.h"
 
 #ifdef HAVE_BOEHM_GC
 #define NEED_TO_ZERO_PTRFREE 1
@@ -141,6 +142,9 @@ static GHashTable *blocked_thread_hash;
 /* Main thread */
 static MonoThread *main_thread;
 
+/* Functions supplied by the runtime */
+static MonoRuntimeCallbacks callbacks;
+
 /**
  * mono_thread_set_main:
  * @thread: thread to set as the main thread
@@ -473,6 +477,18 @@ static MonoImtThunkBuilder imt_thunk_builder = NULL;
 #error "MONO_IMT_SIZE cannot be larger than 32"
 #endif
 
+void
+mono_install_callbacks (MonoRuntimeCallbacks *cbs)
+{
+       memcpy (&callbacks, cbs, sizeof (*cbs));
+}
+
+MonoRuntimeCallbacks*
+mono_get_runtime_callbacks (void)
+{
+       return &callbacks;
+}
+
 void
 mono_install_trampoline (MonoTrampoline func) 
 {
@@ -628,6 +644,10 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                        if (field->type->byref)
                                break;
 
+                       if (static_fields && field->offset == -1)
+                               /* special static */
+                               continue;
+
                        pos = field->offset / sizeof (gpointer);
                        pos += offset;
 
@@ -845,7 +865,7 @@ mono_string_alloc (int length)
        return mono_string_new_size (mono_domain_get (), length);
 }
 
-static void
+void
 mono_class_compute_gc_descriptor (MonoClass *class)
 {
        int max_set = 0;
@@ -1323,7 +1343,7 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                MonoImtBuilderEntry* entry = imt_builder [i];
                while (entry != NULL) {
                        MonoImtBuilderEntry* next = entry->next;
-                       free (entry);
+                       g_free (entry);
                        entry = next;
                }
        }
@@ -1574,6 +1594,9 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtab
        static int num_added = 0;
 
        GenericVirtualCase *gvc, *list;
+       MonoImtBuilderEntry *entries;
+       int i;
+       GPtrArray *sorted;
 
        mono_domain_lock (domain);
        if (!domain->generic_virtual_cases)
@@ -1608,11 +1631,27 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtab
        if (++gvc->count == THUNK_THRESHOLD) {
                gpointer *old_thunk = *vtable_slot;
 
-               /* Force the rebuild of the thunk at the next call */
                if ((gpointer)vtable_slot < (gpointer)vtable)
+                       /* Force the rebuild of the thunk at the next call */
                        *vtable_slot = imt_trampoline;
-               else
-                       *vtable_slot = vtable_trampoline;
+               else {
+                       entries = get_generic_virtual_entries (domain, vtable_slot);
+
+                       sorted = imt_sort_slot_entries (entries);
+
+                       *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
+                                                                                         vtable_trampoline);
+
+                       while (entries) {
+                               MonoImtBuilderEntry *next = entries->next;
+                               g_free (entries);
+                               entries = next;
+                       }
+
+                       for (i = 0; i < sorted->len; ++i)
+                               g_free (g_ptr_array_index (sorted, i));
+                       g_ptr_array_free (sorted, TRUE);
+               }
 
                if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
                        invalidate_generic_virtual_thunk (domain, old_thunk);
@@ -1718,7 +1757,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        }
 
        if (ARCH_USE_IMT) {
-               vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+               vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
                if (class->interface_offsets_count) {
                        imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
                        vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
@@ -1727,7 +1766,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                }
        } else {
                vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.used_class_count++;
@@ -1771,7 +1810,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 
                        bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
                        /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
-                       statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
+                       statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
                        vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
                        mono_domain_add_class_static_data (domain, class, vt->data, NULL);
                        if (bitmap != default_bitmap)
@@ -1799,6 +1838,11 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                                if (!domain->special_static_fields)
                                        domain->special_static_fields = g_hash_table_new (NULL, NULL);
                                g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
+                               /* 
+                                * This marks the field as special static to speed up the
+                                * checks in mono_field_static_get/set_value ().
+                                */
+                               field->offset = -1;
                                continue;
                        }
                }
@@ -1864,7 +1908,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                /* this is a bounded memory retention issue: may want to 
                 * handle it differently when we'll have a rcu-like system.
                 */
-               runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+               runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
                runtime_info->max_domain = new_size - 1;
                /* copy the stuff from the older info */
                if (old_info) {
@@ -1888,13 +1932,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                for (i = 0; i < class->vtable_size; ++i) {
                        MonoMethod *cm;
 
-                       if ((cm = class->vtable [i])) {
-                               if (mono_method_signature (cm)->generic_param_count)
-                                       /* FIXME: Why is this needed ? */
-                                       vt->vtable [i] = cm;
-                               else
-                                       vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
-                       }
+                       if ((cm = class->vtable [i]))
+                               vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
                }
        }
 
@@ -1992,10 +2031,10 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                mono_stats.imt_number_of_tables++;
                mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
                vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        } else {
                vtsize = sizeof (gpointer) * (max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
@@ -2005,7 +2044,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
        else
                pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
-       memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
+       memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
 
        pvt->klass = mono_defaults.transparent_proxy_class;
        /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
@@ -2225,12 +2264,12 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        key = mp_key;
 
        if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
                rc->interface_count = 1;
                rc->interfaces [0] = proxy_class;
                rc->proxy_class = mono_defaults.marshalbyrefobject_class;
        } else {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
                rc->interface_count = 0;
                rc->proxy_class = proxy_class;
        }
@@ -2269,7 +2308,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 
        if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i,j;
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
                rc->proxy_class = remote_class->proxy_class;
                rc->interface_count = remote_class->interface_count + 1;
                
@@ -2284,7 +2323,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
                        rc->interfaces [j] = extra_class;
        } else {
                // Replace the old class. The interface array is the same
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
                rc->proxy_class = extra_class;
                rc->interface_count = remote_class->interface_count;
                if (rc->interface_count > 0)
@@ -2431,8 +2470,14 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
                /* generic methods demand invoke_with_check */
                if (mono_method_signature (res)->generic_param_count)
                        res = mono_marshal_get_remoting_invoke_with_check (res);
-               else
-                       res = mono_marshal_get_remoting_invoke (res);
+               else {
+#ifndef DISABLE_COM
+                       if (klass == mono_defaults.com_object_class || klass->is_com_object)
+                               res = mono_cominterop_get_invoke (res);
+                       else
+#endif
+                               res = mono_marshal_get_remoting_invoke (res);
+               }
        } else {
                if (method->is_inflated) {
                        /* Have to inflate the result */
@@ -2559,6 +2604,8 @@ set_value (MonoType *type, void *dest, void *value, int deref_pointer)
 {
        int t;
        if (type->byref) {
+               /* object fields cannot be byref, so we don't need a
+                  wbarrier here */
                gpointer *p = (gpointer*)dest;
                *p = value;
                return;
@@ -2629,12 +2676,14 @@ handle_enum:
                        t = mono_class_enum_basetype (type->data.klass)->type;
                        goto handle_enum;
                } else {
-                       int size;
-                       size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
-                       if (value == NULL)
+                       MonoClass *class = mono_class_from_mono_type (type);
+                       int size = mono_class_value_size (class, NULL);
+                       if (value == NULL) {
                                memset (dest, 0, size);
-                       else
+                       } else {
                                memcpy (dest, value, size);
+                               mono_gc_wbarrier_value_copy (dest, value, size, class);
+                       }
                }
                return;
        case MONO_TYPE_GENERICINST:
@@ -2687,8 +2736,14 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
        g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
        /* you cant set a constant! */
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
-       
-       dest = (char*)vt->data + field->offset;
+
+       if (field->offset == -1) {
+               /* Special static */
+               gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+               dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+       } else {
+               dest = (char*)vt->data + field->offset;
+       }
        set_value (field->type, dest, value, FALSE);
 }
 
@@ -2893,7 +2948,13 @@ mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
                return;
        }
 
-       src = (char*)vt->data + field->offset;
+       if (field->offset == -1) {
+               /* Special static */
+               gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+               src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+       } else {
+               src = (char*)vt->data + field->offset;
+       }
        set_value (field->type, value, src, TRUE);
 }
 
@@ -3546,8 +3607,21 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                                else
                                        t = &t->data.generic_class->container_class->byval_arg;
                                goto again;
+                       case MONO_TYPE_PTR: {
+                               MonoObject *arg;
+
+                               /* The argument should be an IntPtr */
+                               arg = mono_array_get (params, MonoObject*, i);
+                               if (arg == NULL) {
+                                       pa [i] = NULL;
+                               } else {
+                                       g_assert (arg->vtable->klass == mono_defaults.int_class);
+                                       pa [i] = ((MonoIntPtr*)arg)->m_value;
+                               }
+                               break;
+                       }
                        default:
-                               g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+                               g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
                        }
                }
        }
@@ -3594,6 +3668,27 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                /* obj must be already unboxed if needed */
                res = mono_runtime_invoke (method, obj, pa, exc);
 
+               if (sig->ret->type == MONO_TYPE_PTR) {
+                       MonoClass *pointer_class;
+                       static MonoMethod *box_method;
+                       void *box_args [2];
+                       MonoObject *box_exc;
+
+                       /* 
+                        * The runtime-invoke wrapper returns a boxed IntPtr, need to 
+                        * convert it to a Pointer object.
+                        */
+                       pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+                       if (!box_method)
+                               box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
+
+                       g_assert (res->vtable->klass == mono_defaults.int_class);
+                       box_args [0] = ((MonoIntPtr*)res)->m_value;
+                       box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
+                       res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
+                       g_assert (!box_exc);
+               }
+
                if (has_byref_nullables) {
                        /* 
                         * The runtime invoke wrapper already converted byref nullables back,
@@ -4907,8 +5002,11 @@ mono_raise_exception (MonoException *ex)
         * will point into the next function in the executable, not this one.
         */
 
-       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
-               MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
+       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
+               MonoThread *thread = mono_thread_current ();
+               g_assert (ex->object.vtable->domain == mono_domain_get ());
+               MONO_OBJECT_SETREF (thread, abort_exc, ex);
+       }
        
        ex_handler (ex);
 }
@@ -4961,6 +5059,26 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle)
        }
 }
 
+
+static MonoObject*
+mono_runtime_capture_context (MonoDomain *domain)
+{
+       RuntimeInvokeFunction runtime_invoke;
+
+       if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
+               MonoMethod *method = mono_get_context_capture_method ();
+               MonoMethod *wrapper;
+               if (!method)
+                       return NULL;
+               wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
+               domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
+               domain->capture_context_method = mono_compile_method (method);
+       }
+
+       runtime_invoke = domain->capture_context_runtime_invoke;
+
+       return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+}
 /**
  * mono_async_result_new:
  * @domain:domain where the object will be created.
@@ -4976,11 +5094,10 @@ MonoAsyncResult *
 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
 {
        MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
-       MonoMethod *method = mono_get_context_capture_method ();
-
+       MonoObject *context = mono_runtime_capture_context (domain);
        /* we must capture the execution context from the original thread */
-       if (method) {
-               MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
+       if (context) {
+               MONO_OBJECT_SETREF (res, execution_context, context);
                /* note: result may be null if the flow is suppressed */
        }
 
@@ -5647,49 +5764,24 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
  * mono_create_ftnptr:
  *
  *   Given a function address, create a function descriptor for it.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
 {
-#ifdef __ia64__
-       gpointer *desc;
-
-       desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
-
-       desc [0] = addr;
-       desc [1] = NULL;
-
-       return desc;
-#elif defined(__ppc64__) || defined(__powerpc64__)
-       gpointer *desc;
-
-       desc = mono_domain_code_reserve (domain, 3 * sizeof (gpointer));
-
-       desc [0] = addr;
-       desc [1] = NULL;
-       desc [2] = NULL;
-
-       return desc;
-#else
-       return addr;
-#endif
+       return callbacks.create_ftnptr (domain, addr);
 }
 
 /*
  * mono_get_addr_from_ftnptr:
  *
  *   Given a pointer to a function descriptor, return the function address.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_get_addr_from_ftnptr (gpointer descr)
 {
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
-       return *(gpointer*)descr;
-#else
-       return descr;
-#endif
+       return callbacks.get_addr_from_ftnptr (descr);
 }      
 
 #if 0