2006-09-27 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / object.c
index 754b8a488c9d4291208f991d5e1f1d8f880f2648..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>
 
@@ -79,6 +80,10 @@ get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
 static MonoString*
 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
 
+#define ldstr_lock() EnterCriticalSection (&ldstr_section)
+#define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
+static CRITICAL_SECTION ldstr_section;
+
 void
 mono_runtime_object_init (MonoObject *this)
 {
@@ -125,6 +130,8 @@ typedef struct
 } TypeInitializationLock;
 
 /* for locking access to type_initialization_hash and blocked_thread_hash */
+#define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
+#define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
 static CRITICAL_SECTION type_initialization_section;
 
 /* from vtable to lock */
@@ -163,6 +170,19 @@ mono_type_initialization_init (void)
        InitializeCriticalSection (&type_initialization_section);
        type_initialization_hash = g_hash_table_new (NULL, NULL);
        blocked_thread_hash = g_hash_table_new (NULL, NULL);
+       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);
 }
 
 /*
@@ -197,10 +217,10 @@ mono_runtime_class_init (MonoVTable *vtable)
                int do_initialization = 0;
                MonoDomain *last_domain = NULL;
 
-               EnterCriticalSection (&type_initialization_section);
+               mono_type_initialization_lock ();
                /* double check... */
                if (vtable->initialized) {
-                       LeaveCriticalSection (&type_initialization_section);
+                       mono_type_initialization_unlock ();
                        return;
                }
                lock = g_hash_table_lookup (type_initialization_hash, vtable);
@@ -211,7 +231,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                                last_domain = mono_domain_get ();
                                if (!mono_domain_set (domain, FALSE)) {
                                        vtable->initialized = 1;
-                                       LeaveCriticalSection (&type_initialization_section);
+                                       mono_type_initialization_unlock ();
                                        mono_raise_exception (mono_get_exception_appdomain_unloaded ());
                                }
                        }
@@ -229,7 +249,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                        TypeInitializationLock *pending_lock;
 
                        if (lock->initializing_tid == tid || lock->done) {
-                               LeaveCriticalSection (&type_initialization_section);
+                               mono_type_initialization_unlock ();
                                return;
                        }
                        /* see if the thread doing the initialization is already blocked on this thread */
@@ -237,7 +257,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                        while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
                                if (pending_lock->initializing_tid == tid) {
                                        if (!pending_lock->done) {
-                                               LeaveCriticalSection (&type_initialization_section);
+                                               mono_type_initialization_unlock ();
                                                return;
                                        } else {
                                                /* the thread doing the initialization is blocked on this thread,
@@ -252,7 +272,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                        /* record the fact that we are waiting on the initializing thread */
                        g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
                }
-               LeaveCriticalSection (&type_initialization_section);
+               mono_type_initialization_unlock ();
 
                if (do_initialization) {
                        mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
@@ -266,7 +286,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                        LeaveCriticalSection (&lock->initialization_section);
                }
 
-               EnterCriticalSection (&type_initialization_section);
+               mono_type_initialization_lock ();
                if (lock->initializing_tid != tid)
                        g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
                --lock->waiting_count;
@@ -277,7 +297,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                }
                vtable->initialized = 1;
                /* FIXME: if the cctor fails, the type must be marked as unusable */
-               LeaveCriticalSection (&type_initialization_section);
+               mono_type_initialization_unlock ();
        } else {
                vtable->initialized = 1;
                return;
@@ -320,9 +340,9 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
 void
 mono_release_type_locks (MonoThread *thread)
 {
-       EnterCriticalSection (&type_initialization_section);
-       g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
-       LeaveCriticalSection (&type_initialization_section);
+       mono_type_initialization_lock ();
+       g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
+       mono_type_initialization_unlock ();
 }
 
 static gpointer
@@ -338,8 +358,16 @@ default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
        return NULL;
 }
 
+static gpointer
+default_delegate_trampoline (MonoMethod *method, gpointer addr)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
+static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
 
 void
 mono_install_trampoline (MonoTrampoline func) 
@@ -353,6 +381,12 @@ mono_install_remoting_trampoline (MonoRemotingTrampoline func)
        arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
 }
 
