2006-09-27 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / object.c
index 0b96e930c25bd59892e89fe4f72749656f28b075..6f58093055e7cddf8ea4bd7e3f62a1dc0b0374ab 100644 (file)
@@ -32,6 +32,7 @@
 #include <mono/metadata/environment.h>
 #include "mono/metadata/profiler-private.h"
 #include "mono/metadata/security-manager.h"
+#include "mono/metadata/mono-debug-debugger.h"
 #include <mono/os/gc_wrapper.h>
 #include <mono/utils/strenc.h>
 
@@ -172,6 +173,18 @@ mono_type_initialization_init (void)
        InitializeCriticalSection (&ldstr_section);
 }
 
+void
+mono_type_initialization_cleanup (void)
+{
+#if 0
+       /* This is causing race conditions with
+        * mono_release_type_locks
+        */
+       DeleteCriticalSection (&type_initialization_section);
+#endif
+       DeleteCriticalSection (&ldstr_section);
+}
+
 /*
  * mono_runtime_class_init:
  * @vtable: vtable that needs to be initialized
@@ -469,12 +482,17 @@ mono_install_init_vtable (MonoInitVTableFunc func)
 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
 
 static gsize*
-compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set)
+compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
 {
        MonoClassField *field;
        MonoClass *p;
        guint32 pos;
-       int max_size = class->instance_size / sizeof (gpointer);
+       int max_size;
+
+       if (static_fields)
+               max_size = mono_class_data_size (class) / sizeof (gpointer);
+       else
+               max_size = class->instance_size / sizeof (gpointer);
        if (max_size > size) {
                bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
        }
@@ -484,8 +502,13 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                while ((field = mono_class_get_fields (p, &iter))) {
                        MonoType *type;
 
-                       if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
-                               continue;
+                       if (static_fields) {
+                               if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
+                                       continue;
+                       } else {
+                               if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
+                                       continue;
+                       }
                        /* FIXME: should not happen, flag as type load error */
                        if (field->type->byref)
                                break;
@@ -500,6 +523,9 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                        case MONO_TYPE_U:
                        case MONO_TYPE_PTR:
                        case MONO_TYPE_FNPTR:
+#ifdef HAVE_SGEN_GC
+                               break;
+#endif
                        case MONO_TYPE_STRING:
                        case MONO_TYPE_SZARRAY:
                        case MONO_TYPE_CLASS:
@@ -510,11 +536,21 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                                bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
                                *max_set = MAX (*max_set, pos);
                                break;
+                       case MONO_TYPE_GENERICINST:
+                               if (!mono_type_generic_inst_is_valuetype (type)) {
+                                       g_assert ((field->offset % sizeof(gpointer)) == 0);
+
+                                       bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
+                                       *max_set = MAX (*max_set, pos);
+                                       break;
+                               } else {
+                                       /* fall through */
+                               }
                        case MONO_TYPE_VALUETYPE: {
                                MonoClass *fclass = mono_class_from_mono_type (field->type);
                                if (fclass->has_references) {
                                        /* remove the object header */
-                                       compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set);
+                                       compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
                                }
                                break;
                        }
@@ -536,6 +572,8 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                                break;
                        }
                }
+               if (static_fields)
+                       break;
        }
        return bitmap;
 }
@@ -579,11 +617,6 @@ mono_class_compute_gc_descriptor (MonoClass *class)
        class->gc_descr_inited = TRUE;
        class->gc_descr = GC_NO_DESCRIPTOR;
 
-       if (class->generic_class || class->generic_container) {
-               /* bug #75479 */
-               return;
-       }
-
        bitmap = default_bitmap;
        if (class == mono_defaults.string_class) {
                class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
@@ -598,7 +631,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                                class->name_space, class->name);*/
                } else {
                        /* remove the object header */
-                       bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
+                       bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
                        class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
                        /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
                                class->name_space, class->name);*/
