2006-05-31 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / object.c
index e3a2b7e9ee53c86eea64b98880687c3b5c71774c..e96f043093154f5d5ba5e54c51b5f250a7ff8dcb 100644 (file)
 #include <mono/metadata/threads-types.h>
 #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>
 
-/*
- * Enable typed allocation using the GC_gcj_malloc function.
- */
+#ifdef HAVE_BOEHM_GC
+#define NEED_TO_ZERO_PTRFREE 1
+#define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
+#define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
 #ifdef HAVE_GC_GCJ_MALLOC
 #define CREATION_SPEEDUP 1
+#define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
+#define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
+#define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
+#define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
+#else
+#define GC_NO_DESCRIPTOR (NULL)
+#define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
+#define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
+#define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
+#endif
+#else
+#ifdef HAVE_SGEN_GC
+#define GC_NO_DESCRIPTOR (NULL)
+#define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
+#define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
+#define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
+#define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
+#define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
+#else
+#define NEED_TO_ZERO_PTRFREE 1
+#define GC_NO_DESCRIPTOR (NULL)
+#define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
+#define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
+#define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
+#define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
+#define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
+#endif
 #endif
 
+static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
+static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
+
 static void
 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)
 {
@@ -93,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 */
@@ -131,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);
 }
 
 /*
@@ -165,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);
@@ -179,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 ());
                                }
                        }
@@ -197,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 */
@@ -205,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,
@@ -220,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);
@@ -234,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;
@@ -245,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;
@@ -272,7 +312,7 @@ static
 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
 {
        TypeInitializationLock *lock = (TypeInitializationLock*) value;
-       if (lock->initializing_tid == GPOINTER_TO_UINT (user)) {
+       if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
                lock->done = TRUE;
                LeaveCriticalSection (&lock->initialization_section);
                --lock->waiting_count;
@@ -288,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
@@ -306,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) 
@@ -321,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;
 
 /**
@@ -386,11 +440,7 @@ mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
        if (default_mono_free_method != NULL)
                default_mono_free_method (domain, method);
 
-       /* 
-        * FIXME: This causes crashes because the types inside signatures and
-        * locals are shared.
-        */
-       /* mono_free_method (method); */
+       mono_free_method (method);
 }
 
 static MonoInitVTableFunc init_vtable_func = NULL;
@@ -409,45 +459,141 @@ mono_install_init_vtable (MonoInitVTableFunc func)
        init_vtable_func = func;
 }
 
-#if 0 && HAVE_BOEHM_GC
-static void
-vtable_finalizer (void *obj, void *data) {
-       g_print ("%s finalized (%p)\n", (char*)data, obj);
-}
-#endif
-
-#if CREATION_SPEEDUP
-
-#define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
-
 /*
  * The vtables in the root appdomain are assumed to be reachable by other 
  * roots, and we don't use typed allocation in the other domains.
  */
 