+void
+mono_install_delegate_trampoline (MonoDelegateTrampoline func) 
+{
+       arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
+}
+
 static MonoCompileFunc default_mono_compile_method = NULL;
 
 /**
@@ -448,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));
        }
@@ -463,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;
@@ -479,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:
@@ -489,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 = field->type->data.klass;
+                               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;
                        }
@@ -515,6 +572,8 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                                break;
                        }
                }
+               if (static_fields)
+                       break;
        }
        return bitmap;
 }
@@ -572,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);*/
@@ -584,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) {
@@ -667,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;
@@ -679,15 +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_stats.used_class_count++;
-       mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+       mono_class_init (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 (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;
@@ -712,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;
@@ -729,7 +813,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                if (mono_field_is_deleted (field))
                        continue;
                if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
-                       gint32 special_static = field_is_special_static (class, field);
+                       gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
                        if (special_static != SPECIAL_STATIC_NONE) {
                                guint32 size, offset;
                                int align;
@@ -749,7 +833,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                                memcpy (t, field->data, mono_class_value_size (fklass, NULL));
                        } else {
                                /* it's a pointer type: add check */
-                               g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
+                               g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
                                *t = *(char *)field->data;
                        }
                        continue;
@@ -772,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]);
        }
 
        /* 
@@ -789,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
@@ -883,32 +962,54 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        MonoVTable *vt, *pvt;
        int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
        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;
-
+       
        /* Calculate vtable space for extra interfaces */
        for (j = 0; j < remote_class->interface_count; j++) {
                MonoClass* iclass = remote_class->interfaces[j];
-               int method_count = mono_class_num_methods (iclass);
-       
-               if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
-                       continue;       /* interface implemented by the class */
+               GPtrArray *ifaces;
+               int method_count;
 
-               for (i = 0; i < iclass->interface_count; i++)
-                       method_count += mono_class_num_methods (iclass->interfaces[i]);
+               if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1) 
+                       continue;       /* interface implemented by the class */
+               if (g_slist_find (extra_interfaces, iclass))
+                       continue;
+                       
+               extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
+               
+               method_count = mono_class_num_methods (iclass);
+       
+               ifaces = mono_class_get_implemented_interfaces (iclass);
+               if (ifaces) {
+                       for (i = 0; i < ifaces->len; ++i) {
+                               MonoClass *ic = g_ptr_array_index (ifaces, i);
+                               if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1) 
+                                       continue;       /* interface implemented by the class */
+                               if (g_slist_find (extra_interfaces, ic))
+                                       continue;
+                               extra_interfaces = g_slist_prepend (extra_interfaces, ic);
+                               method_count += mono_class_num_methods (ic);
+                       }
+                       g_ptr_array_free (ifaces, TRUE);
+               }
 
                extra_interface_vtsize += method_count * sizeof (gpointer);
                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 */
@@ -935,54 +1036,132 @@ 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 (remote_class->interface_count > 0)
-       {
+       if (extra_interfaces) {
                int slot = class->vtable_size;
                MonoClass* interf;
-               MonoClass* iclass;
-               int n;
+               gpointer iter;
+               MonoMethod* cm;
+               GSList *list_item;
 
                /* Create trampolines for the methods of the interfaces */
-               for (n = 0; n < remote_class->interface_count; n++) 
-               {
-                       iclass = remote_class->interfaces[n];
-                       if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
-                               continue;       /* interface implemented by the class */
-               
-                       i = -1;
-                       interf = iclass;
-                       do {
-                               MonoMethod* cm;
-                               gpointer iter;
-                               
-                               pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
-       
-                               iter = NULL;
-                               j = 0;
-                               while ((cm = mono_class_get_methods (interf, &iter)))
-                                       pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
-                               
-                               slot += mono_class_num_methods (interf);
-                               if (++i < iclass->interface_count) interf = iclass->interfaces[i];
-                               else interf = NULL;
-                               
-                       } while (interf);
+               for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
+                       interf = list_item->data;
+                       interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
+
+                       iter = NULL;
+                       j = 0;
+                       while ((cm = mono_class_get_methods (interf, &iter)))
+                               pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
+                       
+                       slot += mono_class_num_methods (interf);
                }
+               g_slist_free (extra_interfaces);
        }
 
        return pvt;
 }
 
