2009-09-10 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mono / metadata / object.c
index 3152cc765dcd05d50d7c5e04d356e69ad08d2cfe..e0b30b70ed1d84e4bd24401ba2a4d4d233b03dc6 100644 (file)
@@ -5,9 +5,13 @@
  *   Miguel de Icaza (miguel@ximian.com)
  *   Paolo Molaro (lupus@ximian.com)
  *
- * (C) 2001-2004 Ximian, Inc.
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  */
 #include <config.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 #include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
@@ -35,6 +39,8 @@
 #include "mono/metadata/mono-debug-debugger.h"
 #include <mono/metadata/gc-internal.h>
 #include <mono/utils/strenc.h>
+#include <mono/utils/mono-counters.h>
+#include "cominterop.h"
 
 #ifdef HAVE_BOEHM_GC
 #define NEED_TO_ZERO_PTRFREE 1
@@ -69,12 +75,14 @@ static void
 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
 
 static MonoString*
-mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
 
 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
 static CRITICAL_SECTION ldstr_section;
 
+static gboolean profile_allocs = TRUE;
+
 void
 mono_runtime_object_init (MonoObject *this)
 {
@@ -134,6 +142,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
@@ -212,7 +223,6 @@ get_type_init_exception_for_vtable (MonoVTable *vtable)
 
        return ex;
 }
-
 /*
  * mono_runtime_class_init:
  * @vtable: vtable that needs to be initialized
@@ -221,6 +231,18 @@ get_type_init_exception_for_vtable (MonoVTable *vtable)
  */
 void
 mono_runtime_class_init (MonoVTable *vtable)
+{
+       mono_runtime_class_init_full (vtable, TRUE);
+}
+
+/*
+ * mono_runtime_class_init_full:
+ * @vtable that neeeds to be initialized
+ * @raise_exception is TRUE, exceptions are raised intead of returned 
+ * 
+ */
+MonoException *
+mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
 {
        MonoException *exc;
        MonoException *exc_to_throw;
@@ -231,7 +253,7 @@ mono_runtime_class_init (MonoVTable *vtable)
        MONO_ARCH_SAVE_REGS;
 
        if (vtable->initialized)
-               return;
+               return NULL;
 
        exc = NULL;
        klass = vtable->klass;
@@ -256,14 +278,15 @@ mono_runtime_class_init (MonoVTable *vtable)
                /* double check... */
                if (vtable->initialized) {
                        mono_type_initialization_unlock ();
-                       return;
+                       return NULL;
                }
                if (vtable->init_failed) {
                        mono_type_initialization_unlock ();
 
                        /* The type initialization already failed once, rethrow the same exception */
-                       mono_raise_exception (get_type_init_exception_for_vtable (vtable));
-                       return;
+                       if (raise_exception)
+                               mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+                       return get_type_init_exception_for_vtable (vtable);
                }                       
                lock = g_hash_table_lookup (type_initialization_hash, vtable);
                if (lock == NULL) {
@@ -274,7 +297,9 @@ mono_runtime_class_init (MonoVTable *vtable)
                                if (!mono_domain_set (domain, FALSE)) {
                                        vtable->initialized = 1;
                                        mono_type_initialization_unlock ();
-                                       mono_raise_exception (mono_get_exception_appdomain_unloaded ());
+                                       if (raise_exception)
+                                               mono_raise_exception (mono_get_exception_appdomain_unloaded ());
+                                       return mono_get_exception_appdomain_unloaded ();
                                }
                        }
                        lock = g_malloc (sizeof(TypeInitializationLock));
@@ -292,7 +317,7 @@ mono_runtime_class_init (MonoVTable *vtable)
 
                        if (lock->initializing_tid == tid || lock->done) {
                                mono_type_initialization_unlock ();
-                               return;
+                               return NULL;
                        }
                        /* see if the thread doing the initialization is already blocked on this thread */
                        blocked = GUINT_TO_POINTER (lock->initializing_tid);
@@ -300,7 +325,7 @@ mono_runtime_class_init (MonoVTable *vtable)
                                if (pending_lock->initializing_tid == tid) {
                                        if (!pending_lock->done) {
                                                mono_type_initialization_unlock ();
-                                               return;
+                                               return NULL;
                                        } else {
                                                /* the thread doing the initialization is blocked on this thread,
                                                   but on a lock that has already been freed. It just hasn't got
@@ -370,12 +395,15 @@ mono_runtime_class_init (MonoVTable *vtable)
 
                if (vtable->init_failed) {
                        /* Either we were the initializing thread or we waited for the initialization */
-                       mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+                       if (raise_exception)
+                               mono_raise_exception (get_type_init_exception_for_vtable (vtable));
+                       return get_type_init_exception_for_vtable (vtable);
                }
        } else {
                vtable->initialized = 1;
-               return;
+               return NULL;
        }
+       return NULL;
 }
 
 static
