2010-05-29 Robert Jordan <robertj@gmx.net>
[mono.git] / mono / metadata / object.c
index 120ab08a8be032466e9a2f97ad7eeb891d1a6afb..11043d598276bfce9d4ae0587376a3276f4de7fa 100644 (file)
 #include "mono/metadata/security-manager.h"
 #include "mono/metadata/mono-debug-debugger.h"
 #include <mono/metadata/gc-internal.h>
+#include <mono/metadata/verify-internals.h>
 #include <mono/utils/strenc.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-error-internals.h>
+#include "cominterop.h"
 
 #ifdef HAVE_BOEHM_GC
 #define NEED_TO_ZERO_PTRFREE 1
@@ -141,6 +144,9 @@ static GHashTable *blocked_thread_hash;
 /* Main thread */
 static MonoThread *main_thread;
 
+/* Functions supplied by the runtime */
+static MonoRuntimeCallbacks callbacks;
+
 /**
  * mono_thread_set_main:
  * @thread: thread to set as the main thread
@@ -258,7 +264,10 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                mono_image_check_for_module_cctor (klass->image);
                if (klass->image->has_module_cctor) {
                        MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
-                       mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
+                       MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
+                       if (!module_vtable)
+                               return NULL;
+                       mono_runtime_class_init (module_vtable);
                }
        }
        method = mono_class_get_cctor (klass);
@@ -428,7 +437,7 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
 }
 
 void
-mono_release_type_locks (MonoThread *thread)
+mono_release_type_locks (MonoInternalThread *thread)
 {
        mono_type_initialization_lock ();
        g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
@@ -473,6 +482,18 @@ static MonoImtThunkBuilder imt_thunk_builder = NULL;
 #error "MONO_IMT_SIZE cannot be larger than 32"
 #endif
 
+void
+mono_install_callbacks (MonoRuntimeCallbacks *cbs)
+{
+       memcpy (&callbacks, cbs, sizeof (*cbs));
+}
+
+MonoRuntimeCallbacks*
+mono_get_runtime_callbacks (void)
+{
+       return &callbacks;
+}
+
 void
 mono_install_trampoline (MonoTrampoline func) 
 {
@@ -606,9 +627,20 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                max_size = mono_class_data_size (class) / sizeof (gpointer);
        else
                max_size = class->instance_size / sizeof (gpointer);
-       if (max_size >= size) {
-               bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
+       if (max_size > size) {
+               g_assert (offset <= 0);
+               bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
+               size = max_size;
+       }
+
+#ifdef HAVE_SGEN_GC
+       /*An Ephemeron cannot be marked by sgen*/
+       if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
+               *max_set = 0;
+               memset (bitmap, 0, size / 8);
+               return bitmap;
        }
+#endif
 
        for (p = class; p != NULL; p = p->parent) {
                gpointer iter = NULL;
@@ -628,6 +660,10 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                        if (field->type->byref)
                                break;
 
+                       if (static_fields && field->offset == -1)
+                               /* special static */
+                               continue;
+
                        pos = field->offset / sizeof (gpointer);
                        pos += offset;
 
@@ -652,6 +688,7 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                        case MONO_TYPE_ARRAY:
                                g_assert ((field->offset % sizeof(gpointer)) == 0);
 
+                               g_assert (pos < size || pos <= max_size);
                                bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
                                *max_set = MAX (*max_set, pos);
                                break;
@@ -687,7 +724,7 @@ compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int
                        case MONO_TYPE_CHAR:
                                break;
                        default:
-                               g_assert_not_reached ();
+                               g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
                                break;
                        }
                }
@@ -845,7 +882,7 @@ mono_string_alloc (int length)
        return mono_string_new_size (mono_domain_get (), length);
 }
 
-static void
+void
 mono_class_compute_gc_descriptor (MonoClass *class)
 {
        int max_set = 0;
@@ -957,6 +994,14 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field)
        return SPECIAL_STATIC_NONE;
 }
 
+static gpointer imt_trampoline = NULL;
+
+void
+mono_install_imt_trampoline (gpointer tramp_code)
+{
+       imt_trampoline = tramp_code;
+}
+
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 #define mix(a,b,c) { \
        a -= c;  a ^= rot(c, 4);  c += b; \
@@ -976,14 +1021,26 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field)
        c ^= b; c -= rot(b,24); \
 }
 
+/*
+ * mono_method_get_imt_slot:
+ *
+ *   The IMT slot is embedded into AOTed code, so this must return the same value
+ * for the same method across all executions. This means:
+ * - pointers shouldn't be used as hash values.
+ * - mono_metadata_str_hash () should be used for hashing strings.
+ */
 guint32
-mono_method_get_imt_slot (MonoMethod *method) {
+mono_method_get_imt_slot (MonoMethod *method)
+{
        MonoMethodSignature *sig;
        int hashes_count;
        guint32 *hashes_start, *hashes;
        guint32 a, b, c;
        int i;
 
+       /* This can be used to stress tests the collision code */
+       //return 0;
+
        /*
         * We do this to simplify generic sharing.  It will hurt
         * performance in cases where a class implements two different
@@ -1005,14 +1062,14 @@ mono_method_get_imt_slot (MonoMethod *method) {
        }
        
        /* Initialize hashes */
-       hashes [0] = g_str_hash (method->klass->name);
-       hashes [1] = g_str_hash (method->klass->name_space);
-       hashes [2] = g_str_hash (method->name);
+       hashes [0] = mono_metadata_str_hash (method->klass->name);
+       hashes [1] = mono_metadata_str_hash (method->klass->name_space);
+       hashes [2] = mono_metadata_str_hash (method->name);
        hashes [3] = mono_metadata_type_hash (sig->ret);
        for (i = 0; i < sig->param_count; i++) {
                hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
        }
-       
+
        /* Setup internal state */
        a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
 
@@ -1056,7 +1113,7 @@ add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, gu
                return;
        }
 
-       entry = malloc (sizeof (MonoImtBuilderEntry));
+       entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
        entry->key = method;
        entry->value.vtable_slot = vtable_slot;
        entry->next = imt_builder [imt_slot];
@@ -1072,9 +1129,12 @@ add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, gu
        }
        imt_builder [imt_slot] = entry;
 #if DEBUG_IMT
-       printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
-                       method, method->klass->name_space, method->klass->name,
-                       method->name, imt_slot, vtable_slot, entry->children);
+       {
+       char *method_name = mono_method_full_name (method, TRUE);
+       printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
+                       method, method_name, imt_slot, vtable_slot, entry->children);
+       g_free (method_name);
+       }
 #endif
 }
 
@@ -1082,13 +1142,14 @@ add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, gu
 static void
 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
        if (e != NULL) {
+               MonoMethod *method = e->key;
                printf ("  * %s [%d]: (%p) '%s.%s.%s'\n",
                                message,
                                num,
-                               e->method,
-                               e->method->klass->name_space,
-                               e->method->klass->name,
-                               e->method->name);
+                               method,
+                               method->klass->name_space,
+                               method->klass->name,
+                               method->name);
        } else {
                printf ("  * %s: NULL\n", message);
        }
@@ -1114,6 +1175,7 @@ imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *
                        MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
                        item->key = sorted_array [i]->key;
                        item->value = sorted_array [i]->value;
+                       item->has_target_code = sorted_array [i]->has_target_code;
                        item->is_equals = TRUE;
                        if (i < end - 1)
                                item->check_target_idx = out_array->len + 1;
@@ -1158,9 +1220,10 @@ imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
 }
 
 static gpointer
-initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
+initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
+{
        if (imt_builder_entry != NULL) {
-               if (imt_builder_entry->children == 0) {
+               if (imt_builder_entry->children == 0 && !fail_tramp) {
                        /* No collision, return the vtable slot contents */
                        return vtable->vtable [imt_builder_entry->value.vtable_slot];
                } else {
@@ -1169,34 +1232,51 @@ initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry
                        gpointer result;
                        int i;
                        result = imt_thunk_builder (vtable, domain,
-                               (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, NULL);
+                               (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
                        for (i = 0; i < imt_ir->len; ++i)
                                g_free (g_ptr_array_index (imt_ir, i));
                        g_ptr_array_free (imt_ir, TRUE);
                        return result;
                }
        } else {
-               /* Empty slot */
-               return NULL;
+               if (fail_tramp)
+                       return fail_tramp;
+               else
+                       /* Empty slot */
+                       return NULL;
        }
 }
 
+static MonoImtBuilderEntry*
+get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
+
+/*
+ * LOCKING: requires the loader and domain locks.
+ *
+*/
 static void
-build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
+build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
+{
        int i;
        GSList *list_item;
        guint32 imt_collisions_bitmap = 0;
        MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
        int method_count = 0;
        gboolean record_method_count_for_max_collisions = FALSE;
+       gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
 
 #if DEBUG_IMT
-       printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
+       printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
 #endif
        for (i = 0; i < klass->interface_offsets_count; ++i) {
                MonoClass *iface = klass->interfaces_packed [i];
                int interface_offset = klass->interface_offsets_packed [i];
-               int method_slot_in_interface;
+               int method_slot_in_interface, vt_slot;
+
+               if (mono_class_has_variant_generic_params (iface))
+                       has_variant_iface = TRUE;
+
+               vt_slot = interface_offset;
                for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
                        MonoMethod *method;
 
@@ -1208,11 +1288,22 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                                 * add_imt_builder_entry anyway.
                                 */
                                method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
-                               if (mono_method_get_imt_slot (method) != slot_num)
+                               if (mono_method_get_imt_slot (method) != slot_num) {
+                                       vt_slot ++;
                                        continue;
+                               }
                        }
                        method = mono_class_get_method_by_index (iface, method_slot_in_interface);
-                       add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
+                       if (method->is_generic) {
+                               has_generic_virtual = TRUE;
+                               vt_slot ++;
+                               continue;
+                       }
+
+                       if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
+                               add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
+                               vt_slot ++;
+                       }
                }
        }
        if (extra_interfaces) {
@@ -1230,13 +1321,49 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
        }
        for (i = 0; i < MONO_IMT_SIZE; ++i) {
                /* overwrite the imt slot only if we're building all the entries or if 
-                * we're uilding this specific one
+                * we're building this specific one
                 */
-               if (slot_num < 0 || i == slot_num)
-                       imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
+               if (slot_num < 0 || i == slot_num) {
+                       MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
+
+                       if (entries) {
+                               if (imt_builder [i]) {
+                                       MonoImtBuilderEntry *entry;
+
+                                       /* Link entries with imt_builder [i] */
+                                       for (entry = entries; entry->next; entry = entry->next) {
 #if DEBUG_IMT
-               printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
+                                               MonoMethod *method = (MonoMethod*)entry->key;
+                                               char *method_name = mono_method_full_name (method, TRUE);
+                                               printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
+                                               g_free (method_name);
 #endif
+                                       }
+                                       entry->next = imt_builder [i];
+                                       entries->children += imt_builder [i]->children + 1;
+                               }
+                               imt_builder [i] = entries;
+                       }
+
+                       if (has_generic_virtual || has_variant_iface) {
+                               /*
+                                * There might be collisions later when the the thunk is expanded.
+                                */
+                               imt_collisions_bitmap |= (1 << i);
+
+                               /* 
+                                * The IMT thunk might be called with an instance of one of the 
+                                * generic virtual methods, so has to fallback to the IMT trampoline.
+                                */
+                               imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
+                       } else {
+                               imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
+                       }
+#if DEBUG_IMT
+                       printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
+#endif
+               }
+
                if (imt_builder [i] != NULL) {
                        int methods_in_slot = imt_builder [i]->children + 1;
                        if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
@@ -1256,7 +1383,7 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                MonoImtBuilderEntry* entry = imt_builder [i];
                while (entry != NULL) {
                        MonoImtBuilderEntry* next = entry->next;
-                       free (entry);
+                       g_free (entry);
                        entry = next;
                }
        }
@@ -1270,22 +1397,6 @@ build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt,
        build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
 }
 
-static gpointer imt_trampoline = NULL;
-
-void
-mono_install_imt_trampoline (gpointer tramp_code)
-{
-       imt_trampoline = tramp_code;
-}
-
-static gpointer vtable_trampoline = NULL;
-
-void
-mono_install_vtable_trampoline (gpointer tramp_code)
-{
-       vtable_trampoline = tramp_code;
-}
-
 /**
  * mono_vtable_build_imt_slot:
  * @vtable: virtual object table struct
@@ -1294,6 +1405,8 @@ mono_install_vtable_trampoline (gpointer tramp_code)
  * Fill the given @imt_slot in the IMT table of @vtable with
  * a trampoline or a thunk for the case of collisions.
  * This is part of the internal mono API.
+ *
+ * LOCKING: Take the domain lock.
  */
 void
 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
@@ -1307,11 +1420,13 @@ mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
         * Update and heck needs to ahppen inside the proper domain lock, as all
         * the changes made to a MonoVTable.
         */
+       mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
        mono_domain_lock (vtable->domain);
        /* we change the slot only if it wasn't changed from the generic imt trampoline already */
        if (imt [imt_slot] == imt_trampoline)
                build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
        mono_domain_unlock (vtable->domain);
+       mono_loader_unlock ();
 }
 
 
@@ -1321,7 +1436,11 @@ mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
  * entry points to the last element.  That way appending and removing
  * the first element are both O(1) operations.
  */
+#ifdef MONO_SMALL_CONFIG
+#define NUM_FREE_LISTS         6
+#else
 #define NUM_FREE_LISTS         12
+#endif
 #define FIRST_FREE_LIST_SIZE   64
 #define MAX_WAIT_LENGTH        50
 #define THUNK_THRESHOLD                10
@@ -1405,7 +1524,7 @@ mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
        }
        generic_virtual_thunks_size += size;
 
-       p = mono_code_manager_reserve (domain->code_mp, size);
+       p = mono_domain_code_reserve (domain, size);
        *p = size;
 
        return p + 1;
@@ -1451,27 +1570,70 @@ invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
 }
 
 typedef struct _GenericVirtualCase {
-       MonoGenericInst *inst;
+       MonoMethod *method;
        gpointer code;
        int count;
        struct _GenericVirtualCase *next;
 } GenericVirtualCase;
 
+/*
+ * get_generic_virtual_entries:
+ *
+ *   Return IMT entries for the generic virtual method instances and
+ *   variant interface methods for vtable slot
+ * VTABLE_SLOT.
+ */ 
+static MonoImtBuilderEntry*
+get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
+{
+       GenericVirtualCase *list;
+       MonoImtBuilderEntry *entries;
+  
+       mono_domain_lock (domain);
+       if (!domain->generic_virtual_cases)
+               domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+       entries = NULL;
+       for (; list; list = list->next) {
+               MonoImtBuilderEntry *entry;
+               if (list->count < THUNK_THRESHOLD)
+                       continue;
+               entry = g_new0 (MonoImtBuilderEntry, 1);
+               entry->key = list->method;
+               entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
+               entry->has_target_code = 1;
+               if (entries)
+                       entry->children = entries->children + 1;
+               entry->next = entries;
+               entries = entry;
+       }
+       mono_domain_unlock (domain);
+       /* FIXME: Leaking memory ? */
+       return entries;
+}
+
 /**
  * mono_method_add_generic_virtual_invocation:
  * @domain: a domain
  * @vtable_slot: pointer to the vtable slot
- * @method_inst: the method's method_inst
+ * @method: the inflated generic virtual method
  * @code: the method's code
  *
  * Registers a call via unmanaged code to a generic virtual method
- * instantiation.  If the number of calls reaches a threshold
+ * instantiation or variant interface method.  If the number of calls reaches a threshold
  * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
  * virtual method thunk.
  */
 void
-mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable_slot,
-       MonoGenericInst *method_inst, gpointer code)
+mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
+                                                                                       gpointer *vtable_slot,
+                                                                                       MonoMethod *method, gpointer code)
 {
        static gboolean inited = FALSE;
        static int num_added = 0;
@@ -1486,9 +1648,10 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable
                domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        /* Check whether the case was already added */
-       gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+       list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+       gvc = list;
        while (gvc) {
-               if (gvc->inst == method_inst)
+               if (gvc->method == method)
                        break;
                gvc = gvc->next;
        }
@@ -1496,7 +1659,7 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable
        /* If not found, make a new one */
        if (!gvc) {
                gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
-               gvc->inst = method_inst;
+               gvc->method = method;
                gvc->code = code;
                gvc->count = 0;
                gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
@@ -1510,49 +1673,40 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, gpointer *vtable
                num_added++;
        }
 
-       if (++gvc->count < THUNK_THRESHOLD) {
-               mono_domain_unlock (domain);
-               return;
-       }
-
-       entries = NULL;
-       for (list = gvc; list; list = list->next) {
-               MonoImtBuilderEntry *entry;
+       if (++gvc->count == THUNK_THRESHOLD) {
+               gpointer *old_thunk = *vtable_slot;
+               gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
 
-               if (list->count < THUNK_THRESHOLD)
-                       continue;
-
-               entry = g_new0 (MonoImtBuilderEntry, 1);
-               entry->key = list->inst;
-               entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
-               if (entries)
-                       entry->children = entries->children + 1;
-               entry->next = entries;
-               entries = entry;
-       }
+               if ((gpointer)vtable_slot < (gpointer)vtable)
+                       /* Force the rebuild of the thunk at the next call */
+                       *vtable_slot = imt_trampoline;
+               else {
+                       entries = get_generic_virtual_entries (domain, vtable_slot);
 
-       sorted = imt_sort_slot_entries (entries);
+                       sorted = imt_sort_slot_entries (entries);
 
-       if (*vtable_slot != vtable_trampoline)
-               invalidate_generic_virtual_thunk (domain, *vtable_slot);
+                       *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
+                                                                                         vtable_trampoline);
 
-       *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
-               vtable_trampoline);
+                       while (entries) {
+                               MonoImtBuilderEntry *next = entries->next;
+                               g_free (entries);
+                               entries = next;
+                       }
 
-       mono_domain_unlock (domain);
+                       for (i = 0; i < sorted->len; ++i)
+                               g_free (g_ptr_array_index (sorted, i));
+                       g_ptr_array_free (sorted, TRUE);
+               }
 
-       while (entries) {
-               MonoImtBuilderEntry *next = entries->next;
-               g_free (entries);
-               entries = next;
+               if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
+                       invalidate_generic_virtual_thunk (domain, old_thunk);
        }
 
-       for (i = 0; i < sorted->len; ++i)
-               g_free (g_ptr_array_index (sorted, i));
-       g_ptr_array_free (sorted, TRUE);
+       mono_domain_unlock (domain);
 }
 
-static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
+static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
 
 /**
  * mono_class_vtable:
@@ -1565,18 +1719,37 @@ static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoCla
  */
 MonoVTable *
 mono_class_vtable (MonoDomain *domain, MonoClass *class)
+{
+       return mono_class_vtable_full (domain, class, FALSE);
+}
+
+/**
+ * mono_class_vtable_full:
+ * @domain: the application domain
+ * @class: the class to initialize
+ * @raise_on_error if an exception should be raised on failure or not
+ *
+ * VTables are domain specific because we create domain specific code, and 
+ * they contain the domain specific static class data.
+ */
+MonoVTable *
+mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
 {
        MonoClassRuntimeInfo *runtime_info;
 
        g_assert (class);
 
+       if (class->exception_type) {
+               if (raise_on_error)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
+               return NULL;
+       }
+
        /* 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];
-       if (class->exception_type)
-               return NULL;
-       return mono_class_create_runtime_vtable (domain, class);
+       return mono_class_create_runtime_vtable (domain, class, raise_on_error);
 }
 
 /**
@@ -1601,7 +1774,7 @@ mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
 }
 
 static MonoVTable *
-mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
+mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
 {
        MonoVTable *vt;
        MonoClassRuntimeInfo *runtime_info, *old_info;
@@ -1614,23 +1787,45 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        gpointer iter;
        gpointer *interface_offsets;
 
+       mono_loader_lock (); /*FIXME mono_class_init acquires it*/
        mono_domain_lock (domain);
        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);
+               mono_loader_unlock ();
                return runtime_info->domain_vtables [domain->domain_id];
        }
        if (!class->inited || class->exception_type) {
-               if (!mono_class_init (class) || class->exception_type){
-                       MonoException *exc;
+               if (!mono_class_init (class) || class->exception_type) {
                        mono_domain_unlock (domain);
-                       exc = mono_class_get_exception_for_failure (class);
-                       g_assert (exc);
-                       mono_raise_exception (exc);
+                       mono_loader_unlock ();
+                       if (raise_on_error)
+                               mono_raise_exception (mono_class_get_exception_for_failure (class));
+                       return NULL;
                }
        }
 
-       mono_class_init (class);
+       /* Array types require that their element type be valid*/
+       if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               MonoClass *element_class = class->element_class;
+               if (!element_class->inited)
+                       mono_class_init (element_class);
+
+               /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
+               if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
+                       mono_class_setup_vtable (element_class);
+               
+               if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+                       /*Can happen if element_class only got bad after mono_class_setup_vtable*/
+                       if (class->exception_type == MONO_EXCEPTION_NONE)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_domain_unlock (domain);
+                       mono_loader_unlock ();
+                       if (raise_on_error)
+                               mono_raise_exception (mono_class_get_exception_for_failure (class));
+                       return NULL;
+               }
+       }
 
        /* 
         * For some classes, mono_class_init () already computed class->vtable_size, and 
@@ -1641,11 +1836,14 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 
        if (class->exception_type) {
                mono_domain_unlock (domain);
+               mono_loader_unlock ();
+               if (raise_on_error)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
                return NULL;
        }
 
        if (ARCH_USE_IMT) {
-               vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+               vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
                if (class->interface_offsets_count) {
                        imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
                        vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
@@ -1654,7 +1852,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                }
        } else {
                vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.used_class_count++;
@@ -1698,7 +1896,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 
                        bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
                        /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
-                       statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
+                       statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
                        vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
                        mono_domain_add_class_static_data (domain, class, vt->data, NULL);
                        if (bitmap != default_bitmap)
@@ -1721,11 +1919,34 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                        if (special_static != SPECIAL_STATIC_NONE) {
                                guint32 size, offset;
                                gint32 align;
+                               gsize default_bitmap [4] = {0};
+                               gsize *bitmap;
+                               int max_set = 0;
+                               MonoClass *fclass;
+                               if (mono_type_is_reference (field->type)) {
+                                       default_bitmap [0] = 1;
+                                       max_set = 1;
+                                       bitmap = default_bitmap;
+                               } else if (mono_type_is_struct (field->type)) {
+                                       fclass = mono_class_from_mono_type (field->type);
+                                       bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
+                               } else {
+                                       default_bitmap [0] = 0;
+                                       max_set = 0;
+                                       bitmap = default_bitmap;
+                               }
                                size = mono_type_size (field->type, &align);
-                               offset = mono_alloc_special_static_data (special_static, size, align);
+                               offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
                                if (!domain->special_static_fields)
                                        domain->special_static_fields = g_hash_table_new (NULL, NULL);
                                g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
+                               if (bitmap != default_bitmap)
+                                       g_free (bitmap);
+                               /* 
+                                * This marks the field as special static to speed up the
+                                * checks in mono_field_static_get/set_value ().
+                                */
+                               field->offset = -1;
                                continue;
                        }
                }
@@ -1764,15 +1985,13 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                }
        }
 
-       /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
-        * as we change the code in appdomain.c to invalidate vtables by
-        * looking at the possible MonoClasses created for the domain.
+       /*  class_vtable_array keeps an array of created vtables
         */