-#define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
+/* The sync block is no longer a GC pointer */
+#define GC_HEADER_BITMAP (0)
+
+#define BITMAP_EL_SIZE (sizeof (gsize) * 8)
+
+static gsize*
+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;
+
+       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));
+       }
+
+       for (p = class; p != NULL; p = p->parent) {
+               gpointer iter = NULL;
+               while ((field = mono_class_get_fields (p, &iter))) {
+                       MonoType *type;
+
+                       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;
+
+                       pos = field->offset / sizeof (gpointer);
+                       pos += offset;
+
+                       type = mono_type_get_underlying_type (field->type);
+                       switch (type->type) {
+                       /* FIXME: _I and _U and _PTR should be removed eventually */
+                       case MONO_TYPE_I:
+                       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:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_ARRAY:
+                               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;
+                       case MONO_TYPE_GENERICINST:
+                               if (!mono_type_generic_inst_is_valuetype (type)) {
+                                       g_assert ((field->offset % sizeof(gpointer)) == 0);
+
+                                       bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
+                                       *max_set = MAX (*max_set, pos);
+                                       break;
+                               } else {
+                                       /* fall through */
+                               }
+                       case MONO_TYPE_VALUETYPE: {
+                               MonoClass *fclass = mono_class_from_mono_type (field->type);
+                               if (fclass->has_references) {
+                                       /* remove the object header */
+                                       compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
+                               }
+                               break;
+                       }
+                       case MONO_TYPE_I1:
+                       case MONO_TYPE_U1:
+                       case MONO_TYPE_I2:
+                       case MONO_TYPE_U2:
+                       case MONO_TYPE_I4:
+                       case MONO_TYPE_U4:
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_U8:
+                       case MONO_TYPE_R4:
+                       case MONO_TYPE_R8:
+                       case MONO_TYPE_BOOLEAN:
+                       case MONO_TYPE_CHAR:
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                               break;
+                       }
+               }
+               if (static_fields)
+                       break;
+       }
+       return bitmap;
+}
 
 static void
 mono_class_compute_gc_descriptor (MonoClass *class)
 {
-       MonoClassField *field;
-       guint64 bitmap;
-       guint32 bm [2];
+       int max_set = 0;
+       gsize *bitmap;
+       gsize default_bitmap [4] = {0};
        static gboolean gcj_inited = FALSE;
 
        if (!gcj_inited) {
-               gcj_inited = TRUE;
-
-               GC_init_gcj_malloc (5, NULL);
+               mono_loader_lock ();
 
+               mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
+               mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
                mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
 
+#ifdef HAVE_GC_GCJ_MALLOC
+
+               GC_init_gcj_malloc (5, NULL);
+
 #ifdef GC_REDIRECT_TO_LOCAL
                mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
                mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
 #endif
                mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
                mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
+#endif
+               gcj_inited = TRUE;
+               mono_loader_unlock ();
        }
 
        if (!class->inited)
@@ -459,103 +605,48 @@ mono_class_compute_gc_descriptor (MonoClass *class)
        class->gc_descr_inited = TRUE;
        class->gc_descr = GC_NO_DESCRIPTOR;
 
+       bitmap = default_bitmap;
        if (class == mono_defaults.string_class) {
-               bitmap = GC_HEADER_BITMAP;
-               class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
-       }
-       else if (class->rank) {
+               class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
+       } else if (class->rank) {
                mono_class_compute_gc_descriptor (class->element_class);
-
-               if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
-                       bitmap = GC_HEADER_BITMAP;
-                       if (class->rank > 1)
-                               bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
-                       class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
+#ifdef HAVE_SGEN_GC
+               /* libgc has no usable support for arrays... */
+               if (!class->element_class->valuetype) {
+                       gsize abm = 1;
+                       class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
+                       /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
+                               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, 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);*/
+                       if (bitmap != default_bitmap)
+                               g_free (bitmap);
                }
-       }
-       else {
-               static int count = 0;
-               MonoClass *p;
-               guint32 pos;
-
-               /* GC 6.1 has trouble handling 64 bit descriptors... */
-               if ((class->instance_size / sizeof (gpointer)) > 30) {
-/*                     printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
+#endif
+       } else {
+               /*static int count = 0;
+               if (count++ > 58)
+                       return;*/
+               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) {
+                       /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
+                       if (bitmap != default_bitmap)
+                               g_free (bitmap);
                        return;
                }
-
-               bitmap = GC_HEADER_BITMAP;
-
-               count ++;
-
-/*             if (count > 442) */
-/*                     return;  */
-
-/*             printf("KLASS: %s.\n", class->name); */
-
-               for (p = class; p != NULL; p = p->parent) {
-               gpointer iter = NULL;
-               while ((field = mono_class_get_fields (p, &iter))) {
-                       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
-                               continue;
-                       if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
-                               return;
-
-                       pos = field->offset / sizeof (gpointer);
-                       
-                       if (field->type->byref)
-                               return;
-
-                       switch (field->type->type) {
-                       case MONO_TYPE_BOOLEAN:
-                       case MONO_TYPE_I1:
-                       case MONO_TYPE_U1:
-                       case MONO_TYPE_I2:
-                       case MONO_TYPE_U2:
-                       case MONO_TYPE_CHAR:
-                       case MONO_TYPE_I4:
-                       case MONO_TYPE_U4:
-                       case MONO_TYPE_I8:
-                       case MONO_TYPE_U8:
-                       case MONO_TYPE_R4:
-                       case MONO_TYPE_R8:
-/*                             printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
-                               break;
-                       case MONO_TYPE_I:
-                       case MONO_TYPE_STRING:
-                       case MONO_TYPE_SZARRAY:
-                       case MONO_TYPE_CLASS:
-                       case MONO_TYPE_OBJECT:
-                       case MONO_TYPE_ARRAY:
-                       case MONO_TYPE_PTR:
-                               g_assert ((field->offset % sizeof(gpointer)) == 0);
-
-                               bitmap |= ((guint64)1) << pos;
-/*                             printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
-                               break;
-                       case MONO_TYPE_VALUETYPE: {
-                               MonoClass *fclass = field->type->data.klass;
-                               if (!fclass->enumtype) {
-                                       mono_class_compute_gc_descriptor (fclass);
-                                       bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
-                               }
-                               break;
-                       }
-                       default:
-                               return;
-                       }
-               }
-               }
-
-/*             printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
-               class->gc_bitmap = bitmap;
-               /* Convert to the format expected by GC_make_descriptor */
-               bm [0] = (guint32)bitmap;
-               bm [1] = (guint32)(bitmap >> 32);
-               class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
+#endif
+               class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
+               /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
+               if (bitmap != default_bitmap)
+                       g_free (bitmap);
        }
 }
-#endif /* CREATION_SPEEDUP */
 
 /**
  * field_is_special_static:
@@ -590,6 +681,8 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field)
        return SPECIAL_STATIC_NONE;
 }
 
+static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
+
 /**
  * mono_class_vtable:
  * @domain: the application domain
@@ -601,7 +694,22 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field)
 MonoVTable *
 mono_class_vtable (MonoDomain *domain, MonoClass *class)
 {
-       MonoVTable *vt = NULL;
+       MonoClassRuntimeInfo *runtime_info;
+
+       g_assert (class);
+
+       /* this check can be inlined in jitted code, too */
+       runtime_info = class->runtime_info;
+       if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
+               return runtime_info->domain_vtables [domain->domain_id];
+       return mono_class_create_runtime_vtable (domain, class);
+}
+
+static MonoVTable *
+mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
+{
+       MonoVTable *vt;
+       MonoClassRuntimeInfo *runtime_info, *old_info;
        MonoClassField *field;
        char *t;
        int i;
@@ -610,36 +718,39 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
        guint32 cindex;
        guint32 constant_cols [MONO_CONSTANT_SIZE];
        gpointer iter;
-
-       g_assert (class);
-
-       vt = class->cached_vtable;
-       if (vt && vt->domain == domain)
-               return vt;
+       gpointer *interface_offsets;
 
        mono_domain_lock (domain);
-       if ((vt = g_hash_table_lookup (domain->class_vtable_hash, class))) {
+       runtime_info = class->runtime_info;
+       if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
                mono_domain_unlock (domain);
-               return vt;
+               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_setup_vtable (class);
 
-       vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
-       vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
+       vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
+               sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
+       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;
 
-#if CREATION_SPEEDUP
        mono_class_compute_gc_descriptor (class);
-       if (domain != mono_get_root_domain ())
                /*
                 * We can't use typed allocation in the non-root domains, since the
                 * collector needs the GC descriptor stored in the vtable even after
@@ -652,22 +763,31 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                 * vtable field in MonoObject, since we can no longer assume the 
                 * vtable is reachable by other roots after the appdomain is unloaded.
                 */
+#ifdef HAVE_BOEHM_GC
+       if (domain != mono_get_root_domain ())
                vt->gc_descr = GC_NO_DESCRIPTOR;
        else
-               vt->gc_descr = class->gc_descr;
 #endif
+               vt->gc_descr = class->gc_descr;
 
        if (class->class_size) {
-#if HAVE_BOEHM_GC
-               vt->data = GC_MALLOC (class->class_size + 8);
-               /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
-               /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
-               mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
-#else
-               vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
-               
-#endif
-               mono_stats.class_static_data_size += class->class_size + 8;
+               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_stats.class_static_data_size += class->class_size;
        }
 
        cindex = -1;
@@ -678,9 +798,10 @@ mono_class_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, align, offset;
+                               guint32 size, offset;
+                               int align;
                                size = mono_type_size (field->type, &align);
                                offset = mono_alloc_special_static_data (special_static, size, align);
                                if (!domain->special_static_fields)
@@ -697,7 +818,7 @@ mono_class_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;
@@ -705,7 +826,7 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
                        continue;
 
-               
+               /* later do this only on demand if needed */
                if (!field->data) {
                        cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
                        g_assert (cindex);
@@ -716,29 +837,58 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                        field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
                }
                
-               if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
-                       get_default_field_value (domain, field, (char*)vt->data + field->offset);
        }
 
        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]);
        }
 
        /* 
         * arch_create_jit_trampoline () can recursively call this function again
         * because it compiles icall methods right away.
         */