@@ -426,7 +454,7 @@ default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sy
 }
 
 static gpointer
-default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
+default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
 {
        g_error ("remoting not installed");
        return NULL;
@@ -449,6 +477,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) 
 {
@@ -555,6 +595,8 @@ mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
        if (default_mono_free_method != NULL)
                default_mono_free_method (domain, method);
 
+       mono_method_clear_object (domain, method);
+
        mono_free_method (method);
 }
 
@@ -602,6 +644,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;
 
@@ -819,7 +865,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;
@@ -931,6 +977,22 @@ 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;
+}
+
+static gpointer vtable_trampoline = NULL;
+
+void
+mono_install_vtable_trampoline (gpointer tramp_code)
+{
+       vtable_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; \
@@ -951,17 +1013,22 @@ field_is_special_static (MonoClass *fklass, MonoClassField *field)
 }
 
 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
         * instantiations of the same generic interface.
+        * The code in build_imt_slots () depends on this.
         */
        if (method->is_inflated)
                method = ((MonoMethodInflated*)method)->declaring;
@@ -1028,10 +1095,10 @@ add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, gu
                /* we build just a single imt slot and this is not it */
                return;
        }
-       
-       entry = malloc (sizeof (MonoImtBuilderEntry));
-       entry->method = method;
-       entry->vtable_slot = vtable_slot;
+
+       entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
+       entry->key = method;
+       entry->value.vtable_slot = vtable_slot;
        entry->next = imt_builder [imt_slot];
        if (imt_builder [imt_slot] != NULL) {
                entry->children = imt_builder [imt_slot]->children + 1;
@@ -1073,7 +1140,7 @@ compare_imt_builder_entries (const void *p1, const void *p2) {
        MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
        MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
        
-       return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
+       return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
 }
 
 static int
@@ -1085,8 +1152,9 @@ imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *
                int i;
                for (i = start; i < end; ++i) {
                        MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
-                       item->method = sorted_array [i]->method;
-                       item->vtable_slot = sorted_array [i]->vtable_slot;
+                       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;
@@ -1098,7 +1166,7 @@ imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *
                int middle = start + count / 2;
                MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
 
-               item->method = sorted_array [middle]->method;
+               item->key = sorted_array [middle]->key;
                item->is_equals = FALSE;
                g_ptr_array_add (out_array, item);
                imt_emit_ir (sorted_array, start, middle, out_array);
@@ -1131,36 +1199,50 @@ 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->vtable_slot];
+                       return vtable->vtable [imt_builder_entry->value.vtable_slot];
                } else {
                        /* Collision, build the thunk */
                        GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
                        gpointer result;
                        int i;
-                       result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
+                       result = imt_thunk_builder (vtable, domain,
+                               (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;
 
 #if DEBUG_IMT
        printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
@@ -1169,9 +1251,25 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                MonoClass *iface = klass->interfaces_packed [i];
                int interface_offset = klass->interface_offsets_packed [i];
                int method_slot_in_interface;
-               mono_class_setup_methods (iface);
                for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
-                       MonoMethod *method = iface->methods [method_slot_in_interface];
+                       MonoMethod *method;
+
+                       if (slot_num >= 0 && iface->is_inflated) {
+                               /*
+                                * The imt slot of the method is the same as for its declaring method,
+                                * see the comment in mono_method_get_imt_slot (), so we can
+                                * avoid inflating methods which will be discarded by 
+                                * 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)
+                                       continue;
+                       }
+                       method = mono_class_get_method_by_index (iface, method_slot_in_interface);
+                       if (method->is_generic) {
+                               has_generic_virtual = TRUE;
+                               continue;
+                       }
                        add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
                }
        }
@@ -1181,9 +1279,8 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
                        MonoClass* iface = list_item->data;
                        int method_slot_in_interface;
-                       mono_class_setup_methods (iface);
                        for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
-                               MonoMethod *method = iface->methods [method_slot_in_interface];
+                               MonoMethod *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);
                        }
                        interface_offset += iface->method.count;
@@ -1191,10 +1288,39 @@ 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)
+                                               ;                                               
+                                       entry->next = imt_builder [i];
+                                       entries->children += imt_builder [i]->children + 1;
+                               }
+                               imt_builder [i] = entries;
+                       }
+
+                       if (has_generic_virtual) {
+                               /*
+                                * 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\n", i, imt [i]);
 #endif
@@ -1217,7 +1343,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;
                }
        }
@@ -1231,22 +1357,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
@@ -1255,6 +1365,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)
@@ -1268,11 +1380,284 @@ 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 ();
+}
+
+
+/*
+ * The first two free list entries both belong to the wait list: The
+ * first entry is the pointer to the head of the list and the second
+ * entry points to the last element.  That way appending and removing
+ * the first element are both O(1) operations.
+ */
+#define NUM_FREE_LISTS         12
+#define FIRST_FREE_LIST_SIZE   64
+#define MAX_WAIT_LENGTH        50
+#define THUNK_THRESHOLD                10
+
+/*
+ * LOCKING: The domain lock must be held.
+ */
+static void
+init_thunk_free_lists (MonoDomain *domain)
+{
+       if (domain->thunk_free_lists)
+               return;
+       domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
+}
+
+static int
+list_index_for_size (int item_size)
+{
+       int i = 2;
+       int size = FIRST_FREE_LIST_SIZE;
+
+       while (item_size > size && i < NUM_FREE_LISTS - 1) {
+               i++;
+               size <<= 1;
+       }
+
+       return i;
+}
+
+/**
+ * mono_method_alloc_generic_virtual_thunk:
+ * @domain: a domain
+ * @size: size in bytes
+ *
+ * Allocs size bytes to be used for the code of a generic virtual
+ * thunk.  It's either allocated from the domain's code manager or
+ * reused from a previously invalidated piece.
+ *
+ * LOCKING: The domain lock must be held.
+ */
+gpointer
+mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
+{
+       static gboolean inited = FALSE;
+       static int generic_virtual_thunks_size = 0;
+
+       guint32 *p;
+       int i;
+       MonoThunkFreeList **l;
+
+       init_thunk_free_lists (domain);
+
+       size += sizeof (guint32);
+       if (size < sizeof (MonoThunkFreeList))
+               size = sizeof (MonoThunkFreeList);
+
+       i = list_index_for_size (size);
+       for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
+               if ((*l)->size >= size) {
+                       MonoThunkFreeList *item = *l;
+                       *l = item->next;
+                       return ((guint32*)item) + 1;
+               }
+       }
+
+       /* no suitable item found - search lists of larger sizes */
+       while (++i < NUM_FREE_LISTS) {
+               MonoThunkFreeList *item = domain->thunk_free_lists [i];
+               if (!item)
+                       continue;
+               g_assert (item->size > size);
+               domain->thunk_free_lists [i] = item->next;
+               return ((guint32*)item) + 1;
+       }
+
+       /* still nothing found - allocate it */
+       if (!inited) {
+               mono_counters_register ("Generic virtual thunk bytes",
+                               MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
+               inited = TRUE;
+       }
+       generic_virtual_thunks_size += size;
+
+       p = mono_domain_code_reserve (domain, size);
+       *p = size;
+
+       return p + 1;
+}
+
+/*
+ * LOCKING: The domain lock must be held.
+ */
+static void
+invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
+{
+       guint32 *p = code;
+       MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
+
+       init_thunk_free_lists (domain);
+
+       while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
+               MonoThunkFreeList *item = domain->thunk_free_lists [0];
+               int length = item->length;
+               int i;
+
+               /* unlink the first item from the wait list */
+               domain->thunk_free_lists [0] = item->next;
+               domain->thunk_free_lists [0]->length = length - 1;
+
+               i = list_index_for_size (item->size);
+
+               /* put it in the free list */
+               item->next = domain->thunk_free_lists [i];
+               domain->thunk_free_lists [i] = item;
+       }
+
+       l->next = NULL;
+       if (domain->thunk_free_lists [1]) {
+               domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
+               domain->thunk_free_lists [0]->length++;
+       } else {
+               g_assert (!domain->thunk_free_lists [0]);
+
+               domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
+               domain->thunk_free_lists [0]->length = 1;
+       }
+}
+
+typedef struct _GenericVirtualCase {
+       MonoMethod *method;
+       gpointer code;
+       int count;
+       struct _GenericVirtualCase *next;
+} GenericVirtualCase;
+
+/*
+ * get_generic_virtual_entries:
+ *
+ *   Return IMT entries for the generic virtual method instances 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: 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
+ * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
+ * virtual method thunk.
+ */
+void
+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;
+
+       GenericVirtualCase *gvc, *list;
+       MonoImtBuilderEntry *entries;
+       int i;
+       GPtrArray *sorted;
+
+       mono_domain_lock (domain);
+       if (!domain->generic_virtual_cases)
+               domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
+
+       /* Check whether the case was already added */
+       list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+       gvc = list;
+       while (gvc) {
+               if (gvc->method == method)
+                       break;
+               gvc = gvc->next;
+       }
+
+       /* If not found, make a new one */
+       if (!gvc) {
+               gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
+               gvc->method = method;
+               gvc->code = code;
+               gvc->count = 0;
+               gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
+
+               g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
+
+               if (!inited) {
+                       mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
+                       inited = TRUE;
+               }
+               num_added++;
+       }
+
+       if (++gvc->count == THUNK_THRESHOLD) {
+               gpointer *old_thunk = *vtable_slot;
+
+               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);
+
+                       *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;
+                       }
+
+                       for (i = 0; i < sorted->len; ++i)
+                               g_free (g_ptr_array_index (sorted, i));
+                       g_ptr_array_free (sorted, TRUE);
+               }
+
+               if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
+                       invalidate_generic_virtual_thunk (domain, old_thunk);
+       }
+
+       mono_domain_unlock (domain);
 }
 
 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