-       g_hash_table_insert (domain->class_vtable_hash, class, vt);
+       g_ptr_array_add (domain->class_vtable_array, 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 */
@@ -1791,7 +2010,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                /* this is a bounded memory retention issue: may want to 
                 * handle it differently when we'll have a rcu-like system.
                 */
-               runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+               runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
                runtime_info->max_domain = new_size - 1;
                /* copy the stuff from the older info */
                if (old_info) {
@@ -1802,13 +2021,12 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                mono_memory_barrier ();
                class->runtime_info = runtime_info;
        }
-       mono_loader_unlock ();
 
        /* Initialize vtable */
-       if (vtable_trampoline) {
+       if (callbacks.get_vtable_trampoline) {
                // This also covers the AOT case
                for (i = 0; i < class->vtable_size; ++i) {
-                       vt->vtable [i] = vtable_trampoline;
+                       vt->vtable [i] = callbacks.get_vtable_trampoline (i);
                }
        } else {
                mono_class_setup_vtable (class);
@@ -1816,13 +2034,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                for (i = 0; i < class->vtable_size; ++i) {
                        MonoMethod *cm;
 
-                       if ((cm = class->vtable [i])) {
-                               if (mono_method_signature (cm)->generic_param_count)
-                                       /* FIXME: Why is this needed ? */
-                                       vt->vtable [i] = cm;
-                               else
-                                       vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
-                       }
+                       if ((cm = class->vtable [i]))
+                               vt->vtable [i] = arch_create_jit_trampoline (cm);
                }
        }
 
@@ -1838,19 +2051,34 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        }
 
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
 
        /* 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);
-       }
+       if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
+               mono_raise_exception (mono_class_get_exception_for_failure (class));
 
        /* make sure the parent is initialized */
+       /*FIXME shouldn't this fail the current type?*/
        if (class->parent)
-               mono_class_vtable (domain, class->parent);
+               mono_class_vtable_full (domain, class->parent, raise_on_error);
 
+       /*FIXME check for OOM*/
        vt->type = mono_type_get_object (domain, &class->byval_arg);
+#if HAVE_SGEN_GC
+       if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
+               static void *type_desc = NULL;
+
+               if (!type_desc) {
+                       gsize bmap = 1;
+                       type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
+               }
+
+               /* This is unregistered in
+                  unregister_vtable_reflection_type() in
+                  domain.c. */
+               mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
+       }
+#endif
        if (class->contextbound)
                vt->remote = 1;
        else
@@ -1872,14 +2100,22 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 static MonoVTable *
 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
 {
+       MonoError error;
        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;
+       uint8_t *bitmap;
+       int bsize;
+       
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       int bcsize;
+#endif
 
        vt = mono_class_vtable (domain, class);
+       g_assert (vt); /*FIXME property handle failure*/
        max_interface_id = vt->max_interface_id;
        
        /* Calculate vtable space for extra interfaces */
@@ -1888,6 +2124,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                GPtrArray *ifaces;
                int method_count;
 
+               /*FIXME test for interfaces with variant generic arguments*/
                if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
                        continue;       /* interface implemented by the class */
                if (g_slist_find (extra_interfaces, iclass))
@@ -1897,10 +2134,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                
                method_count = mono_class_num_methods (iclass);
        
-               ifaces = mono_class_get_implemented_interfaces (iclass);
+               ifaces = mono_class_get_implemented_interfaces (iclass, &error);
+               g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
                if (ifaces) {
                        for (i = 0; i < ifaces->len; ++i) {
                                MonoClass *ic = g_ptr_array_index (ifaces, i);
+                               /*FIXME test for interfaces with variant generic arguments*/
                                if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
                                        continue;       /* interface implemented by the class */
                                if (g_slist_find (extra_interfaces, ic))
@@ -1919,10 +2158,10 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                mono_stats.imt_number_of_tables++;
                mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
                vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        } else {
                vtsize = sizeof (gpointer) * (max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
@@ -1932,7 +2171,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
        else
                pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
-       memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
+       memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
 
        pvt->klass = mono_defaults.transparent_proxy_class;
        /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
@@ -1961,7 +2200,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        }
 
        pvt->max_interface_id = max_interface_id;
-       pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
+       bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       bitmap = g_malloc0 (bsize);
+#else
+       bitmap = mono_domain_alloc0 (domain, bsize);
+#endif
 
        if (! ARCH_USE_IMT) {
                /* initialize interface offsets */
@@ -1973,7 +2217,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        }
        for (i = 0; i < class->interface_offsets_count; ++i) {
                int interface_id = class->interfaces_packed [i]->interface_id;
-               pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
+               bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
        }
 
        if (extra_interfaces) {
@@ -1990,7 +2234,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        if (! ARCH_USE_IMT) {
                                interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
                        }
-                       pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
+                       bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
 
                        iter = NULL;
                        j = 0;
@@ -2012,6 +2256,14 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                }
        }
 
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
+       pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
+       mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
+       g_free (bitmap);
+#else
+       pvt->interface_bitmap = bitmap;
+#endif
        return pvt;
 }
 
@@ -2128,13 +2380,16 @@ copy_remote_class_key (MonoDomain *domain, gpointer *key)
  * @class_name: name of the remote class
  *
  * Creates and initializes a MonoRemoteClass object for a remote type. 
- * 
+ *
+ * Can raise an exception on failure. 
  */
 MonoRemoteClass*
 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
 {
+       MonoError error;
        MonoRemoteClass *rc;
        gpointer* key, *mp_key;
+       char *name;
        
        key = create_remote_class_key (NULL, proxy_class);
        
@@ -2147,24 +2402,31 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
                return rc;
        }
 
+       name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
+       if (!mono_error_ok (&error)) {
+               g_free (key);
+               mono_domain_unlock (domain);
+               mono_error_raise_exception (&error);
+       }
+
        mp_key = copy_remote_class_key (domain, key);
        g_free (key);
        key = mp_key;
 
        if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
                rc->interface_count = 1;
                rc->interfaces [0] = proxy_class;
                rc->proxy_class = mono_defaults.marshalbyrefobject_class;
        } else {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
                rc->interface_count = 0;
                rc->proxy_class = proxy_class;
        }
        
        rc->default_vtable = NULL;
        rc->xdomain_vtable = NULL;
-       rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
+       rc->proxy_class_name = name;
        mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
 
        g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
@@ -2196,7 +2458,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 
        if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i,j;
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
                rc->proxy_class = remote_class->proxy_class;
                rc->interface_count = remote_class->interface_count + 1;
                
@@ -2211,7 +2473,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
                        rc->interfaces [j] = extra_class;
        } else {
                // Replace the old class. The interface array is the same
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
                rc->proxy_class = extra_class;
                rc->interface_count = remote_class->interface_count;
                if (rc->interface_count > 0)
@@ -2230,11 +2492,13 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 gpointer
 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
 {
+       mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
        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);
+               mono_loader_unlock ();
                return remote_class->xdomain_vtable;
        }
        if (remote_class->default_vtable == NULL) {
@@ -2249,6 +2513,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
        }
        
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
        return remote_class->default_vtable;
 }
 
@@ -2269,6 +2534,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
        MonoRemoteClass *remote_class;
        gboolean redo_vtable;
 
+       mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
        mono_domain_lock (domain);
 
        tproxy = (MonoTransparentProxy*) proxy_object;
@@ -2291,6 +2557,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
        }
        
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
 }
 
 
@@ -2338,8 +2605,12 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
        /* check method->slot is a valid index: perform isinstance? */
        if (method->slot != -1) {
                if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                       if (!is_proxy)
-                               res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
+                       if (!is_proxy) {
+                               gboolean variance_used = FALSE;
+                               int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
+                               g_assert (iface_offset > 0);
+                               res = vtable [iface_offset + method->slot];
+                       }
                } else {
                        res = vtable [method->slot];
                }
@@ -2353,8 +2624,14 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
                /* generic methods demand invoke_with_check */
                if (mono_method_signature (res)->generic_param_count)
                        res = mono_marshal_get_remoting_invoke_with_check (res);