+       /* 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.
+        */
        g_hash_table_insert (domain->class_vtable_hash, class, vt);
-       if (!class->cached_vtable)
-               class->cached_vtable = vt;
+       /* class->runtime_info is protected by the loader lock, both when
+        * it it enlarged and when it is stored info.
+        */
+       mono_loader_lock ();
+       old_info = class->runtime_info;
+       if (old_info && old_info->max_domain >= domain->domain_id) {
+               /* someone already created a large enough runtime info */
+               old_info->domain_vtables [domain->domain_id] = vt;
+       } else {
+               int new_size = domain->domain_id;
+               if (old_info)
+                       new_size = MAX (new_size, old_info->max_domain);
+               new_size++;
+               /* make the new size a power of two */
+               i = 2;
+               while (new_size > i)
+                       i <<= 1;
+               new_size = i;
+               /* this is a bounded memory retention issue: may want to 
+                * handle it differently when we'll have a rcu-like system.
+                */
+               runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+               runtime_info->max_domain = new_size - 1;
+               /* copy the stuff from the older info */
+               if (old_info) {
+                       memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
+               }
+               runtime_info->domain_vtables [domain->domain_id] = vt;
+               /* keep this last (add membarrier) */
+               class->runtime_info = runtime_info;
+       }
+       mono_loader_unlock ();
 
        /* initialize vtable */
        if (init_vtable_func)