@@ -1297,9 +1682,32 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
        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);
 }
 
+/**
+ * mono_class_try_get_vtable:
+ * @domain: the application domain
+ * @class: the class to initialize
+ *
+ * This function tries to get the associated vtable from @class if
+ * it was already created.
+ */
+MonoVTable *
+mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
+{
+       MonoClassRuntimeInfo *runtime_info;
+
+       g_assert (class);
+
+       runtime_info = class->runtime_info;
+       if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
+               return runtime_info->domain_vtables [domain->domain_id];
+       return NULL;
+}
+
 static MonoVTable *
 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 {
@@ -1311,20 +1719,22 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        int imt_table_bytes = 0;
        guint32 vtable_size, class_size;
        guint32 cindex;
-       guint32 constant_cols [MONO_CONSTANT_SIZE];
        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;
                        mono_domain_unlock (domain);
+                       mono_loader_unlock ();
                        exc = mono_class_get_exception_for_failure (class);
                        g_assert (exc);
                        mono_raise_exception (exc);
@@ -1342,11 +1752,12 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
 
        if (class->exception_type) {
                mono_domain_unlock (domain);
+               mono_loader_unlock ();
                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);
@@ -1355,12 +1766,12 @@ 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++;
        mono_stats.class_vtable_size += vtable_size;
-       interface_offsets = mono_mempool_alloc0 (domain->mp,  vtable_size);
+       interface_offsets = mono_domain_alloc0 (domain, vtable_size);
 
        if (ARCH_USE_IMT)
                vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
@@ -1384,7 +1795,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                 * vtable is reachable by other roots after the appdomain is unloaded.
                 */
 #ifdef HAVE_BOEHM_GC
-       if (domain != mono_get_root_domain ())
+       if (domain != mono_get_root_domain () && !mono_dont_free_domains)
                vt->gc_descr = GC_NO_DESCRIPTOR;
        else
 #endif
@@ -1399,13 +1810,13 @@ 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)
                                g_free (bitmap);
                } else {
-                       vt->data = mono_mempool_alloc0 (domain->mp, class_size);
+                       vt->data = mono_domain_alloc0 (domain, class_size);
                }
                mono_stats.class_static_data_size += class_size;
        }