-               else
-                       res = mono_marshal_get_remoting_invoke (res);
+               else {
+#ifndef DISABLE_COM
+                       if (klass == mono_defaults.com_object_class || klass->is_com_object)
+                               res = mono_cominterop_get_invoke (res);
+                       else
+#endif
+                               res = mono_marshal_get_remoting_invoke (res);
+               }
        } else {
                if (method->is_inflated) {
                        /* Have to inflate the result */
@@ -2413,10 +2690,20 @@ static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
 MonoObject*
 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
+       MonoObject *result;
+
        if (mono_runtime_get_no_exec ())
                g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
 
-       return default_mono_runtime_invoke (method, obj, params, exc);
+       if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+               mono_profiler_method_start_invoke (method);
+
+       result = default_mono_runtime_invoke (method, obj, params, exc);
+
+       if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
+               mono_profiler_method_end_invoke (method);
+
+       return result;
 }
 
 /**
@@ -2481,6 +2768,8 @@ set_value (MonoType *type, void *dest, void *value, int deref_pointer)
 {
        int t;
        if (type->byref) {
+               /* object fields cannot be byref, so we don't need a
+                  wbarrier here */
                gpointer *p = (gpointer*)dest;
                *p = value;
                return;
@@ -2551,12 +2840,12 @@ handle_enum:
                        t = mono_class_enum_basetype (type->data.klass)->type;
                        goto handle_enum;
                } else {
-                       int size;
-                       size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
+                       MonoClass *class = mono_class_from_mono_type (type);
+                       int size = mono_class_value_size (class, NULL);
                        if (value == NULL)
                                memset (dest, 0, size);
                        else
-                               memcpy (dest, value, size);
+                               mono_gc_wbarrier_value_copy (dest, value, 1, class);
                }
                return;
        case MONO_TYPE_GENERICINST:
@@ -2609,8 +2898,14 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
        g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
        /* you cant set a constant! */
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
-       
-       dest = (char*)vt->data + field->offset;
+
+       if (field->offset == -1) {
+               /* Special static */
+               gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+               dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+       } else {
+               dest = (char*)vt->data + field->offset;
+       }
        set_value (field->type, dest, value, FALSE);
 }
 
@@ -2621,6 +2916,26 @@ mono_vtable_get_static_field_data (MonoVTable *vt)
        return vt->data;
 }
 
+static guint8*
+mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
+{
+       guint8 *src;
+
+       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+               if (field->offset == -1) {
+                       /* Special static */
+                       gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+                       src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+               } else {
+                       src = (guint8*)vt->data + field->offset;
+               }
+       } else {
+               src = (guint8*)obj + field->offset;
+       }
+
+       return src;
+}
+
 /**
  * mono_field_get_value:
  * @obj: Object instance
@@ -2643,6 +2958,8 @@ mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
 {
        void *src;
 
+       g_assert (obj);
+
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
 
        src = (char*)obj + field->offset;
@@ -2668,6 +2985,7 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
        gchar *v;
        gboolean is_static = FALSE;
        gboolean is_ref = FALSE;
+       gboolean is_literal = FALSE;
 
        switch (field->type->type) {
        case MONO_TYPE_STRING:
@@ -2695,7 +3013,7 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
                is_ref = field->type->byref;
                break;
        case MONO_TYPE_GENERICINST:
-               is_ref = !field->type->data.generic_class->container_class->valuetype;
+               is_ref = !mono_type_generic_inst_is_valuetype (field->type);
                break;
        default:
                g_error ("type 0x%x not handled in "
@@ -2703,15 +3021,32 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
                return NULL;
        }
 
+       if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
+               is_literal = TRUE;
+
        if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
                is_static = TRUE;
-               vtable = mono_class_vtable (domain, field->parent);
-               if (!vtable->initialized)
-                       mono_runtime_class_init (vtable);
+
+               if (!is_literal) {
+                       vtable = mono_class_vtable (domain, field->parent);
+                       if (!vtable) {
+                               char *name = mono_type_get_full_name (field->parent);
+                               /*FIXME extend this to use the MonoError api*/
+                               g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
+                               g_free (name);
+                               return NULL;
+                       }
+                       if (!vtable->initialized)
+                               mono_runtime_class_init (vtable);
+               }
+       } else {
+               g_assert (obj);
        }
        
        if (is_ref) {
-               if (is_static) {
+               if (is_literal) {
+                       get_default_field_value (domain, field, &o);
+               } else if (is_static) {
                        mono_field_static_get_value (vtable, field, &o);
                } else {
                        mono_field_get_value (obj, field, &o);
@@ -2721,9 +3056,16 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
 
        /* boxed value type */
        klass = mono_class_from_mono_type (field->type);
+
+       if (mono_class_is_nullable (klass))
+               return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
+
        o = mono_object_new (domain, klass);
        v = ((gchar *) o) + sizeof (MonoObject);
-       if (is_static) {
+
+       if (is_literal) {
+               get_default_field_value (domain, field, v);
+       } else if (is_static) {
                mono_field_static_get_value (vtable, field, v);
        } else {
                mono_field_get_value (obj, field, v);
@@ -2815,7 +3157,13 @@ mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
                return;
        }
 
-       src = (char*)vt->data + field->offset;
+       if (field->offset == -1) {
+               /* Special static */
+               gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
+               src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
+       } else {
+               src = (char*)vt->data + field->offset;
+       }
        set_value (field->type, value, src, TRUE);
 }
 
@@ -2886,10 +3234,14 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
        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
+       if (value) {
+               if (param_class->has_references)
+                       mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
+               else
+                       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));
+       }
 }
 
 /**
@@ -2910,7 +3262,10 @@ mono_nullable_box (guint8 *buf, MonoClass *klass)
 
        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));
+               if (param_class->has_references)
+                       mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
+               else
+                       memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
                return o;
        }
        else
@@ -2928,6 +3283,10 @@ mono_get_delegate_invoke (MonoClass *klass)
 {
        MonoMethod *im;
 
+       /* This is called at runtime, so avoid the slower search in metadata */
+       mono_class_setup_methods (klass);
+       if (klass->exception_type)
+               return NULL;
        im = mono_class_get_method_from_name (klass, "Invoke", -1);
        g_assert (im);
 
@@ -3106,6 +3465,130 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        return result;
 }
 
+static MonoObject*
+serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *serialize_method;
+
+       void *params [1];
+       MonoObject *array;
+
+       if (!serialize_method) {
+               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+               serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
+       }
+
+       if (!serialize_method) {
+               *failure = TRUE;
+               return NULL;
+       }
+
+       g_assert (!mono_object_class (obj)->marshalbyref);
+
+       params [0] = obj;
+       *exc = NULL;
+       array = mono_runtime_invoke (serialize_method, NULL, params, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return array;
+}
+
+static MonoObject*
+deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *deserialize_method;
+
+       void *params [1];
+       MonoObject *result;
+
+       if (!deserialize_method) {
+               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+               deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+       }
+       if (!deserialize_method) {
+               *failure = TRUE;
+               return NULL;
+       }
+
+       params [0] = obj;
+       *exc = NULL;
+       result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return result;
+}
+
+static MonoObject*
+make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *get_proxy_method;
+
+       MonoDomain *domain = mono_domain_get ();
+       MonoRealProxy *real_proxy;
+       MonoReflectionType *reflection_type;
+       MonoTransparentProxy *transparent_proxy;
+
+       if (!get_proxy_method)
+               get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+       g_assert (obj->vtable->klass->marshalbyref);
+
+       real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
+       reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+
+       MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
+       MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
+
+       *exc = NULL;
+       transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return (MonoObject*) transparent_proxy;
+}
+
+/**
+ * mono_object_xdomain_representation
+ * @obj: an object
+ * @target_domain: a domain
+ * @exc: pointer to a MonoObject*
+ *
+ * Creates a representation of obj in the domain target_domain.  This
+ * is either a copy of obj arrived through via serialization and
+ * deserialization or a proxy, depending on whether the object is
+ * serializable or marshal by ref.  obj must not be in target_domain.
+ *
+ * If the object cannot be represented in target_domain, NULL is
+ * returned and *exc is set to an appropriate exception.
+ */
+MonoObject*
+mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
+{
+       MonoObject *deserialized = NULL;
+       gboolean failure = FALSE;
+
+       *exc = NULL;
+
+       if (mono_object_class (obj)->marshalbyref) {
+               deserialized = make_transparent_proxy (obj, &failure, exc);
+       } else {
+               MonoDomain *domain = mono_domain_get ();
+               MonoObject *serialized;
+
+               mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
+               serialized = serialize_object (obj, &failure, exc);
+               mono_domain_set_internal_with_options (target_domain, FALSE);
+               if (!failure)
+                       deserialized = deserialize_object (serialized, &failure, exc);
+               if (domain != target_domain)
+                       mono_domain_set_internal_with_options (domain, FALSE);
+       }
+
+       return deserialized;
+}
+
 /* Used in call_unhandled_exception_delegate */
 static MonoObject *
 create_unhandled_exception_eventargs (MonoObject *exc)