@@ -761,6 +911,13 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
 
        mono_domain_unlock (domain);
 
+       /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
+       if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
+               MonoException *exc = mono_class_get_exception_for_failure (class);
+               g_assert (exc);
+               mono_raise_exception (exc);
+       }
+
        /* make sure the the parent is initialized */
        if (class->parent)
                mono_class_vtable (domain, class->parent);
@@ -790,34 +947,58 @@ 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 */
+       pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
 
        /* initialize vtable */
        mono_class_setup_vtable (class);
@@ -840,54 +1021,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
@@ -900,113 +1159,157 @@ 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);
        
+       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.
@@ -1166,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;
@@ -1177,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 ();
@@ -1235,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
@@ -1308,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);
@@ -1471,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:
@@ -1534,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;
 }
@@ -1585,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);
@@ -1645,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 {
@@ -1774,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);
        }
 
@@ -1872,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:
@@ -1896,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);
                        }
@@ -1919,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) {
@@ -1929,6 +2335,9 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        else
                                o = obj;
                }
+               else if (method->klass->valuetype)
+                       obj = mono_value_box (mono_domain_get (), method->klass, obj);
+
                mono_runtime_invoke (method, o, pa, exc);
                return obj;
        } else {
@@ -1953,32 +2362,40 @@ arith_overflow (void)
  * Returns: an allocated object of size @size, or NULL on failure.
  */
 static inline void *
-mono_object_allocate (size_t size)
+mono_object_allocate (size_t size, MonoVTable *vtable)
 {
-#if HAVE_BOEHM_GC
-       /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
-       void *o = GC_MALLOC (size);
-#else
-       void *o = calloc (1, size);
-       if (!o)
-               return mono_gc_out_of_memory (size);
-#endif
+       MonoObject *o;
        mono_stats.new_object_count++;
+       ALLOC_OBJECT (o, vtable, size);
 
        return o;
 }
 
-#if CREATION_SPEEDUP
+/**
+ * mono_object_allocate_ptrfree:
+ * @size: number of bytes to allocate
+ *
+ * Note that the memory allocated is not zeroed.
+ * Returns: an allocated object of size @size, or NULL on failure.
+ */
 static inline void *
-mono_object_allocate_spec (size_t size, void *gcdescr)
+mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
 {
-       /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
-       void *o = GC_GCJ_MALLOC (size, gcdescr);
+       MonoObject *o;
+       mono_stats.new_object_count++;
+       ALLOC_PTRFREE (o, vtable, size);
+       return o;
+}
+
+static inline void *
+mono_object_allocate_spec (size_t size, MonoVTable *vtable)
+{
+       void *o;
+       ALLOC_TYPED (o, size, vtable);
        mono_stats.new_object_count++;
 
        return o;
 }
-#endif
 
 /**
  * mono_object_new:
@@ -2040,18 +2457,14 @@ mono_object_new_alloc_specific (MonoVTable *vtable)
 {
        MonoObject *o;
 
-#if CREATION_SPEEDUP
-       if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
+       if (!vtable->klass->has_references) {
+               o = mono_object_new_ptrfree (vtable);
+       } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
        } else {
 /*             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
-               o = mono_object_allocate (vtable->klass->instance_size);
-               o->vtable = vtable;
+               o = mono_object_allocate (vtable->klass->instance_size, vtable);
        }
-#else
-       o = mono_object_allocate (vtable->klass->instance_size);
-       o->vtable = vtable;
-#endif
        if (vtable->klass->has_finalize)
                mono_object_register_finalizer (o);
        
@@ -2059,33 +2472,71 @@ mono_object_new_alloc_specific (MonoVTable *vtable)
        return o;
 }
 
-#if CREATION_SPEEDUP
-
 MonoObject*
 mono_object_new_fast (MonoVTable *vtable)
 {
-       return GC_GCJ_MALLOC (vtable->klass->instance_size, vtable);
+       MonoObject *o;
+       ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
+       return o;
 }
 
+static MonoObject*
+mono_object_new_ptrfree (MonoVTable *vtable)
+{
+       MonoObject *obj;
+       ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
+#if NEED_TO_ZERO_PTRFREE
+       /* an inline memset is much faster for the common vcase of small objects
+        * note we assume the allocated size is a multiple of sizeof (void*).
+        */
+       if (vtable->klass->instance_size < 128) {
+               gpointer *p, *end;
+               end = (gpointer*)((char*)obj + vtable->klass->instance_size);
+               p = (gpointer*)((char*)obj + sizeof (MonoObject));
+               while (p < end) {
+                       *p = NULL;
+                       ++p;
+               }
+       } else {
+               memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
+       }
 #endif
+       return obj;
+}
+
+static MonoObject*
+mono_object_new_ptrfree_box (MonoVTable *vtable)
+{
+       MonoObject *obj;
+       ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
+       /* the object will be boxed right away, no need to memzero it */
+       return obj;
+}
 
 /**
  * mono_class_get_allocation_ftn:
  * @vtable: vtable
+ * @for_box: the object will be used for boxing
  * @pass_size_in_words: 
  *
  * Return the allocation function appropriate for the given class.
  */
 
 void*
-mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean *pass_size_in_words)
+mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
 {
        *pass_size_in_words = FALSE;
 
        if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
                return mono_object_new_specific;
 
-#if CREATION_SPEEDUP
+       if (!vtable->klass->has_references) {
+               //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
+               if (for_box)
+                       return mono_object_new_ptrfree_box;
+               return mono_object_new_ptrfree;
+       }
+
        if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
 
                return mono_object_new_fast;
@@ -2103,7 +2554,6 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean *pass_size_in_words)
 #endif
                */
        }
-#endif
 
        return mono_object_new_specific;
 }
@@ -2140,8 +2590,9 @@ mono_object_clone (MonoObject *obj)
        int size;
 
        size = obj->vtable->klass->instance_size;
-       o = mono_object_allocate (size);
-       memcpy (o, obj, size);
+       o = mono_object_allocate (size, obj->vtable);
+       /* do not copy the sync state */
+       memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
        
        mono_profiler_allocation (o, obj->vtable->klass);
 
@@ -2185,7 +2636,7 @@ MonoArray*
 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
 {
        MonoArray *o;
-       int size, i;
+       guint32 size, i;
        guint32 *sizes;
        MonoClass *klass = array->obj.vtable->klass;
 
@@ -2247,10 +2698,9 @@ MonoArray*
 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
                     guint32 *lengths, guint32 *lower_bounds)
 {
-       guint32 byte_len, len;
+       guint32 byte_len, len, bounds_size;
        MonoObject *o;
        MonoArray *array;
-       MonoArrayBounds *bounds;
        MonoVTable *vtable;
        int i;
 
@@ -2260,32 +2710,22 @@ 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)) {
-               bounds = NULL;
+       /* 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 ();
+               bounds_size = 0;
        } else {
-       #if HAVE_BOEHM_GC
-               bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
-       #else
-               bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
-       #endif
-               for (i = 0; i < array_class->rank; ++i)
+               bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
+
+               for (i = 0; i < array_class->rank; ++i) {
                        if ((int) lengths [i] < 0)
                                arith_overflow ();
-               
-               for (i = 0; i < array_class->rank; ++i) {
-                       bounds [i].length = lengths [i];
                        if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
                                mono_gc_out_of_memory (MYGUINT32_MAX);
                        len *= lengths [i];
                }
-
-               if (lower_bounds)
-                       for (i = 0; i < array_class->rank; ++i)
-                               bounds [i].lower_bound = lower_bounds [i];
        }
 
        if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
@@ -2294,28 +2734,44 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
        if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
                mono_gc_out_of_memory (MYGUINT32_MAX);
        byte_len += sizeof (MonoArray);
+       if (bounds_size) {
+               /* align */
+               if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
+                       mono_gc_out_of_memory (MYGUINT32_MAX);
+               byte_len = (byte_len + 3) & ~3;
+               if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
+                       mono_gc_out_of_memory (MYGUINT32_MAX);
+               byte_len += bounds_size;
+       }
        /* 
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
         */
        vtable = mono_class_vtable (domain, array_class);