@@ -1427,39 +1838,32 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                                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));
+                               /* 
+                                * This marks the field as special static to speed up the
+                                * checks in mono_field_static_get/set_value ().
+                                */
+                               field->offset = -1;
                                continue;
                        }
                }
                if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
                        MonoClass *fklass = mono_class_from_mono_type (field->type);
+                       const char *data = mono_field_get_data (field);
+
                        g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
                        t = (char*)vt->data + field->offset;
                        /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
-                       if (!field->data)
+                       if (!data)
                                continue;
                        if (fklass->valuetype) {
-                               memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+                               memcpy (t, data, mono_class_value_size (fklass, NULL));
                        } else {
                                /* it's a pointer type: add check */
                                g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
-                               *t = *(char *)field->data;
+                               *t = *(char *)data;
                        }
                        continue;
-               }
-               if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
-                       continue;
-
-               /* later do this only on demand if needed */
-               if (!field->data) {
-                       cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
-                       g_assert (cindex);
-                       g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
-
-                       mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
-                       field->def_type = constant_cols [MONO_CONSTANT_TYPE];
-                       field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
-               }
-               
+               }               
        }
 
        vt->max_interface_id = class->max_interface_id;
@@ -1485,7 +1889,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        /* 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 */
@@ -1504,7 +1908,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_mempool_alloc0 (class->image->mempool, 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) {
@@ -1515,7 +1919,6 @@ 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) {
@@ -1529,13 +1932,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] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
                }
        }
 
@@ -1551,6 +1949,7 @@ 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)) {
@@ -1632,20 +2031,20 @@ 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;
 
-       interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
+       interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
        if (ARCH_USE_IMT)
                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 */
@@ -1657,8 +2056,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                MonoMethod *cm;
                    
                if ((cm = class->vtable [i]))
-                       pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
-                               ? cm : arch_create_remoting_trampoline (cm, target_type);
+                       pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
                else
                        pvt->vtable [i] = NULL;
        }
@@ -1670,12 +2068,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        gpointer iter = NULL;
                        while ((m = mono_class_get_methods (k, &iter)))
                                if (!pvt->vtable [m->slot])
-                                       pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
+                                       pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
                }
        }
 
        pvt->max_interface_id = max_interface_id;
-       pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
+       pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
 
        if (! ARCH_USE_IMT) {
                /* initialize interface offsets */
@@ -1709,7 +2107,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        iter = NULL;
                        j = 0;
                        while ((cm = mono_class_get_methods (interf, &iter)))
-                               pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
+                               pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
                        
                        slot += mono_class_num_methods (interf);
                }