@@ -3139,15 +3622,48 @@ static void
 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
        MonoObject *e = NULL;
        gpointer pa [2];
+       MonoDomain *current_domain = mono_domain_get ();
+
+       if (domain != current_domain)
+               mono_domain_set_internal_with_options (domain, FALSE);
+
+       g_assert (domain == mono_object_domain (domain->domain));
+
+       if (mono_object_domain (exc) != domain) {
+               MonoObject *serialization_exc;
+
+               exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
+               if (!exc) {
+                       if (serialization_exc) {
+                               MonoObject *dummy;
+                               exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
+                               g_assert (exc);
+                       } else {
+                               exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
+                                               "System.Runtime.Serialization", "SerializationException",
+                                               "Could not serialize unhandled exception.");
+                       }
+               }
+       }
+       g_assert (mono_object_domain (exc) == domain);
 
        pa [0] = domain->domain;
        pa [1] = create_unhandled_exception_eventargs (exc);
        mono_runtime_delegate_invoke (delegate, pa, &e);
-       
+
+       if (domain != current_domain)
+               mono_domain_set_internal_with_options (current_domain, FALSE);
+
        if (e) {
-               gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
-               g_warning ("exception inside UnhandledException handler: %s\n", msg);
-               g_free (msg);
+               MonoError error;
+               gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
+               if (!mono_error_ok (&error)) {
+                       g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
+                       mono_error_cleanup (&error);
+               } else {
+                       g_warning ("exception inside UnhandledException handler: %s\n", msg);
+                       g_free (msg);
+               }
        }
 }
 
@@ -3204,10 +3720,10 @@ mono_unhandled_exception (MonoObject *exc)
        g_assert (field);
 
        if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
-               gboolean abort_process = (mono_thread_current () == main_thread) ||
+               gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
                                (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
                root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
-               if (current_domain != root_domain && (mono_framework_version () >= 2)) {
+               if (current_domain != root_domain) {
                        current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
                } else {
                        current_appdomain_delegate = NULL;
@@ -3229,7 +3745,12 @@ mono_unhandled_exception (MonoObject *exc)
        }
 }
 
-/*
+/**
+ * mono_runtime_exec_managed_code:
+ * @domain: Application domain
+ * @main_func: function to invoke from the execution thread
+ * @main_args: parameter to the main_func
+ *
  * Launch a new thread to execute a function
  *
  * main_func is called back from the thread with main_args as the
@@ -3262,7 +3783,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        int rval;
        MonoCustomAttrInfo* cinfo;
        gboolean has_stathread_attribute;
-       MonoThread* thread = mono_thread_current ();
+       MonoInternalThread* thread = mono_thread_internal_current ();
 
        g_assert (args);
 
@@ -3301,8 +3822,6 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        }
        if (has_stathread_attribute) {
                thread->apartment_state = ThreadApartmentState_STA;
-       } else if (mono_framework_version () == 1) {
-               thread->apartment_state = ThreadApartmentState_Unknown;
        } else {
                thread->apartment_state = ThreadApartmentState_MTA;
        }
@@ -3465,8 +3984,21 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                                else
                                        t = &t->data.generic_class->container_class->byval_arg;
                                goto again;
+                       case MONO_TYPE_PTR: {
+                               MonoObject *arg;
+
+                               /* The argument should be an IntPtr */
+                               arg = mono_array_get (params, MonoObject*, i);
+                               if (arg == NULL) {
+                                       pa [i] = NULL;
+                               } else {
+                                       g_assert (arg->vtable->klass == mono_defaults.int_class);
+                                       pa [i] = ((MonoIntPtr*)arg)->m_value;
+                               }
+                               break;
+                       }
                        default:
-                               g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+                               g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
                        }
                }
        }
@@ -3486,6 +4018,7 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 
                if (!obj) {
                        obj = mono_object_new (mono_domain_get (), method->klass);
+                       g_assert (obj); /*maybe we should raise a TLE instead?*/
                        if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
                                method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
                        }
@@ -3513,6 +4046,27 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                /* obj must be already unboxed if needed */
                res = mono_runtime_invoke (method, obj, pa, exc);
 
+               if (sig->ret->type == MONO_TYPE_PTR) {
+                       MonoClass *pointer_class;
+                       static MonoMethod *box_method;
+                       void *box_args [2];
+                       MonoObject *box_exc;
+
+                       /* 
+                        * The runtime-invoke wrapper returns a boxed IntPtr, need to 
+                        * convert it to a Pointer object.
+                        */
+                       pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+                       if (!box_method)
+                               box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
+
+                       g_assert (res->vtable->klass == mono_defaults.int_class);
+                       box_args [0] = ((MonoIntPtr*)res)->m_value;
+                       box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
+                       res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
+                       g_assert (!box_exc);
+               }
+
                if (has_byref_nullables) {
                        /* 
                         * The runtime invoke wrapper already converted byref nullables back,
@@ -3590,12 +4144,19 @@ mono_object_allocate_spec (size_t size, MonoVTable *vtable)
  * looked up using @klass.   This will not invoke any constructors, 
  * so the consumer of this routine has to invoke any constructors on
  * its own to initialize the object.
+ * 
+ * It returns NULL on failure.
  */
 MonoObject *
 mono_object_new (MonoDomain *domain, MonoClass *klass)
 {
+       MonoVTable *vtable;
+
        MONO_ARCH_SAVE_REGS;
-       return mono_object_new_specific (mono_class_vtable (domain, klass));
+       vtable = mono_class_vtable (domain, klass);
+       if (!vtable)
+               return NULL;
+       return mono_object_new_specific (vtable);
 }
 
 /**
@@ -3777,17 +4338,17 @@ MonoObject *
 mono_object_clone (MonoObject *obj)
 {
        MonoObject *o;
-       int size;
+       int size = obj->vtable->klass->instance_size;
 
-       size = obj->vtable->klass->instance_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));
 
-#ifdef HAVE_SGEN_GC
-       if (obj->vtable->klass->has_references)
-               mono_gc_wbarrier_object (o);
-#endif
+       if (obj->vtable->klass->has_references) {
+               mono_gc_wbarrier_object_copy (o, obj);
+       } else {
+               int size = obj->vtable->klass->instance_size;
+               /* do not copy the sync state */
+               memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
+       }
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, obj->vtable->klass);
 