+/**
+ * mono_class_has_special_static_fields:
+ * 
+ *   Returns whenever @klass has any thread/context static fields.
+ */
+gboolean
+mono_class_has_special_static_fields (MonoClass *klass)
+{
+       MonoClassField *field;
+       gpointer iter;
+
+       iter = NULL;
+       while ((field = mono_class_get_fields (klass, &iter))) {
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
+                       continue;
+               if (mono_field_is_deleted (field))
+                       continue;
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
+                       if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
+                               return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+/**
+ * create_remote_class_key:
+ * Creates an array of pointers that can be used as a hash key for a remote class.
+ * The first element of the array is the number of pointers.
+ */
+static gpointer*
+create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
+{
+       gpointer *key;
+       int i, j;
+       
+       if (remote_class == NULL) {
+               if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+                       key = g_malloc (sizeof(gpointer) * 3);
+                       key [0] = GINT_TO_POINTER (2);
+                       key [1] = mono_defaults.marshalbyrefobject_class;
+                       key [2] = extra_class;
+               } else {
+                       key = g_malloc (sizeof(gpointer) * 2);
+                       key [0] = GINT_TO_POINTER (1);
+                       key [1] = extra_class;
+               }
+       } else {
+               if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+                       key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
+                       key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
+                       key [1] = remote_class->proxy_class;
+
+                       // Keep the list of interfaces sorted
+                       for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
+                               if (extra_class && remote_class->interfaces [i] > extra_class) {
+                                       key [j++] = extra_class;
+                                       extra_class = NULL;
+                               }
+                               key [j] = remote_class->interfaces [i];
+                       }
+                       if (extra_class)
+                               key [j] = extra_class;
+               } else {
+                       // Replace the old class. The interface list is the same
+                       key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
+                       key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
+                       key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
+                       for (i = 0; i < remote_class->interface_count; i++)
+                               key [2 + i] = remote_class->interfaces [i];
+               }
+       }
+       
+       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
@@ -995,113 +1174,165 @@ MonoRemoteClass*
 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
 {
        MonoRemoteClass *rc;
-
+       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, class_name);
+       rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
 
        if (rc) {
+               g_free (key);
                mono_domain_unlock (domain);
                return rc;
        }
 
-       rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
+       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;
+               rc->interfaces [0] = proxy_class;
+               rc->proxy_class = mono_defaults.marshalbyrefobject_class;
+       } else {
+               rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
+               rc->interface_count = 0;
+               rc->proxy_class = proxy_class;
+       }
+       
        rc->default_vtable = NULL;
        rc->xdomain_vtable = NULL;
-       rc->interface_count = 0;
-       rc->interfaces = NULL;
-       rc->proxy_class = mono_defaults.marshalbyrefobject_class;
-       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, class_name, rc);
-       mono_upgrade_remote_class (domain, rc, proxy_class);
+       g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
 
        mono_domain_unlock (domain);
-
        return rc;
 }
 
-static void
-extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
+/**
+ * clone_remote_class:
+ * Creates a copy of the remote_class, adding the provided class or interface
+ */
+static MonoRemoteClass*
+clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
 {
-       /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
+       MonoRemoteClass *rc;
+       gpointer* key, *mp_key;
+       
+       key = create_remote_class_key (remote_class, extra_class);
+       rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
+       if (rc != NULL) {
+               g_free (key);
+               return rc;
+       }
 
-       int current_size = ((remote_class->interface_count / 5) + 1) * 5;
-       remote_class->interface_count += amount;
+       mp_key = copy_remote_class_key (domain->mp, key);
+       g_free (key);
+       key = mp_key;
 
-       if (remote_class->interface_count > current_size || remote_class->interfaces == NULL) 
-       {
-               int new_size = ((remote_class->interface_count / 5) + 1) * 5;
-               MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
-       
-               if (remote_class->interfaces != NULL)
-                       memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
+       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));
+               rc->proxy_class = remote_class->proxy_class;
+               rc->interface_count = remote_class->interface_count + 1;
                