@@ -610,7 +643,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                /*static int count = 0;
                if (count++ > 58)
                        return;*/
-               bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
+               bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
 #ifdef HAVE_BOEHM_GC
                /* It seems there are issues when the bitmap doesn't fit: play it safe */
                if (max_set >= 30) {
@@ -693,10 +726,11 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        char *t;
        int i;
        gboolean inited = FALSE;
-       guint32 vtable_size;
+       guint32 vtable_size, class_size;
        guint32 cindex;
        guint32 constant_cols [MONO_CONSTANT_SIZE];
        gpointer iter;
+       gpointer *interface_offsets;
 
        mono_domain_lock (domain);
        runtime_info = class->runtime_info;
@@ -705,17 +739,28 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                return runtime_info->domain_vtables [domain->domain_id];
        }
        if (!class->inited)
-               mono_class_init (class);
+               if (!mono_class_init (class)){
+                       MonoException *exc;
+                       mono_domain_unlock (domain);
+                       exc = mono_class_get_exception_for_failure (class);
+                       g_assert (exc);
+                       mono_raise_exception (exc);
+               }
 
-       mono_class_setup_vtable (class);
+       mono_class_init (class);
 
-       mono_stats.used_class_count++;
-       mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+       /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
+       if (class->image->dynamic)
+               mono_class_setup_vtable (class);
 
-       vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+       vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
+               sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
-       vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
+       mono_stats.used_class_count++;
+       mono_stats.class_vtable_size += vtable_size;
+       interface_offsets = mono_mempool_alloc0 (domain->mp,  vtable_size);
 
+       vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
        vt->klass = class;
        vt->rank = class->rank;
        vt->domain = domain;
@@ -740,13 +785,24 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 #endif
                vt->gc_descr = class->gc_descr;
 
-       if (class->class_size) {
-               if (class->has_static_refs)
-                       vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
-               else
-                       vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
-               mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
-               mono_stats.class_static_data_size += class->class_size;
+       if ((class_size = mono_class_data_size (class))) {
+               if (class->has_static_refs) {
+                       gpointer statics_gc_descr;
+                       int max_set = 0;
+                       gsize default_bitmap [4] = {0};
+                       gsize *bitmap;
+
+                       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);
+                       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)
+                               g_free (bitmap);
+               } else {
+                       vt->data = mono_mempool_alloc0 (domain->mp, class_size);
+               }
+               mono_stats.class_static_data_size += class_size;
        }
 
        cindex = -1;
@@ -800,14 +856,11 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 
        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 (i = 0; i <= class->max_interface_id; ++i) {
                int slot = class->interface_offsets [i];
                if (slot >= 0)
-                       vt->interface_offsets [i] = &(vt->vtable [slot]);
+                       interface_offsets [class->max_interface_id - i] = &(vt->vtable [slot]);
        }
 
        /* 
@@ -817,8 +870,6 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
         * as we change the code in appdomain.c to invalidate vtables by
         * looking at the possible MonoClasses created for the domain.
-        * Or we can reuse static_data_hash, by using vtable as a key
-        * and always inserting into that hash.
         */
        g_hash_table_insert (domain->class_vtable_hash, class, vt);
        /* class->runtime_info is protected by the loader lock, both when
@@ -913,6 +964,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        MonoClass *k;
        GSList *extra_interfaces = NULL;
        MonoClass *class = remote_class->proxy_class;
+       gpointer *interface_offsets;
 
        vt = mono_class_vtable (domain, class);
        max_interface_id = vt->max_interface_id;
@@ -950,12 +1002,14 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
        }
 
-       vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+       vtsize = sizeof (gpointer) * (max_interface_id + 1) +
+               sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
        mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
 
-       pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
-       memcpy (pvt, vt, vtsize);
+       interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
+       pvt = (MonoVTable*)(interface_offsets + max_interface_id + 1);
+       memcpy (pvt, vt, sizeof (MonoVTable) + 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 */
@@ -982,14 +1036,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        }
 
        pvt->max_interface_id = max_interface_id;