@@ -1823,13 +2221,13 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
 /**
  * copy_remote_class_key:
  *
- *   Make a copy of KEY in the mempool MP and return the copy.
+ *   Make a copy of KEY in the domain and return the copy.
  */
 static gpointer*
-copy_remote_class_key (MonoMemPool *mp, gpointer *key)
+copy_remote_class_key (MonoDomain *domain, gpointer *key)
 {
        int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
-       gpointer *mp_key = mono_mempool_alloc (mp, key_size);
+       gpointer *mp_key = mono_domain_alloc (domain, key_size);
 
        memcpy (mp_key, key, key_size);
 
@@ -1861,17 +2259,17 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
                return rc;
        }
 
-       mp_key = copy_remote_class_key (domain->mp, key);
+       mp_key = copy_remote_class_key (domain, key);
        g_free (key);
        key = mp_key;
 
        if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+               rc = 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_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
                rc->interface_count = 0;
                rc->proxy_class = proxy_class;
        }
@@ -1879,6 +2277,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        rc->default_vtable = NULL;
        rc->xdomain_vtable = NULL;
        rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
+       mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
 
        g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
 
@@ -1903,13 +2302,13 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
                return rc;
        }
 
-       mp_key = copy_remote_class_key (domain->mp, key);
+       mp_key = copy_remote_class_key (domain, key);
        g_free (key);
        key = mp_key;
 
        if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i,j;
-               rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+               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;
                
@@ -1924,7 +2323,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_mempool_alloc (domain->mp, 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)
@@ -1943,11 +2342,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) {
@@ -1962,6 +2363,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
        }
        
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
        return remote_class->default_vtable;
 }
 
@@ -1982,6 +2384,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;
@@ -2004,6 +2407,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
        }
        
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
 }
 
 
@@ -2037,22 +2441,27 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
        mono_class_setup_vtable (klass);
        vtable = klass->vtable;
 
-       /* check method->slot is a valid index: perform isinstance? */
-       if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               if (!is_proxy)
-                      res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
-       } else {
-               if (method->slot != -1) {
-                       res = vtable [method->slot];
+       if (method->slot == -1) {
+               /* method->slot might not be set for instances of generic methods */
+               if (method->is_inflated) {
+                       g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
+                       method->slot = ((MonoMethodInflated*)method)->declaring->slot; 
                } else {
-                       /* method->slot might not be set for instances of generic methods in the AOT case */
-                       if (method->is_inflated) {
-                               g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
-                               res = vtable [((MonoMethodInflated*)method)->declaring->slot];
-                       }
+                       if (!is_proxy)
+                               g_assert_not_reached ();
                }
        }
 
+       /* 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];
+               } else {
+                       res = vtable [method->slot];
+               }
+    }
+
        if (is_proxy) {
                /* It may be an interface, abstract class method or generic method */
                if (!res || mono_method_signature (res)->generic_param_count)
@@ -2061,10 +2470,16 @@ 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 && !res->is_inflated) {
+               if (method->is_inflated) {
                        /* Have to inflate the result */
                        res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
                }
@@ -2121,6 +2536,9 @@ static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
 MonoObject*
 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
+       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);
 }
 
@@ -2186,6 +2604,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;
@@ -2253,15 +2673,17 @@ handle_enum:
        case MONO_TYPE_VALUETYPE:
                /* note that 't' and 'type->type' can be different */
                if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
-                       t = type->data.klass->enum_basetype->type;
+                       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);
-                       if (value == 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
+                       } else {
                                memcpy (dest, value, size);
+                               mono_gc_wbarrier_value_copy (dest, value, size, class);
+                       }
                }
                return;
        case MONO_TYPE_GENERICINST:
@@ -2314,8 +2736,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);
 }
 
@@ -2470,7 +2898,7 @@ mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const
                readr8 (p, (double*) value);
                break;
        case MONO_TYPE_STRING:
-               *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
+               *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
                break;
        case MONO_TYPE_CLASS:
                *(gpointer*) value = NULL;
@@ -2485,8 +2913,11 @@ mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const
 static void
 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
 {
-       g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
-       mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
+       MonoTypeEnum def_type;
+       const char* data;
+       
+       data = mono_class_get_field_default_value (field, &def_type);
+       mono_get_constant_value_from_blob (domain, def_type, data, value);
 }
 
 /**
@@ -2517,7 +2948,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);
 }
 
@@ -2630,6 +3067,9 @@ 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);
+
        im = mono_class_get_method_from_name (klass, "Invoke", -1);
        g_assert (im);
 
@@ -2853,7 +3293,7 @@ call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, Mon
        }
 }
 
-static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
+static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
 
 /**
  * mono_runtime_unhandled_exception_policy_set:
@@ -2907,9 +3347,9 @@ mono_unhandled_exception (MonoObject *exc)
 
        if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
                gboolean abort_process = (mono_thread_current () == main_thread) ||
-                               (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
+                               (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_get_runtime_info ()->framework_version [0] >= '2')) {
+               if (current_domain != root_domain && (mono_framework_version () >= 2)) {
                        current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
                } else {
                        current_appdomain_delegate = NULL;
@@ -2977,11 +3417,17 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
 
                assembly = method->klass->image->assembly;
                domain->entry_assembly = assembly;
-               MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
+               /* Domains created from another domain already have application_base and configuration_file set */
+               if (domain->setup->application_base == NULL) {
+                       MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
+               }
 