@@ -3806,7 +4367,7 @@ mono_object_clone (MonoObject *obj)
 void
 mono_array_full_copy (MonoArray *src, MonoArray *dest)
 {
-       mono_array_size_t size;
+       uintptr_t size;
        MonoClass *klass = src->obj.vtable->klass;
 
        MONO_ARCH_SAVE_REGS;
@@ -3842,8 +4403,8 @@ MonoArray*
 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
 {
        MonoArray *o;
-       mono_array_size_t size, i;
-       mono_array_size_t *sizes;
+       uintptr_t size, i;
+       uintptr_t *sizes;
        MonoClass *klass = array->obj.vtable->klass;
 
        MONO_ARCH_SAVE_REGS;
@@ -3868,14 +4429,14 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
                return o;
        }
        
-       sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
+       sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
        size = mono_array_element_size (klass);
        for (i = 0; i < klass->rank; ++i) {
                sizes [i] = array->bounds [i].length;
                size *= array->bounds [i].length;
                sizes [i + klass->rank] = array->bounds [i].lower_bound;
        }
-       o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
+       o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
 #ifdef HAVE_SGEN_GC
        if (klass->element_class->valuetype) {
                if (klass->element_class->has_references)
@@ -3923,6 +4484,24 @@ mono_array_clone (MonoArray *array)
                                         ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
 #endif
 
+gboolean
+mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
+{
+       uintptr_t byte_len;
+
+       byte_len = mono_array_element_size (class);
+       if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+               return FALSE;
+       byte_len *= len;
+       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
+               return FALSE;
+       byte_len += sizeof (MonoArray);
+
+       *res = byte_len;
+
+       return TRUE;
+}
+
 /**
  * mono_array_new_full:
  * @domain: domain where the object is created
@@ -3934,18 +4513,18 @@ mono_array_clone (MonoArray *array)
  * lower bounds and type.
  */
 MonoArray*
-mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
+mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
 {
-       mono_array_size_t byte_len, len, bounds_size;
+       uintptr_t byte_len, len, bounds_size;
        MonoObject *o;
        MonoArray *array;
+       MonoArrayBounds *bounds;
        MonoVTable *vtable;
        int i;
 
        if (!array_class->inited)
                mono_class_init (array_class);
 
-       byte_len = mono_array_element_size (array_class);
        len = 1;
 
        /* A single dimensional array with a 0 lower bound is the same as an szarray */
@@ -3966,12 +4545,9 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
                }
        }
 
-       if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+       if (!mono_array_calc_byte_len (array_class, len, &byte_len))
                mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-       byte_len *= len;
-       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
-               mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-       byte_len += sizeof (MonoArray);
+
        if (bounds_size) {
                /* align */
                if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
@@ -3985,7 +4561,8 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
         */
-       vtable = mono_class_vtable (domain, array_class);
+       vtable = mono_class_vtable_full (domain, array_class, TRUE);
+#ifndef HAVE_SGEN_GC
        if (!array_class->has_references) {
                o = mono_object_allocate_ptrfree (byte_len, vtable);
 #if NEED_TO_ZERO_PTRFREE
@@ -4001,8 +4578,21 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
        array->max_length = len;
 
        if (bounds_size) {
-               MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
+               bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
                array->bounds = bounds;
+       }
+#else
+       if (bounds_size)
+               o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
+       else
+               o = mono_gc_alloc_vector (vtable, byte_len, len);
+       array = (MonoArray*)o;
+       mono_stats.new_object_count++;
+
+       bounds = array->bounds;
+#endif
+
+       if (bounds_size) {
                for (i = 0; i < array_class->rank; ++i) {
                        bounds [i].length = lengths [i];
                        if (lower_bounds)
@@ -4025,7 +4615,7 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
  * This routine creates a new szarray with @n elements of type @eclass.
  */
 MonoArray *
-mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
+mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
 {
        MonoClass *ac;
 
@@ -4034,7 +4624,7 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
        ac = mono_array_class_get (eclass, 1);
        g_assert (ac);
 
-       return mono_array_new_specific (mono_class_vtable (domain, ac), n);
+       return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
 }
 
 /**
@@ -4046,11 +4636,11 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
  * can be sure about the domain it operates in.
  */
 MonoArray *
-mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
+mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
 {
        MonoObject *o;
        MonoArray *ao;
-       guint32 byte_len, elem_size;
+       uintptr_t byte_len;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -4058,18 +4648,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
                arith_overflow ();
                return NULL;
        }
-       
-       elem_size = mono_array_element_size (vtable->klass);
-       if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
-               mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-               return NULL;
-       }
-       byte_len = n * elem_size;
-       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
+
+       if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
                mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
                return NULL;
        }
-       byte_len += sizeof (MonoArray);
+#ifndef HAVE_SGEN_GC
        if (!vtable->klass->has_references) {
                o = mono_object_allocate_ptrfree (byte_len, vtable);
 #if NEED_TO_ZERO_PTRFREE
@@ -4085,6 +4669,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
 
        ao = (MonoArray *)o;
        ao->max_length = n;
+#else
+       o = mono_gc_alloc_vector (vtable, byte_len, n);
+       ao = (MonoArray*)o;
+       mono_stats.new_object_count++;
+#endif
+
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, vtable->klass);
 
@@ -4130,10 +4720,15 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
                mono_gc_out_of_memory (-1);
 
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
+       g_assert (vtable);
 
+#ifndef HAVE_SGEN_GC
        s = mono_object_allocate_ptrfree (size, vtable);
 
        s->length = len;
+#else
+       s = mono_gc_alloc_string (vtable, size, len);
+#endif
 #if NEED_TO_ZERO_PTRFREE
        s->chars [len] = 0;
 #endif
@@ -4255,6 +4850,8 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
                return mono_nullable_box (value, class);
 
        vtable = mono_class_vtable (domain, class);
+       if (!vtable)
+               return NULL;
        size = mono_class_instance_size (class);
        res = mono_object_new_alloc_specific (vtable);
        if (G_UNLIKELY (profile_allocs))
@@ -4263,9 +4860,9 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        size = size - sizeof (MonoObject);
 
 #ifdef HAVE_SGEN_GC
+       g_assert (size == mono_class_value_size (class, NULL));
        mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
-#endif
-
+#else
 #if NO_UNALIGNED_ACCESS
        memcpy ((char *)res + sizeof (MonoObject), value, size);
 #else
@@ -4285,6 +4882,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        default:
                memcpy ((char *)res + sizeof (MonoObject), value, size);
        }
+#endif
 #endif
        if (class->has_finalize)
                mono_object_register_finalizer (res);
@@ -4303,9 +4901,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 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);
 }
 
 /*
@@ -4324,8 +4920,8 @@ 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);
+       g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
        mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
-       memmove (d, src, size * count);
 }
 
 /**
@@ -4407,7 +5003,7 @@ mono_object_isinst (MonoObject *obj, MonoClass *klass)
        if (!klass->inited)
                mono_class_init (klass);
 
-       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
+       if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
                return mono_object_isinst_mbyref (obj, klass);
 
        if (!obj)
@@ -4430,6 +5026,10 @@ mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
                if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
                        return obj;
                }
+
+               /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
+               if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
+                       return obj;
        } else {
                MonoClass *oklass = vt->klass;
                if ((oklass == mono_defaults.transparent_proxy_class))
@@ -4598,10 +5198,14 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
 {
        MONO_ARCH_SAVE_REGS;
 
-       if (image->dynamic)
-               return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
-       else
+       if (image->dynamic) {
+               MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
+               return str;
+       } else {
+               if (!mono_verifier_verify_string_signature (image, idx, NULL))
+                       return NULL; /*FIXME we should probably be raising an exception here*/
                return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
+       }
 }
 
 /**
@@ -4617,7 +5221,7 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
        const char *str = sig;
        MonoString *o, *interned;
        size_t len2;
-       
+
        len2 = mono_metadata_decode_blob_size (str, &str);
        len2 >>= 1;
 
@@ -4652,13 +5256,28 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
  *
  * Return the UTF8 representation for @s.
  * the resulting buffer nedds to be freed with g_free().
+ *
+ * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
  */
 char *
 mono_string_to_utf8 (MonoString *s)
+{
+       MonoError error;
+       char *result = mono_string_to_utf8_checked (s, &error);
+       
+       if (!mono_error_ok (&error))
+               mono_error_raise_exception (&error);
+       return result;
+}
+
+char *
+mono_string_to_utf8_checked (MonoString *s, MonoError *error)
 {
        long written = 0;
        char *as;
-       GError *error = NULL;
+       GError *gerror = NULL;
+
+       mono_error_init (error);
 
        if (s == NULL)
                return NULL;
@@ -4666,11 +5285,11 @@ mono_string_to_utf8 (MonoString *s)
        if (!s->length)
                return g_strdup ("");
 
-       as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
-       if (error) {
-               MonoException *exc = mono_get_exception_argument ("string", error->message);
-               g_error_free (error);
-               mono_raise_exception(exc);
+       as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
+       if (gerror) {
+               mono_error_set_argument (error, "string", "%s", gerror->message);
+               g_error_free (gerror);
+               return NULL;
        }
        /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
        if (s->length > written) {
@@ -4693,7 +5312,7 @@ mono_string_to_utf8 (MonoString *s)
  * This is a temporary helper until our string implementation
  * is reworked to always include the null terminating char.
  */
-gunichar2 *
+mono_unichar2*
 mono_string_to_utf16 (MonoString *s)
 {
        char *as;
@@ -4737,23 +5356,23 @@ mono_string_from_utf16 (gunichar2 *data)
 
 
 static char *
-mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
+mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
 {
        char *r;
        char *mp_s;
        int len;
 
-       if (!mp && !image)
-               return mono_string_to_utf8 (s);
-
-       r = mono_string_to_utf8 (s);
-       if (!r)
+       r = mono_string_to_utf8_checked (s, error);
+       if (!mono_error_ok (error))
                return NULL;
 
+       if (!mp && !image)
+               return r;
+
        len = strlen (r) + 1;
        if (mp)
                mp_s = mono_mempool_alloc (mp, len);
-       else if (image)
+       else
                mp_s = mono_image_alloc (image, len);
 
        memcpy (mp_s, r, len);
@@ -4770,9 +5389,9 @@ mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
  */
 char *
-mono_string_to_utf8_image (MonoImage *image, MonoString *s)
+mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
 {
-       return mono_string_to_utf8_internal (NULL, image, s);
+       return mono_string_to_utf8_internal (NULL, image, s, error);
 }
 
 /**
@@ -4782,9 +5401,9 @@ mono_string_to_utf8_image (MonoImage *image, MonoString *s)
  * Same as mono_string_to_utf8, but allocate the string from a mempool.
  */
 char *
-mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
 {
-       return mono_string_to_utf8_internal (mp, NULL, s);
+       return mono_string_to_utf8_internal (mp, NULL, s, error);
 }
 
 static void
@@ -4826,8 +5445,11 @@ mono_raise_exception (MonoException *ex)
         * will point into the next function in the executable, not this one.
         */
 
-       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
-               MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
+       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
+               MonoInternalThread *thread = mono_thread_internal_current ();
+               g_assert (ex->object.vtable->domain == mono_domain_get ());
+               MONO_OBJECT_SETREF (thread, abort_exc, ex);
+       }
        
        ex_handler (ex);
 }
@@ -4846,11 +5468,11 @@ mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
        gpointer params [1];
        static MonoMethod *handle_set;
 
-       res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
+       res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
 
        /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
        if (!handle_set)
-               handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
+               handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
 
        params [0] = &handle;
        mono_runtime_invoke (handle_set, res, params, NULL);
@@ -4865,8 +5487,8 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle)
        static MonoClassField *f_safe_handle;
 
        if (!f_os_handle && !f_safe_handle) {
-               f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
-               f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
+               f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
+               f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
        }
 
        if (f_os_handle) {
@@ -4880,6 +5502,26 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle)
        }
 }
 