-       pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
-                       sizeof (gpointer) * (max_interface_id + 1));
 
        /* initialize interface offsets */
        for (i = 0; i <= class->max_interface_id; ++i) {
                int slot = class->interface_offsets [i];
                if (slot >= 0)
-                       pvt->interface_offsets [i] = &(pvt->vtable [slot]);
+                       interface_offsets [max_interface_id - i] = &(pvt->vtable [slot]);
        }
 
        if (extra_interfaces) {
@@ -1002,7 +1054,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                /* Create trampolines for the methods of the interfaces */
                for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
                        interf = list_item->data;
-                       pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
+                       interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
 
                        iter = NULL;
                        j = 0;
@@ -1094,6 +1146,22 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
        return key;
 }
 
+/**
+ * copy_remote_class_key:
+ *
+ *   Make a copy of KEY in the mempool MP and return the copy.
+ */
+static gpointer*
+copy_remote_class_key (MonoMemPool *mp, gpointer *key)
+{
+       int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
+       gpointer *mp_key = mono_mempool_alloc (mp, key_size);
+
+       memcpy (mp_key, key, key_size);
+
+       return mp_key;
+}
+
 /**
  * mono_remote_class:
  * @domain: the application domain
@@ -1106,12 +1174,12 @@ MonoRemoteClass*
 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
 {
        MonoRemoteClass *rc;
-       gpointer* key;
+       gpointer* key, *mp_key;
        
        key = create_remote_class_key (NULL, proxy_class);
        
        mono_domain_lock (domain);
-       rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
+       rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
 
        if (rc) {
                g_free (key);
@@ -1119,6 +1187,10 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
                return rc;
        }
 
+       mp_key = copy_remote_class_key (domain->mp, key);
+       g_free (key);
+       key = mp_key;
+
        if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
                rc->interface_count = 1;
@@ -1132,9 +1204,9 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        
        rc->default_vtable = NULL;
        rc->xdomain_vtable = NULL;
-       rc->proxy_class_name = mono_string_to_utf8 (class_name);
+       rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
 
-       mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
+       g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
 
        mono_domain_unlock (domain);
        return rc;
@@ -1148,15 +1220,19 @@ static MonoRemoteClass*
 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
 {
        MonoRemoteClass *rc;
-       gpointer* key;
+       gpointer* key, *mp_key;
        
        key = create_remote_class_key (remote_class, extra_class);
-       rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
+       rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
        if (rc != NULL) {
                g_free (key);
                return rc;
        }
 
+       mp_key = copy_remote_class_key (domain->mp, key);
+       g_free (key);
+       key = mp_key;
+
        if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i,j;
                rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
@@ -1185,7 +1261,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
        rc->xdomain_vtable = NULL;
        rc->proxy_class_name = remote_class->proxy_class_name;
 
-       mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
+       g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
 
        return rc;
 }
@@ -1200,8 +1276,16 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
                mono_domain_unlock (domain);
                return remote_class->xdomain_vtable;
        }
-       if (remote_class->default_vtable == NULL)
-               remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
+       if (remote_class->default_vtable == NULL) {
+               MonoType *type;
+               MonoClass *klass;
+               type = ((MonoReflectionType *)rp->class_to_proxy)->type;
+               klass = mono_class_from_mono_type (type);
+               if ((klass->is_com_object || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote)
+                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
+               else
+                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
+       }
        
        mono_domain_unlock (domain);
        return remote_class->default_vtable;
@@ -1408,6 +1492,9 @@ handle_enum:
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
        case MONO_TYPE_ARRAY:
+               mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
+               return;
+       case MONO_TYPE_FNPTR:
        case MONO_TYPE_PTR: {
                gpointer *p = (gpointer*)dest;
                *p = deref_pointer? *(gpointer*)value: value;
@@ -1480,6 +1567,13 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
        set_value (field->type, dest, value, FALSE);
 }
 
+/* Used by the debugger */
+void *
+mono_vtable_get_static_field_data (MonoVTable *vt)
+{
+       return vt->data;
+}
+
 /**
  * mono_field_get_value:
  * @obj: Object instance
@@ -1553,6 +1647,9 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
        case MONO_TYPE_VALUETYPE:
                is_ref = field->type->byref;
                break;
+       case MONO_TYPE_GENERICINST:
+               is_ref = !field->type->data.generic_class->container_class->valuetype;
+               break;
        default:
                g_error ("type 0x%x not handled in "
                         "mono_field_get_value_object", field->type->type);
@@ -1718,10 +1815,17 @@ mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObjec
 
 /*
  * mono_nullable_init:
+ * @buf: The nullable structure to initialize.
+ * @value: the value to initialize from
+ * @klass: the type for the object
+ *
+ * Initialize the nullable structure pointed to by @buf from @value which
+ * should be a boxed value type.   The size of @buf should be able to hold
+ * as much data as the @klass->instance_size (which is the number of bytes
+ * that will be copies).
  *
- *   Initialize the nullable structure pointed to by @buf from @value which
- * should be a boxed value type. Since Nullables have variable structure, we 
- * can't define a C structure for them.
+ * Since Nullables have variable structure, we can not define a C
+ * structure for them.
  */
 void
 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