-               str = g_strconcat (assembly->image->name, ".config", NULL);
-               MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
-               g_free (str);
+               if (domain->setup->configuration_file == NULL) {
+                       str = g_strconcat (assembly->image->name, ".config", NULL);
+                       MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
+                       g_free (str);
+                       mono_set_private_bin_path_from_config (domain);
+               }
        }
 
        cinfo = mono_custom_attrs_from_method (method);
@@ -2997,7 +3443,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        }
        if (has_stathread_attribute) {
                thread->apartment_state = ThreadApartmentState_STA;
-       } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
+       } else if (mono_framework_version () == 1) {
                thread->apartment_state = ThreadApartmentState_Unknown;
        } else {
                thread->apartment_state = ThreadApartmentState_MTA;
@@ -3092,7 +3538,9 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 {
        MonoMethodSignature *sig = mono_method_signature (method);
        gpointer *pa = NULL;
+       MonoObject *res;
        int i;
+       gboolean has_byref_nullables = FALSE;
 
        if (NULL != params) {
                pa = alloca (sizeof (gpointer) * mono_array_length (params));
@@ -3117,11 +3565,10 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
                                if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
-                                       if (t->byref)
-                                               /* FIXME: */
-                                               g_assert_not_reached ();
-                                       /* The runtime invoke wrapper needs the original boxed vtype */
+                                       /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
                                        pa [i] = mono_array_get (params, MonoObject*, i);
+                                       if (t->byref)
+                                               has_byref_nullables = TRUE;
                                } else {
                                        /* MS seems to create the objects if a null is passed in */
                                        if (!mono_array_get (params, MonoObject*, i))
@@ -3160,8 +3607,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);
                        }
                }
        }
@@ -3206,7 +3666,44 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                }
 
                /* obj must be already unboxed if needed */
-               return mono_runtime_invoke (method, obj, pa, exc);
+               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,
+                        * and stored them in pa, we just need to copy them back to the
+                        * managed array.
+                        */
+                       for (i = 0; i < mono_array_length (params); i++) {
+                               MonoType *t = sig->params [i];
+
+                               if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
+                                       mono_array_setref (params, i, pa [i]);
+                       }
+               }
+
+               return res;
        }
 }
 