-               remote_class->interfaces = new_array;
+               // Keep the list of interfaces sorted, since the hash key of
+               // the remote class depends on this
+               for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
+                       if (remote_class->interfaces [i] > extra_class && i == j)
+                               rc->interfaces [j++] = extra_class;
+                       rc->interfaces [j] = remote_class->interfaces [i];
+               }
+               if (i == j)
+                       rc->interfaces [j] = extra_class;
+       } else {
+               // Replace the old class. The interface array is the same
+               rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+               rc->proxy_class = extra_class;
+               rc->interface_count = remote_class->interface_count;
+               if (rc->interface_count > 0)
+                       memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
        }
+       
+       rc->default_vtable = NULL;
+       rc->xdomain_vtable = NULL;
+       rc->proxy_class_name = remote_class->proxy_class_name;
+
+       g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
+
+       return rc;
 }
 
 gpointer
 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
 {
+       mono_domain_lock (domain);
        if (rp->target_domain_id != -1) {
                if (remote_class->xdomain_vtable == NULL)
                        remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
+               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;
 }
 
-
 /**
  * mono_upgrade_remote_class:
  * @domain: the application domain
- * @remote_class: the remote class
+ * @tproxy: the proxy whose remote class has to be upgraded.
  * @klass: class to which the remote class can be casted.
  *
  * Updates the vtable of the remote class by adding the necessary method slots
  * and interface offsets so it can be safely casted to klass. klass can be a
  * class or an interface.
  */
-void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
+void
+mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
 {
+       MonoTransparentProxy *tproxy;
+       MonoRemoteClass *remote_class;
        gboolean redo_vtable;
 
        mono_domain_lock (domain);
 
+       tproxy = (MonoTransparentProxy*) proxy_object;
+       remote_class = tproxy->remote_class;
+       
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i;
                redo_vtable = TRUE;
-               for (i = 0; i < remote_class->interface_count; i++)
-                       if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
-                               
-               if (redo_vtable) {
-                       extend_interface_array (domain, remote_class, 1);
-                       remote_class->interfaces [remote_class->interface_count-1] = klass;
-               }
+               for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
+                       if (remote_class->interfaces [i] == klass)
+                               redo_vtable = FALSE;
        }
        else {
                redo_vtable = (remote_class->proxy_class != klass);
-               remote_class->proxy_class = klass;
        }
 
        if (redo_vtable) {
-               remote_class->default_vtable = NULL;
-               remote_class->xdomain_vtable = NULL;
+               tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
+               proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
        }
-/*
-       int n;
-       printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
        
-       for (n=0; n<remote_class->interface_count; n++)
-               printf ("  I:%s\n", remote_class->interfaces[n]->name);
-*/
-
        mono_domain_unlock (domain);
 }
 
+
 /**
  * mono_object_get_virtual_method:
  * @obj: object to operate on.
@@ -1261,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;
@@ -1272,13 +1506,16 @@ handle_enum:
                        goto handle_enum;
                } else {
                        int size;
-                       size = mono_class_value_size (type->data.klass, NULL);
+                       size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
                        if (value == NULL)
                                memset (dest, 0, size);
                        else
                                memcpy (dest, value, size);
                }
                return;
+       case MONO_TYPE_GENERICINST:
+               t = type->data.generic_class->container_class->byval_arg.type;
+               goto handle_enum;
        default:
                g_warning ("got type %x", type->type);
                g_assert_not_reached ();
@@ -1330,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
@@ -1403,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);
@@ -1566,6 +1813,59 @@ mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObjec
        return default_mono_runtime_invoke (prop->get, obj, params, exc);
 }
 
+/*
+ * 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).
+ *
+ * Since Nullables have variable structure, we can not define a C
+ * structure for them.
+ */
+void
+mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
+{
+       MonoClass *param_class = klass->cast_class;
+                               
+       g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
+       g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
+
+       *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
+       if (value)
+               memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
+       else
+               memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
+}
+
+/**
+ * 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
+ * @buf.
+ */
+MonoObject*
+mono_nullable_box (guint8 *buf, MonoClass *klass)
+{
+       MonoClass *param_class = klass->cast_class;
+
+       g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
+       g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
+
+       if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
+               MonoObject *o = mono_object_new (mono_domain_get (), param_class);
+               memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+               return o;
+       }
+       else
+               return NULL;
+}
 
 /**
  * mono_get_delegate_invoke:
@@ -1629,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;
 }
@@ -1680,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);
@@ -1740,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 {
@@ -1869,17 +2171,14 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        domain = mono_object_domain (args);
        if (!domain->entry_assembly) {
                gchar *str;
-               gchar *config_suffix;
                MonoAssembly *assembly;
 
                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));
 
-               config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
-               str = g_build_filename (assembly->basedir, config_suffix, NULL);
-               g_free (config_suffix);
-               domain->setup->configuration_file = mono_string_new (domain, str);
+               str = g_strconcat (assembly->image->name, ".config", NULL);
+               MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
                g_free (str);
        }
 
@@ -1967,15 +2266,14 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
        MonoMethodSignature *sig = mono_method_signature (method);
        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 */