@@ -1740,8 +1844,10 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
 
 /**
  * mono_nullable_box:
+ * @buf: The buffer representing the data to be boxed
+ * @klass: the type to box it as.
  *
- *   Creates a boxed vtype or NULL from the Nullable structure pointed to by
+ * Creates a boxed vtype or NULL from the Nullable structure pointed to by
  * @buf.
  */
 MonoObject*
@@ -1823,7 +1929,7 @@ mono_runtime_get_main_args (void)
        res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
 
        for (i = 0; i < num_main_args; ++i)
-               mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
+               mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
 
        return res;
 }
@@ -1874,6 +1980,8 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        gchar *utf8_fullpath;
        int result;
 
+       g_assert (method != NULL);
+       
        mono_thread_set_main (mono_thread_current ());
 
        main_args = g_new0 (char*, argc);
@@ -1934,7 +2042,7 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
                         */
                        gchar *str = mono_utf8_from_external (argv [i]);
                        MonoString *arg = mono_string_new (domain, str);
-                       mono_array_set (args, gpointer, i, arg);
+                       mono_array_setref (args, i, arg);
                        g_free (str);
                }
        } else {
@@ -2067,10 +2175,10 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
 
                assembly = method->klass->image->assembly;
                domain->entry_assembly = assembly;
-               domain->setup->application_base = mono_string_new (domain, assembly->basedir);
+               MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
 
                str = g_strconcat (assembly->image->name, ".config", NULL);
-               domain->setup->configuration_file = mono_string_new (domain, str);
+               MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
                g_free (str);
        }
 
@@ -2165,10 +2273,6 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        MonoType *t = sig->params [i];
 
                again:
-                       if (t->byref) {
-                               /* nothing to do */
-                       }
-
                        switch (t->type) {
                        case MONO_TYPE_U1:
                        case MONO_TYPE_I1:
@@ -2186,12 +2290,29 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
                                if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
+                                       if (t->byref)
+                                               /* FIXME: */
+                                               g_assert_not_reached ();
                                        /* The runtime invoke wrapper needs the original boxed vtype */
                                        pa [i] = (char *)(((gpointer *)params->vector)[i]);
                                } else {
                                        /* MS seems to create the objects if a null is passed in */
                                        if (!((gpointer *)params->vector)[i])
                                                ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
+
+                                       if (t->byref) {
+                                               /*
+                                                * We can't pass the unboxed vtype byref to the callee, since
+                                                * that would mean the callee would be able to modify boxed
+                                                * primitive types. So we (and MS) make a copy of the boxed
+                                                * object, pass that to the callee, and replace the original
+                                                * boxed object in the arg array with the copy.
+                                                */
+                                               MonoObject *orig = mono_array_get (params, MonoObject*, i);
+                                               MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
+                                               mono_array_setref (params, i, copy);
+                                       }
+                                               
                                        pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
                                }
                                break;
