2006-05-31 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / object.c
index 2d0868fb5b25a2ca3f69aa4bdd08c06e72698474..e96f043093154f5d5ba5e54c51b5f250a7ff8dcb 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,7 @@ 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);
 }
 
 /*
@@ -197,10 +205,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 +219,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 +237,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 +245,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 +260,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 +274,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 +285,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 +328,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 +346,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 +369,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 +470,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 = class->class_size / sizeof (gpointer);
+       else
+               max_size = class->instance_size / sizeof (gpointer);
        if (max_size > size) {
                bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
        }
@@ -463,8 +490,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 +511,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 +524,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 +560,8 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                                break;
                        }
                }
+               if (static_fields)
+                       break;
        }
        return bitmap;
 }
@@ -572,7 +619,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 +631,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) {
@@ -671,6 +718,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        guint32 cindex;
        guint32 constant_cols [MONO_CONSTANT_SIZE];
        gpointer iter;
+       gpointer *interface_offsets;
 
        mono_domain_lock (domain);
        runtime_info = class->runtime_info;
@@ -679,15 +727,25 @@ 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_stats.used_class_count++;
-       mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
-       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;
@@ -713,11 +771,22 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                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
+               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->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->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->class_size);
-               mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
+               }
                mono_stats.class_static_data_size += class->class_size;
        }
 
@@ -729,7 +798,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;
@@ -772,14 +841,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 +855,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
@@ -885,6 +949,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;
@@ -922,12 +987,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 */
@@ -954,14 +1021,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) {
@@ -974,7 +1039,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;
@@ -989,6 +1054,32 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        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.
@@ -1040,6 +1131,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
@@ -1052,12 +1159,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);
@@ -1065,6 +1172,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;
@@ -1078,9 +1189,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;
@@ -1094,15 +1205,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));
@@ -1131,7 +1246,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;
 }
@@ -1354,6 +1469,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;
@@ -1365,13 +1483,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 ();
@@ -1423,6 +1544,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
@@ -1496,6 +1624,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);
@@ -1659,6 +1790,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:
@@ -1722,7 +1906,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;
 }
@@ -1773,6 +1957,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);
@@ -1833,7 +2019,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 {
@@ -1962,17 +2148,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);
        }
 
@@ -2060,15 +2243,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:
@@ -2084,21 +2266,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);
                        }
@@ -2107,6 +2314,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) {
@@ -2492,8 +2710,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 ();
@@ -2801,6 +3019,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
@@ -2834,13 +3089,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);
+       }
 }
 
 /**
@@ -2893,11 +3155,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;
@@ -2965,11 +3229,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)
 {
@@ -2979,14 +3259,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;
@@ -3001,11 +3282,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;
 }
 
@@ -3082,15 +3363,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;
 }
@@ -3116,8 +3398,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;
@@ -3174,6 +3457,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)
 {
@@ -3214,7 +3522,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);
 }
@@ -3250,21 +3558,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;
@@ -3284,20 +3593,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);
@@ -3305,8 +3614,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;
@@ -3387,6 +3696,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;
 
@@ -3394,9 +3704,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++;
                }
        }
@@ -3470,23 +3780,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);
        }
 }
 
@@ -3537,7 +3855,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) {
@@ -3638,12 +3956,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);
@@ -3661,8 +3977,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);
 
@@ -3671,7 +3989,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);
@@ -3697,6 +4015,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);
 
@@ -3724,8 +4043,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);
 
@@ -3761,6 +4082,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);
 
@@ -3786,9 +4108,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);
 
@@ -3814,6 +4138,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);
 
@@ -3833,12 +4158,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
+}