-#if CREATION_SPEEDUP
-       if (vtable->gc_descr != GC_NO_DESCRIPTOR)
+       if (!array_class->has_references) {
+               o = mono_object_allocate_ptrfree (byte_len, vtable);
+#if NEED_TO_ZERO_PTRFREE
+               memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
+#endif
+       } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (byte_len, vtable);
-       else {
-               o = mono_object_allocate (byte_len);
-               o->vtable = vtable;
+       }else {
+               o = mono_object_allocate (byte_len, vtable);
        }
-#else
-       o = mono_object_allocate (byte_len);
-       o->vtable = vtable;
-#endif
 
        array = (MonoArray*)o;
-
-       array->bounds = bounds;
        array->max_length = len;
 
+       if (bounds_size) {
+               MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
+               array->bounds = bounds;
+               for (i = 0; i < array_class->rank; ++i) {
+                       bounds [i].length = lengths [i];
+                       if (lower_bounds)
+                               bounds [i].lower_bound = lower_bounds [i];
+               }
+       }
+
        mono_profiler_allocation (o, array_class);
 
        return array;
@@ -2369,18 +2825,17 @@ mono_array_new_specific (MonoVTable *vtable, guint32 n)
        if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
                mono_gc_out_of_memory (MYGUINT32_MAX);
        byte_len += sizeof (MonoArray);