@@ -2329,7 +2450,8 @@ mono_object_new_specific (MonoVTable *vtable)
 
        MONO_ARCH_SAVE_REGS;
        
-       if (vtable->remote)
+       /* check for is_com_object for COM Interop */
+       if (vtable->remote || vtable->klass->is_com_object)
        {
                gpointer pa [1];
                MonoMethod *im = vtable->domain->create_proxy_for_type_method;
@@ -2921,6 +3043,43 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        return res;
 }
 
+/*
+ * mono_value_copy:
+ * @dest: destination pointer
+ * @src: source pointer
+ * @klass: a valuetype class
+ *
+ * Copy a valuetype from @src to @dest. This function must be used
+ * when @klass contains references fields.
+ */
+void
+mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
+{
+       int size = mono_class_value_size (klass, NULL);
+       mono_gc_wbarrier_value_copy (dest, src, 1, klass);
+       memcpy (dest, src, size);
+}
+
+/*
+ * mono_value_copy_array:
+ * @dest: destination array
+ * @dest_idx: index in the @dest array
+ * @src: source pointer
+ * @count: number of items
+ *
+ * Copy @count valuetype items from @src to @dest. This function must be used
+ * when @klass contains references fields.
+ * Overlap is handled.
+ */
+void
+mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
+{
+       int size = mono_array_element_size (dest->obj.vtable->klass);
+       char *d = mono_array_addr_with_size (dest, size, dest_idx);
+       mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
+       memmove (d, src, size * count);
+}
+
 /**
  * mono_object_get_domain:
  * @obj: object to query
@@ -2954,13 +3113,20 @@ guint
 mono_object_get_size (MonoObject* o)
 {
        MonoClass* klass = mono_object_class (o);
-       
-       if (klass == mono_defaults.string_class)
+       if (klass == mono_defaults.string_class) {
                return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
-       else if (klass->parent == mono_defaults.array_class)
-               return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
-       else
+       } else if (o->vtable->rank) {
+               MonoArray *array = (MonoArray*)o;
+               size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
+               if (array->bounds) {
+                       size += 3;
+                       size &= ~3;
+                       size += sizeof (MonoArrayBounds) * o->vtable->rank;
+               }
+               return size;
+       } else {
                return mono_class_instance_size (klass);
+       }
 }
 
 /**
@@ -3013,11 +3179,13 @@ mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
        vt = obj->vtable;
        
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               if ((klass->interface_id <= vt->max_interface_id) &&
-                   (vt->interface_offsets [klass->interface_id] != 0))
-                       return obj;
-       }
-       else {
+               if (klass->interface_id <= vt->max_interface_id) {
+                       /* the interface_offsets array is stored before the vtable */
+                       gpointer *interface_offsets = (gpointer*)vt;
+                       if (interface_offsets [- (klass->interface_id + 1)] != NULL)
+                               return obj;
+               }
+       } else {
                MonoClass *oklass = vt->klass;
                if ((oklass == mono_defaults.transparent_proxy_class))
                        oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
@@ -3088,6 +3256,24 @@ str_lookup (MonoDomain *domain, gpointer user_data)
        info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
 }
 