@@ -3330,10 +3827,11 @@ mono_object_new_alloc_specific (MonoVTable *vtable)
 /*             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
                o = mono_object_allocate (vtable->klass->instance_size, vtable);
        }
-       if (vtable->klass->has_finalize)
+       if (G_UNLIKELY (vtable->klass->has_finalize))
                mono_object_register_finalizer (o);
        
-       mono_profiler_allocation (o, vtable->klass);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation (o, vtable->klass);
        return o;
 }
 
@@ -3392,6 +3890,9 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *p
 {
        *pass_size_in_words = FALSE;
 
+       if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
+               profile_allocs = FALSE;
+
        if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
                return mono_object_new_specific;
 
@@ -3463,7 +3964,8 @@ mono_object_clone (MonoObject *obj)
        if (obj->vtable->klass->has_references)
                mono_gc_wbarrier_object (o);
 #endif
-       mono_profiler_allocation (o, obj->vtable->klass);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation (o, obj->vtable->klass);
 
        if (obj->vtable->klass->has_finalize)
                mono_object_register_finalizer (o);
@@ -3493,7 +3995,7 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest)
 #ifdef HAVE_SGEN_GC
        if (klass->element_class->valuetype) {
                if (klass->element_class->has_references)
-                       mono_value_copy_array (dest, 0, src, mono_array_length (src));
+                       mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
                else
                        memcpy (&dest->vector, &src->vector, size);
        } else {
@@ -3530,7 +4032,7 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
 #ifdef HAVE_SGEN_GC
                if (klass->element_class->valuetype) {
                        if (klass->element_class->has_references)
-                               mono_value_copy_array (o, 0, array, mono_array_length (array));
+                               mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
                        else
                                memcpy (&o->vector, &array->vector, size);
                } else {
@@ -3553,7 +4055,7 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
 #ifdef HAVE_SGEN_GC
        if (klass->element_class->valuetype) {
                if (klass->element_class->has_references)
-                       mono_value_copy_array (o, 0, array, mono_array_length (array));
+                       mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
                else
                        memcpy (&o->vector, &array->vector, size);
        } else {
@@ -3583,18 +4085,18 @@ mono_array_clone (MonoArray *array)
 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
 #define MYGUINT_MAX MYGUINT64_MAX
 #define CHECK_ADD_OVERFLOW_UN(a,b) \
-        (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
+           (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
 #define CHECK_MUL_OVERFLOW_UN(a,b) \
-        ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
-        (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
+           (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
+                                        ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
 #else
 #define MYGUINT32_MAX 4294967295U
 #define MYGUINT_MAX MYGUINT32_MAX
 #define CHECK_ADD_OVERFLOW_UN(a,b) \
-        (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
+           (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
 #define CHECK_MUL_OVERFLOW_UN(a,b) \
-        ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
-        (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
+           (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
+                                        ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
 #endif
 
 /**
@@ -3684,7 +4186,8 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
                }
        }
 
-       mono_profiler_allocation (o, array_class);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation (o, array_class);
 
        return array;
 }
@@ -3705,7 +4208,7 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
        MONO_ARCH_SAVE_REGS;
 
        ac = mono_array_class_get (eclass, 1);
-       g_assert (ac != NULL);
+       g_assert (ac);
 
        return mono_array_new_specific (mono_class_vtable (domain, ac), n);
 }
@@ -3727,19 +4230,26 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
 
        MONO_ARCH_SAVE_REGS;
 
-       if (n > MONO_ARRAY_MAX_INDEX)
+       if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
                arith_overflow ();
+               return NULL;
+       }
        
        elem_size = mono_array_element_size (vtable->klass);
-       if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
+       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 (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
                mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
+               return NULL;
+       }
        byte_len += sizeof (MonoArray);
        if (!vtable->klass->has_references) {
                o = mono_object_allocate_ptrfree (byte_len, vtable);
 #if NEED_TO_ZERO_PTRFREE
+               ((MonoArray*)o)->bounds = NULL;
                memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
 #endif
        } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
@@ -3750,9 +4260,9 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
        }
 
        ao = (MonoArray *)o;
-       ao->bounds = NULL;
        ao->max_length = n;
-       mono_profiler_allocation (o, vtable->klass);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation (o, vtable->klass);
 
        return ao;
 }
@@ -3803,7 +4313,8 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
 #if NEED_TO_ZERO_PTRFREE
        s->chars [len] = 0;
 #endif
-       mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
 
        return s;
 }
@@ -3844,23 +4355,41 @@ mono_string_new_len (MonoDomain *domain, const char *text, guint length)
 MonoString*
 mono_string_new (MonoDomain *domain, const char *text)
 {
-       GError *error = NULL;
-       MonoString *o = NULL;
-       guint16 *ut;
-       glong items_written;
-       int l;
+    GError *error = NULL;
+    MonoString *o = NULL;
+    guint16 *ut;
+    glong items_written;
+    int l;
 
-       l = strlen (text);
-       
-       ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
+    l = strlen (text);
+   
+    ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
 
-       if (!error)
-               o = mono_string_new_utf16 (domain, ut, items_written);
-       else 
-               g_error_free (error);
+    if (!error)
+        o = mono_string_new_utf16 (domain, ut, items_written);
+    else
+        g_error_free (error);
 
-       g_free (ut);
+    g_free (ut);
+/*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
+#if 0
+       gunichar2 *str;
+       const gchar *end;
+       int len;
+       MonoString *o = NULL;
+
+       if (!g_utf8_validate (text, -1, &end))
+               return NULL;
+
+       len = g_utf8_strlen (text, -1);
+       o = mono_string_new_size (domain, len);
+       str = mono_string_chars (o);
 
+       while (text < end) {
+               *str++ = g_utf8_get_char (text);
+               text = g_utf8_next_char (text);
+       }
+#endif
        return o;
 }
 
@@ -3904,7 +4433,8 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        vtable = mono_class_vtable (domain, class);
        size = mono_class_instance_size (class);
        res = mono_object_new_alloc_specific (vtable);
-       mono_profiler_allocation (res, class);
+       if (G_UNLIKELY (profile_allocs))
+               mono_profiler_allocation (res, class);
 
        size = size - sizeof (MonoObject);
 
@@ -3961,8 +4491,8 @@ mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
  * @src: source pointer
  * @count: number of items
  *
- * Copy @count valuetype items from @src to @dest. This function must be used
- * when @klass contains references fields.
+ * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
+ * This function must be used when @klass contains references fields.
  * Overlap is handled.
  */
 void
@@ -4247,18 +4777,18 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
        if (image->dynamic)
                return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
        else
-               return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
+               return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
 }
 
 /**
- * mono_ldstr_metdata_sig
+ * mono_ldstr_metadata_sig
  * @domain: the domain for the string
  * @sig: the signature of a metadata string
  *
  * Returns: a MonoString for a string stored in the metadata
  */
 static MonoString*
-mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
+mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
 {
        const char *str = sig;
        MonoString *o, *interned;
@@ -4381,24 +4911,27 @@ mono_string_from_utf16 (gunichar2 *data)
        return mono_string_new_utf16 (domain, data, len);
 }
 
-/**
- * mono_string_to_utf8_mp:
- * @s: a System.String
- *
- * Same as mono_string_to_utf8, but allocate the string from a mempool.
- */
-char *
-mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+
+static char *
+mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
 {
-       char *r = mono_string_to_utf8 (s);
+       char *r;
        char *mp_s;
        int len;
 
+       if (!mp && !image)
+               return mono_string_to_utf8 (s);
+
+       r = mono_string_to_utf8 (s);
        if (!r)
                return NULL;
 
        len = strlen (r) + 1;
-       mp_s = mono_mempool_alloc (mp, len);
+       if (mp)
+               mp_s = mono_mempool_alloc (mp, len);
+       else
+               mp_s = mono_image_alloc (image, len);
+
        memcpy (mp_s, r, len);
 
        g_free (r);
@@ -4406,6 +4939,30 @@ mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
        return mp_s;
 }
 
+/**
+ * mono_string_to_utf8_image:
+ * @s: a System.String
+ *
+ * Same as mono_string_to_utf8, but allocate the string from the image mempool.
+ */
+char *
+mono_string_to_utf8_image (MonoImage *image, MonoString *s)
+{
+       return mono_string_to_utf8_internal (NULL, image, s);
+}
+
+/**
+ * mono_string_to_utf8_mp:
+ * @s: a System.String
+ *
+ * Same as mono_string_to_utf8, but allocate the string from a mempool.
+ */
+char *
+mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
+{
+       return mono_string_to_utf8_internal (mp, NULL, s);
+}
+
 static void
 default_ex_handler (MonoException *ex)
 {
@@ -4445,8 +5002,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) {
+               MonoThread *thread = mono_thread_current ();
+               g_assert (ex->object.vtable->domain == mono_domain_get ());
+               MONO_OBJECT_SETREF (thread, abort_exc, ex);
+       }
        
        ex_handler (ex);
 }
@@ -4499,6 +5059,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.
@@ -4514,11 +5094,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 */
        }
 
@@ -4750,29 +5329,28 @@ mono_print_unhandled_exception (MonoObject *exc)
  * @this: pointer to an uninitialized delegate object
  * @target: target object
  * @addr: pointer to native code
+ * @method: method
  *
- * This is used to initialize a delegate.
+ * Initialize a delegate and sets a specific method, not the one
+ * associated with addr.  This is useful when sharing generic code.
+ * In that case addr will most probably not be associated with the
+ * correct instantiation of the method.
  */
 void
-mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
+mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
 {
-       MonoDomain *domain = mono_domain_get ();
        MonoDelegate *delegate = (MonoDelegate *)this;
-       MonoMethod *method = NULL;
        MonoClass *class;
-       MonoJitInfo *ji;
 
        g_assert (this);
        g_assert (addr);
 
+       if (method)
+               delegate->method = method;
+
        class = this->vtable->klass;
        mono_stats.delegate_creations++;
 
-       if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
-               method = ji->method;
-               delegate->method = method;
-       }
-
        if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
                g_assert (method);
                method = mono_marshal_get_remoting_invoke (method);
@@ -4790,6 +5368,31 @@ mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
        delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
 }
 
+/**
+ * mono_delegate_ctor:
+ * @this: pointer to an uninitialized delegate object
+ * @target: target object
+ * @addr: pointer to native code
+ *
+ * This is used to initialize a delegate.
+ */
+void
+mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
+{
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitInfo *ji;
+       MonoMethod *method = NULL;
+
+       g_assert (addr);
+
+       if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
+               method = ji->method;
+               g_assert (!method->klass->generic_container);
+       }
+
+       mono_delegate_ctor_with_method (this, target, addr, method);
+}
+
 /**
  * mono_method_call_message_new:
  * @method: method to encapsulate
@@ -4967,7 +5570,7 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
 
        full_name = mono_type_get_full_name (klass);
        mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
-       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
        g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
@@ -5033,7 +5636,7 @@ mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *
 
        full_name = mono_type_get_full_name (klass);
        mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
-       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
        g_free (full_name);
 
        mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
@@ -5098,7 +5701,7 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
 
        full_name = mono_type_get_full_name (klass);
        mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
-       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
        mono_array_setref (msg->args, 2, arg);
        g_free (full_name);
 
@@ -5148,7 +5751,7 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
 
        full_name = mono_type_get_full_name (klass);
        mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
-       mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
+       mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
        mono_array_setref (msg->args, 2, arg);
        g_free (full_name);
 
@@ -5161,53 +5764,24 @@ 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