-#if CREATION_SPEEDUP
-       if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
+       if (!vtable->klass->has_references) {
+               o = mono_object_allocate_ptrfree (byte_len, vtable);
+#if NEED_TO_ZERO_PTRFREE
+               memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
+#endif
+       } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (byte_len, vtable);
        } else {
 /*             printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
-               o = mono_object_allocate (byte_len);
-               o->vtable = vtable;
+               o = mono_object_allocate (byte_len, vtable);
        }
-#else
-       o = mono_object_allocate (byte_len);
-       o->vtable = vtable;
-#endif
 
        ao = (MonoArray *)o;
        ao->bounds = NULL;
@@ -2430,19 +2885,12 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
 
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
 
-#if CREATION_SPEEDUP
-       if (vtable->gc_descr != GC_NO_DESCRIPTOR)
-               s = mono_object_allocate_spec (size, vtable);
-       else {
-               s = (MonoString*)mono_object_allocate (size);
-               s->object.vtable = vtable;
-       }
-#else
-       s = (MonoString*)mono_object_allocate (size);
-       s->object.vtable = vtable;
-#endif
+       s = mono_object_allocate_ptrfree (size, vtable);
 
        s->length = len;
+#if NEED_TO_ZERO_PTRFREE
+       s->chars [len] = 0;
+#endif
        mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
 
        return s;
@@ -2541,8 +2989,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 
        vtable = mono_class_vtable (domain, class);
        size = mono_class_instance_size (class);
-       res = mono_object_allocate (size);
-       res->vtable = vtable;
+       res = mono_object_allocate (size, vtable);
        mono_profiler_allocation (res, class);
 
        size = size - sizeof (MonoObject);
@@ -2572,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
@@ -2605,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);
+       }
 }
 
 /**
@@ -2664,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;
@@ -2697,8 +3190,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;
                }
        }
@@ -2737,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)
 {
@@ -2751,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;
@@ -2773,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;
 }
 
@@ -2854,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;
 }
@@ -2888,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;
@@ -2946,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)
 {
@@ -2986,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);
 }
@@ -3022,16 +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 *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;
@@ -3051,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);
@@ -3072,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;
@@ -3081,6 +3623,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);
        }
@@ -3152,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;
 
@@ -3159,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++;
                }
        }
@@ -3235,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);
        }
 }
 
@@ -3302,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) {
@@ -3323,12 +3876,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) {
@@ -3392,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);
@@ -3415,14 +3977,19 @@ 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);
 
        if (exc) mono_raise_exception ((MonoException *)exc);
 
-       *res = mono_array_get (out_args, MonoObject *, 0);
+       if (mono_array_length (out_args) == 0)
+               return NULL;
+
+       *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
 
        if (field_class->valuetype) {
                return ((char *)*res) + sizeof (MonoObject);
@@ -3448,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);
 
@@ -3472,16 +4040,22 @@ mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *
        
        msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
        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);
 
        if (exc) mono_raise_exception ((MonoException *)exc);
 
-       res = mono_array_get (out_args, MonoObject *, 0);
+       if (mono_array_length (out_args) == 0)
+               res = NULL;
+       else
+               res = mono_array_get (out_args, MonoObject *, 0);
 
        return res;
 }
@@ -3508,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);
 
@@ -3533,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);
 
@@ -3561,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);
 
@@ -3580,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
+}