+#ifdef HAVE_SGEN_GC
+
+static MonoString*
+mono_string_get_pinned (MonoString *str)
+{
+       int size;
+       MonoString *news;
+       size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
+       news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
+       memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
+       news->length = mono_string_length (str);
+       return news;
+}
+
+#else
+#define mono_string_get_pinned(str) (str)
+#endif
+
 static MonoString*
 mono_string_is_interned_lookup (MonoString *str, int insert)
 {
@@ -3103,6 +3289,7 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
                return res;
        }
        if (insert) {
+               str = mono_string_get_pinned (str);
                mono_g_hash_table_insert (ldstr_table, str, str);
                ldstr_unlock ();
                return str;
@@ -3207,6 +3394,7 @@ mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
                return interned;
        }
 
+       o = mono_string_get_pinned (o);
        mono_g_hash_table_insert (domain->ldstr_table, o, o);
        ldstr_unlock ();
 
@@ -3293,6 +3481,31 @@ mono_string_from_utf16 (gunichar2 *data)
        return mono_string_new_utf16 (domain, data, len);
 }
 
+/**
+ * mono_string_to_utf8_mp:
+ * @s: a System.String
+ *
+ * Same as mono_string_to_utf8, but allocate the string from a mempool.
+ */
+char *
+mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+{
+       char *r = mono_string_to_utf8 (s);
+       char *mp_s;
+       int len;
+
+       if (!r)
+               return NULL;
+
+       len = strlen (r) + 1;
+       mp_s = mono_mempool_alloc (mp, len);
+       memcpy (mp_s, r, len);
+
+       g_free (r);
+
+       return mp_s;
+}
+
 static void
 default_ex_handler (MonoException *ex)
 {
@@ -3333,7 +3546,7 @@ mono_raise_exception (MonoException *ex)
         */
 
        if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
-               mono_thread_current ()->abort_exc = ex;
+               MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
        
        ex_handler (ex);
 }
@@ -3369,21 +3582,22 @@ mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
  *
  */
 MonoAsyncResult *
-mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
+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 ();
 
        /* we must capture the execution context from the original thread */
        if (method) {
-               res->execution_context = mono_runtime_invoke (method, NULL, NULL, NULL);
+               MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
                /* note: result may be null if the flow is suppressed */
        }
 
        res->data = data;
-       res->async_state = state;
+       MONO_OBJECT_SETREF (res, object_data, object_data);
+       MONO_OBJECT_SETREF (res, async_state, state);
        if (handle != NULL)
-               res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
+               MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
 
        res->sync_completed = FALSE;
        res->completed = FALSE;
@@ -3403,20 +3617,20 @@ mono_message_init (MonoDomain *domain,
        char **names;
        guint8 arg_type;
 
-       this->method = method;
+       MONO_OBJECT_SETREF (this, method, method);
 
-       this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
-       this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
+       MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
+       MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
        this->async_result = NULL;
        this->call_type = CallType_Sync;
 
        names = g_new (char *, sig->param_count);
        mono_method_get_param_names (method->method, (const char **) names);
-       this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
+       MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
        
        for (i = 0; i < sig->param_count; i++) {
                 name = mono_string_new (domain, names [i]);
-                mono_array_set (this->names, gpointer, i, name);       
+                mono_array_setref (this->names, i, name);      
        }
 
        g_free (names);
@@ -3424,8 +3638,8 @@ mono_message_init (MonoDomain *domain,
 
                if (sig->params [i]->byref) {
                        if (out_args) {
-                               gpointer arg = mono_array_get (out_args, gpointer, j);
-                               mono_array_set (this->args, gpointer, i, arg);
+                               MonoObject* arg = mono_array_get (out_args, gpointer, j);
+                               mono_array_setref (this->args, i, arg);
                                j++;
                        }
                        arg_type = 2;
@@ -3506,6 +3720,7 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
                        outarg_count++;
        }
 
+       /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
        *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
        *exc = NULL;
 
@@ -3513,9 +3728,9 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
 
        for (i = 0, j = 0; i < sig->param_count; i++) {
                if (sig->params [i]->byref) {
-                       gpointer arg;
+                       MonoObject* arg;
                        arg = mono_array_get (msg->args, gpointer, i);
-                       mono_array_set (*out_args, gpointer, j, arg);
+                       mono_array_setref (*out_args, j, arg);
                        j++;
                }
        }
@@ -3591,18 +3806,18 @@ mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
 
        if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
                method = ji->method;
-               delegate->method_info = mono_method_get_object (domain, method, NULL);
+               MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, method, NULL));
        }
 
        if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
                g_assert (method);
                method = mono_marshal_get_remoting_invoke (method);
                delegate->method_ptr = mono_compile_method (method);