-                       }
+                       MonoType *t = sig->params [i];
 
-                       switch (sig->params [i]->type) {
+               again:
+                       switch (t->type) {
                        case MONO_TYPE_U1:
                        case MONO_TYPE_I1:
                        case MONO_TYPE_BOOLEAN:
@@ -1991,21 +2289,46 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
-                               /* 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]));
-                               pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
+                               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;
                        case MONO_TYPE_STRING:
                        case MONO_TYPE_OBJECT:
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
-                               if (sig->params [i]->byref)
+                               if (t->byref)
                                        pa [i] = &(((gpointer *)params->vector)[i]);
                                else
                                        pa [i] = (char *)(((gpointer *)params->vector)[i]);
                                break;
+                       case MONO_TYPE_GENERICINST:
+                               t = &t->data.generic_class->container_class->byval_arg;
+                               goto again;
                        default:
                                g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
                        }
@@ -2014,6 +2337,17 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 
        if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
                void *o = obj;
+
+               if (mono_class_is_nullable (method->klass)) {
+                       /* Need to create a boxed vtype instead */
+                       g_assert (!obj);
+
+                       if (!params)
+                               return NULL;
+                       else
+                               return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
+               }
+
                if (!obj) {
                        obj = mono_object_new (mono_domain_get (), method->klass);
                        if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
@@ -2116,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;
@@ -2399,8 +2734,8 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
        byte_len = mono_array_element_size (array_class);
        len = 1;
 
-       if (array_class->rank == 1 &&
-           (lower_bounds == NULL || lower_bounds [0] == 0)) {
+       /* A single dimensional array with a 0 lower bound is the same as an szarray */
+       if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
                len = lengths [0];
                if ((int) len < 0)
                        arith_overflow ();
@@ -2708,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
@@ -2741,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);
+       }
 }
 
 /**
@@ -2800,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;
@@ -2833,8 +3214,7 @@ mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
        
                if (*(MonoBoolean *) mono_object_unbox(res)) {
                        /* Update the vtable of the remote type, so it can safely cast to this new type */
-                       mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
-                       obj->vtable = mono_remote_class_vtable (domain, ((MonoTransparentProxy *)obj)->remote_class, (MonoRealProxy *)rp);
+                       mono_upgrade_remote_class (domain, obj, klass);
                        return obj;
                }
        }
@@ -2873,11 +3253,27 @@ str_lookup (MonoDomain *domain, gpointer user_data)
        LDStrInfo *info = user_data;
        if (info->res || domain == info->orig_domain)
                return;
-       mono_domain_lock (domain);
        info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
-       mono_domain_unlock (domain);
 }
 