+
+static MonoObject*
+mono_runtime_capture_context (MonoDomain *domain)
+{
+       RuntimeInvokeFunction runtime_invoke;
+
+       if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
+               MonoMethod *method = mono_get_context_capture_method ();
+               MonoMethod *wrapper;
+               if (!method)
+                       return NULL;
+               wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
+               domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
+               domain->capture_context_method = mono_compile_method (method);
+       }
+
+       runtime_invoke = domain->capture_context_runtime_invoke;
+
+       return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+}
 /**
  * mono_async_result_new:
  * @domain:domain where the object will be created.
@@ -4895,11 +5537,10 @@ MonoAsyncResult *
 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
 {
        MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
-       MonoMethod *method = mono_get_context_capture_method ();
-
+       MonoObject *context = mono_runtime_capture_context (domain);
        /* we must capture the execution context from the original thread */
-       if (method) {
-               MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
+       if (context) {
+               MONO_OBJECT_SETREF (res, execution_context, context);
                /* note: result may be null if the flow is suppressed */
        }
 
@@ -5092,6 +5733,7 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
 void
 mono_print_unhandled_exception (MonoObject *exc)
 {
+       MonoError error;
        char *message = (char *) "";
        MonoString *str; 
        MonoMethod *method;
@@ -5111,8 +5753,13 @@ mono_print_unhandled_exception (MonoObject *exc)
 
                str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
                if (str) {
-                       message = mono_string_to_utf8 (str);
-                       free_message = TRUE;
+                       message = mono_string_to_utf8_checked (str, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_cleanup (&error);
+                               message = (char *)"";
+                       } else {
+                               free_message = TRUE;
+                       }
                }
        }                               
 
@@ -5158,7 +5805,7 @@ mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer a
                method = mono_marshal_get_remoting_invoke (method);
                delegate->method_ptr = mono_compile_method (method);
                MONO_OBJECT_SETREF (delegate, target, target);
-       } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
+       } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
                method = mono_marshal_get_unbox_wrapper (method);
                delegate->method_ptr = mono_compile_method (method);
                MONO_OBJECT_SETREF (delegate, target, target);
@@ -5282,42 +5929,22 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        arg = mono_array_get (out_args, gpointer, j);
                        type = pt->type;
 
-                       switch (type) {
-                       case MONO_TYPE_VOID:
-                               g_assert_not_reached ();
-                               break;
-                       case MONO_TYPE_U1:
-                       case MONO_TYPE_I1:
-                       case MONO_TYPE_BOOLEAN:
-                       case MONO_TYPE_U2:
-                       case MONO_TYPE_I2:
-                       case MONO_TYPE_CHAR:
-                       case MONO_TYPE_U4:
-                       case MONO_TYPE_I4:
-                       case MONO_TYPE_I8:
-                       case MONO_TYPE_U8:
-                       case MONO_TYPE_R4:
-                       case MONO_TYPE_R8:
-                       case MONO_TYPE_VALUETYPE: {
+                       g_assert (type != MONO_TYPE_VOID);
+
+                       if (MONO_TYPE_IS_REFERENCE (pt)) {
+                               mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
+                       } else {
                                if (arg) {
-                                       size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
-                                       memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
-                               }
-                               else {
+                                       MonoClass *class = ((MonoObject*)arg)->vtable->klass;
+                                       size = mono_class_value_size (class, NULL);
+                                       if (class->has_references)
+                                               mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
+                                       else
+                                               memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
+                               } else {
                                        size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
                                        memset (*((gpointer *)params [i]), 0, size);
                                }
-                               break;
-                       }
-                       case MONO_TYPE_STRING:
-                       case MONO_TYPE_CLASS: 
-                       case MONO_TYPE_ARRAY:
-                       case MONO_TYPE_SZARRAY:
-                       case MONO_TYPE_OBJECT:
-                               **((MonoObject ***)params [i]) = (MonoObject *)arg;
-                               break;
-                       default:
-                               g_assert_not_reached ();
                        }
 
                        j++;
@@ -5566,56 +6193,26 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
  * mono_create_ftnptr:
  *
  *   Given a function address, create a function descriptor for it.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
 {
-#ifdef __ia64__
-       gpointer *desc;
-
-       mono_domain_lock (domain);
-       desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
-       mono_domain_unlock (domain);
-
-       desc [0] = addr;
-       desc [1] = NULL;
-
-       return desc;
-#elif defined(__ppc64__) || defined(__powerpc64__)
-       gpointer *desc;
-
-       mono_domain_lock (domain);
-       desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
-       mono_domain_unlock (domain);
-
-       desc [0] = addr;
-       desc [1] = NULL;
-       desc [2] = NULL;
-
-       return desc;
-#else
-       return addr;
-#endif
+       return callbacks.create_ftnptr (domain, addr);
 }
 
 /*
  * mono_get_addr_from_ftnptr:
  *
  *   Given a pointer to a function descriptor, return the function address.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_get_addr_from_ftnptr (gpointer descr)
 {
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
-       return *(gpointer*)descr;
-#else
-       return descr;
-#endif
+       return callbacks.get_addr_from_ftnptr (descr);
 }      
 
-#if 0
 /**
  * mono_string_chars:
  * @s: a MonoString
@@ -5623,9 +6220,9 @@ mono_get_addr_from_ftnptr (gpointer descr)
  * Returns a pointer to the UCS16 characters stored in the MonoString
  */
 gunichar2 *
-mono_string_chars(MonoString *s)
+mono_string_chars (MonoString *s)
 {
-       /* This method is here only for documentation extraction, this is a macro */
+       return s->chars;
 }
 
 /**
@@ -5637,7 +6234,33 @@ mono_string_chars(MonoString *s)
 int
 mono_string_length (MonoString *s)
 {
-       /* This method is here only for documentation extraction, this is a macro */
+       return s->length;
+}
+
+/**
+ * mono_array_length:
+ * @array: a MonoArray*
+ *
+ * Returns the total number of elements in the array. This works for
+ * both vectors and multidimensional arrays.
+ */
+uintptr_t
+mono_array_length (MonoArray *array)
+{
+       return array->max_length;
+}
+
+/**
+ * mono_array_addr_with_size:
+ * @array: a MonoArray*
+ * @size: size of the array elements
+ * @idx: index into the array
+ *
+ * Returns the address of the @idx element in the array.
+ */
+char*
+mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
+{
+       return ((char*)(array)->vector) + size * idx;
 }
 
-#endif