-               delegate->target = target;
+               MONO_OBJECT_SETREF (delegate, target, target);
        } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
                method = mono_marshal_get_unbox_wrapper (method);
                delegate->method_ptr = mono_compile_method (method);
-               delegate->target = target;
+               MONO_OBJECT_SETREF (delegate, target, target);
        } else {
                if (method) {
                        /* 
@@ -3613,7 +3828,7 @@ mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
                        addr = arch_create_delegate_trampoline (method, addr);
                }
                delegate->method_ptr = addr;
-               delegate->target = target;
+               MONO_OBJECT_SETREF (delegate, target, target);
        }
 }
 
@@ -3664,7 +3879,7 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *
                else 
                        arg = *((MonoObject **)vpos);
                      
-               mono_array_set (msg->args, gpointer, i, arg);
+               mono_array_setref (msg->args, i, arg);
        }
 
        if (cb != NULL && state != NULL) {
@@ -3721,8 +3936,14 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE: {
-                               size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
-                               memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
+                               if (arg) {
+                                       size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
+                                       memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
+                               }
+                               else {
+                                       size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
+                                       memset (*((gpointer *)params [i]), 0, size);
+                               }
                                break;
                        }
                        case MONO_TYPE_STRING:
@@ -3765,12 +3986,10 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
        MonoMethodMessage *msg;
        MonoArray *out_args;
        MonoObject *exc;
-       gpointer tmp;
+       char* full_name;
 
        g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
-
-       if (!res)
-               res = &tmp;
+       g_assert (res != NULL);
 
        if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
                mono_field_get_value (tp->rp->unwrapped_server, field, res);
@@ -3788,8 +4007,10 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
        out_args = mono_array_new (domain, mono_defaults.object_class, 1);
        mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
 
-       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
-       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+       full_name = mono_type_get_full_name (klass);
+       mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 
@@ -3798,7 +4019,7 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
        if (mono_array_length (out_args) == 0)
                return NULL;
 
-       *res = mono_array_get (out_args, MonoObject *, 0);
+       *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
 
        if (field_class->valuetype) {
                return ((char *)*res) + sizeof (MonoObject);
@@ -3824,6 +4045,7 @@ mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *
        MonoMethodMessage *msg;
        MonoArray *out_args;
        MonoObject *exc, *res;
+       char* full_name;
 
        g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
 
@@ -3851,8 +4073,10 @@ mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *
 
        mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
 
-       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
-       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+       full_name = mono_type_get_full_name (klass);
+       mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 
@@ -3888,6 +4112,7 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
        MonoArray *out_args;
        MonoObject *exc;
        MonoObject *arg;
+       char* full_name;
 
        g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
 
@@ -3913,9 +4138,11 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
        msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
        mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
 
-       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
-       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
-       mono_array_set (msg->args, gpointer, 2, arg);
+       full_name = mono_type_get_full_name (klass);
+       mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 2, arg);
+       g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 
@@ -3941,6 +4168,7 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
        MonoMethodMessage *msg;
        MonoArray *out_args;
        MonoObject *exc;
+       char* full_name;
 
        g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
 
@@ -3960,9 +4188,11 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
        msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
        mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
 
-       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
-       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
-       mono_array_set (msg->args, gpointer, 2, arg);
+       full_name = mono_type_get_full_name (klass);
+       mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 2, arg);
+       g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);