+#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)
 {
@@ -2887,14 +3283,15 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
        
        domain = ((MonoObject *)str)->vtable->domain;
        ldstr_table = domain->ldstr_table;
-       mono_domain_lock (domain);
+       ldstr_lock ();
        if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
-               mono_domain_unlock (domain);
+               ldstr_unlock ();
                return res;
        }
        if (insert) {
+               str = mono_string_get_pinned (str);
                mono_g_hash_table_insert (ldstr_table, str, str);
-               mono_domain_unlock (domain);
+               ldstr_unlock ();
                return str;
        } else {
                LDStrInfo ldstr_info;
@@ -2909,11 +3306,11 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
                         * intern it in the current one as well.
                         */
                        mono_g_hash_table_insert (ldstr_table, str, str);
-                       mono_domain_unlock (domain);
+                       ldstr_unlock ();
                        return str;
                }
        }
-       mono_domain_unlock (domain);
+       ldstr_unlock ();
        return NULL;
 }
 
@@ -2990,15 +3387,16 @@ mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
                }
        }
 #endif
-       mono_domain_lock (domain);
+       ldstr_lock ();
        if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
-               mono_domain_unlock (domain);
+               ldstr_unlock ();
                /* o will get garbage collected */
                return interned;
        }
 
+       o = mono_string_get_pinned (o);
        mono_g_hash_table_insert (domain->ldstr_table, o, o);
-       mono_domain_unlock (domain);
+       ldstr_unlock ();
 
        return o;
 }
@@ -3024,8 +3422,9 @@ mono_string_to_utf8 (MonoString *s)
 
        as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
        if (error) {
-               g_warning (error->message);
+               MonoException *exc = mono_get_exception_argument ("string", error->message);
                g_error_free (error);
+               mono_raise_exception(exc);
        }
 
        return as;
@@ -3082,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)
 {
@@ -3122,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);
 }
@@ -3158,16 +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 *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
+       MonoMethod *method = mono_get_context_capture_method ();
 
-       res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
+       /* 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));
+               /* 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;
@@ -3187,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);
@@ -3208,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;
@@ -3217,6 +3647,8 @@ mono_message_init (MonoDomain *domain,
                                arg_type |= 1;
                } else {
                        arg_type = 1;
+                       if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
+                               arg_type |= 4;
                }
                mono_array_set (this->arg_types, guint8, i, arg_type);
        }
@@ -3288,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;
 
@@ -3295,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++;
                }
        }
@@ -3371,23 +3804,31 @@ mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
 
        class = this->vtable->klass;
 
-       if ((ji = mono_jit_info_table_find (domain, 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) {
+                       /* 
+                        * Replace the original trampoline with a delegate trampoline
+                        * which will patch delegate->method_ptr with the address of the
+                        * compiled method.
+                        */
+                       addr = arch_create_delegate_trampoline (method, addr);
+               }
                delegate->method_ptr = addr;
-               delegate->target = target;
+               MONO_OBJECT_SETREF (delegate, target, target);
        }
 }
 
@@ -3438,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) {
@@ -3459,12 +3900,23 @@ void
 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
 {
        MonoMethodSignature *sig = mono_method_signature (method);
-       int i, j, type, size;
+       int i, j, type, size, out_len;
+       
+       if (out_args == NULL)
+               return;
+       out_len = mono_array_length (out_args);
+       if (out_len == 0)
+               return;
+
        for (i = 0, j = 0; i < sig->param_count; i++) {
                MonoType *pt = sig->params [i];
 
                if (pt->byref) {
-                       char *arg = mono_array_get (out_args, gpointer, j);
+                       char *arg;
+                       if (j >= out_len)
+                               mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
+
+                       arg = mono_array_get (out_args, gpointer, j);
                        type = pt->type;
 
                        switch (type) {
@@ -3484,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:
@@ -3528,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);
@@ -3551,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);
 
@@ -3561,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);
@@ -3587,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);
 
@@ -3614,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);
 
@@ -3651,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);
 
@@ -3676,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);
 
@@ -3704,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);
 
@@ -3723,12 +4188,29 @@ 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);
 
        if (exc) mono_raise_exception ((MonoException *)exc);
 }
 
+/*
+ * mono_get_addr_from_ftnptr:
+ *
+ *   Given a pointer to a function descriptor, return the function address.
+ * This is only needed on IA64.
+ */
+gpointer
+mono_get_addr_from_ftnptr (gpointer descr)
+{
+#ifdef __ia64__
+       return *(gpointer*)descr;
+#else
+       return descr;
+#endif
+}