[sgen] For object copies, check whether we can use memmove in the wbarrier.
[mono.git] / mono / metadata / object.c
index 00c013b215c40b61fad713bdaa881df23f75fe48..21df3486224604646fd7058bbc0970766b226aec 100644 (file)
@@ -15,7 +15,6 @@
 #endif
 #include <stdlib.h>
 #include <stdio.h>
-#include <signal.h>
 #include <string.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/tabledefs.h>
@@ -145,6 +144,21 @@ typedef struct
 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
 static mono_mutex_t type_initialization_section;
 
+
+static void
+mono_type_init_lock (TypeInitializationLock *lock)
+{
+       MONO_TRY_BLOCKING
+       mono_mutex_lock (&lock->initialization_section);
+       MONO_FINISH_TRY_BLOCKING
+}
+
+static void
+mono_type_init_unlock (TypeInitializationLock *lock)
+{
+       mono_mutex_unlock (&lock->initialization_section);
+}
+
 /* from vtable to lock */
 static GHashTable *type_initialization_hash;
 
@@ -276,8 +290,6 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
        MonoClass *klass;
        gchar *full_name;
 
-       MONO_ARCH_SAVE_REGS;
-
        if (vtable->initialized)
                return NULL;
 
@@ -350,7 +362,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                        lock->waiting_count = 1;
                        lock->done = FALSE;
                        /* grab the vtable lock while this thread still owns type_initialization_section */
-                       mono_mutex_lock (&lock->initialization_section);
+                       mono_type_init_lock (lock);
                        g_hash_table_insert (type_initialization_hash, vtable, lock);
                        do_initialization = 1;
                } else {
@@ -415,11 +427,11 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                        if (last_domain)
                                mono_domain_set (last_domain, TRUE);
                        lock->done = TRUE;
-                       mono_mutex_unlock (&lock->initialization_section);
+                       mono_type_init_unlock (lock);
                } else {
                        /* this just blocks until the initializing thread is done */
-                       mono_mutex_lock (&lock->initialization_section);
-                       mono_mutex_unlock (&lock->initialization_section);
+                       mono_type_init_lock (lock);
+                       mono_type_init_unlock (lock);
                }
 
                mono_type_initialization_lock ();
@@ -463,7 +475,7 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
                 * and get_type_init_exception_for_class () needs to be aware of this.
                 */
                vtable->init_failed = 1;
-               mono_mutex_unlock (&lock->initialization_section);
+               mono_type_init_unlock (lock);
                --lock->waiting_count;
                if (lock->waiting_count == 0) {
                        mono_mutex_destroy (&lock->initialization_section);
@@ -518,8 +530,7 @@ default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
-static MonoImtThunkBuilder imt_thunk_builder = NULL;
-#define ARCH_USE_IMT (imt_thunk_builder != NULL)
+static MonoImtThunkBuilder imt_thunk_builder;
 #if (MONO_IMT_SIZE > 32)
 #error "MONO_IMT_SIZE cannot be larger than 32"
 #endif
@@ -986,7 +997,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
        } else if (class->rank) {
                mono_class_compute_gc_descriptor (class->element_class);
-               if (!class->element_class->valuetype) {
+               if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
                        gsize abm = 1;
                        class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
                        /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
@@ -1405,7 +1416,7 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                                 * 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], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
+                               imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
                        } else {
                                imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
                        }
@@ -1851,6 +1862,27 @@ mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
        return NULL;
 }
 
+static gpointer*
+alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
+{
+       size_t alloc_offset;
+
+       /*
+        * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
+        * address bits.  The IMT has an odd number of entries, however, so on 32 bits the
+        * alignment will be off.  In that case we allocate 4 more bytes and skip over them.
+        */
+       if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
+               g_assert ((imt_table_bytes & 7) == 4);
+               vtable_size += 4;
+               alloc_offset = 4;
+       } else {
+               alloc_offset = 0;
+       }
+
+       return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
+}
+
 static MonoVTable *
 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
 {
@@ -1859,11 +1891,9 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        MonoClassField *field;
        char *t;
        int i, vtable_slots;
-       int imt_table_bytes = 0;
-       int alloc_offset;
+       size_t imt_table_bytes;
        int gc_bits;
        guint32 vtable_size, class_size;
-       guint32 cindex;
        gpointer iter;
        gpointer *interface_offsets;
 
@@ -1934,37 +1964,20 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        if (class_size)
                vtable_slots++;
 
-       if (ARCH_USE_IMT) {
-               vtable_size = MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
-               if (class->interface_offsets_count) {
-                       imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
-                       vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
-                       mono_stats.imt_number_of_tables++;
-                       mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
-               }
+       if (class->interface_offsets_count) {
+               imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
+               mono_stats.imt_number_of_tables++;
+               mono_stats.imt_tables_size += imt_table_bytes;
        } else {
-               vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
-                       MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
+               imt_table_bytes = 0;
        }
 
-       /*
-        * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
-        * address bits.  The IMT has an odd number of entries, however, so on 32 bits the
-        * alignment will be off.  In that case we allocate 4 more bytes and skip over them.
-        */
-       if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
-               g_assert ((imt_table_bytes & 7) == 4);
-               vtable_size += 4;
-               alloc_offset = 4;
-       } else {
-               alloc_offset = 0;
-       }
+       vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
 
        mono_stats.used_class_count++;
        mono_stats.class_vtable_size += vtable_size;
 
-       interface_offsets = (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
-
+       interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
        vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
        g_assert (!((gsize)vt & 7));
 
@@ -2019,7 +2032,6 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
                mono_stats.class_static_data_size += class_size;
        }
 
-       cindex = -1;
        iter = NULL;
        while ((field = mono_class_get_fields (class, &iter))) {
                if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
@@ -2089,15 +2101,6 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        
        //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
        //              class->name, class->interface_offsets_count);
-       
-       if (! ARCH_USE_IMT) {
-               /* initialize interface offsets */
-               for (i = 0; i < class->interface_offsets_count; ++i) {
-                       int interface_id = class->interfaces_packed [i]->interface_id;
-                       int slot = class->interface_offsets_packed [i];
-                       interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
-               }
-       }
 
        /* Initialize vtable */
        if (callbacks.get_vtable_trampoline) {
@@ -2116,15 +2119,10 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
                }
        }
 
-       if (ARCH_USE_IMT && imt_table_bytes) {
+       if (imt_table_bytes) {
                /* Now that the vtable is full, we can actually fill up the IMT */
-               if (callbacks.get_imt_trampoline) {
-                       /* lazy construction of the IMT entries enabled */
                        for (i = 0; i < MONO_IMT_SIZE; ++i)
                                interface_offsets [i] = callbacks.get_imt_trampoline (i);
-               } else {
-                       build_imt (class, vt, domain, interface_offsets, NULL);
-               }
        }
 
        /*
@@ -2234,6 +2232,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        gpointer *interface_offsets;
        uint8_t *bitmap;
        int bsize;
+       size_t imt_table_bytes;
        
 #ifdef COMPRESSED_INTERFACE_BITMAP
        int bcsize;
@@ -2279,23 +2278,18 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
        }
 
-       if (ARCH_USE_IMT) {
-               mono_stats.imt_number_of_tables++;
-               mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
-               vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
-                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
-       } else {
-               vtsize = sizeof (gpointer) * (max_interface_id + 1) +
-                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
-       }
+       imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
+       mono_stats.imt_number_of_tables++;
+       mono_stats.imt_tables_size += imt_table_bytes;
+
+       vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
 
        mono_stats.class_vtable_size += 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);
+       interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
+       pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
+       g_assert (!((gsize)pvt & 7));
+
        memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
 
        pvt->klass = mono_defaults.transparent_proxy_class;
@@ -2332,14 +2326,6 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        bitmap = mono_domain_alloc0 (domain, bsize);
 #endif
 
-       if (! ARCH_USE_IMT) {
-               /* initialize interface offsets */
-               for (i = 0; i < class->interface_offsets_count; ++i) {
-                       int interface_id = class->interfaces_packed [i]->interface_id;
-                       int slot = class->interface_offsets_packed [i];
-                       interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
-               }
-       }
        for (i = 0; i < class->interface_offsets_count; ++i) {
                int interface_id = class->interfaces_packed [i]->interface_id;
                bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
@@ -2356,9 +2342,6 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
                        interf = list_item->data;
                        
-                       if (! ARCH_USE_IMT) {
-                               interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
-                       }
                        bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
 
                        iter = NULL;
@@ -2368,17 +2351,12 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        
                        slot += mono_class_num_methods (interf);
                }
-               if (! ARCH_USE_IMT) {
-                       g_slist_free (extra_interfaces);
-               }
        }
 
-       if (ARCH_USE_IMT) {
-               /* Now that the vtable is full, we can actually fill up the IMT */
-               build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
-               if (extra_interfaces) {
-                       g_slist_free (extra_interfaces);
-               }
+       /* Now that the vtable is full, we can actually fill up the IMT */
+       build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
+       if (extra_interfaces) {
+               g_slist_free (extra_interfaces);
        }
 
 #ifdef COMPRESSED_INTERFACE_BITMAP
@@ -2789,8 +2767,10 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
 #endif
        {
                if (method->is_inflated) {
+                       MonoError error;
                        /* Have to inflate the result */
-                       res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
+                       res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
+                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                }
        }
 
@@ -2918,8 +2898,8 @@ mono_method_get_unmanaged_thunk (MonoMethod *method)
        return mono_compile_method (method);
 }
 
-static void
-set_value (MonoType *type, void *dest, void *value, int deref_pointer)
+void
+mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
 {
        int t;
        if (type->byref) {
@@ -3031,7 +3011,7 @@ mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
 
        dest = (char*)obj + field->offset;
-       set_value (field->type, dest, value, FALSE);
+       mono_copy_value (field->type, dest, value, FALSE);
 }
 
 /**
@@ -3064,7 +3044,7 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
        } else {
                dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
        }
-       set_value (field->type, dest, value, FALSE);
+       mono_copy_value (field->type, dest, value, FALSE);
 }
 
 /**
@@ -3133,7 +3113,7 @@ mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
 
        src = (char*)obj + field->offset;
-       set_value (field->type, value, src, TRUE);
+       mono_copy_value (field->type, value, src, TRUE);
 }
 
 /**
@@ -3248,7 +3228,7 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
                }
 
                /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
-               args [0] = *ptr;
+               args [0] = ptr ? *ptr : NULL;
                args [1] = mono_type_get_object (mono_domain_get (), type);
 
                return mono_runtime_invoke (m, NULL, args, NULL);
@@ -3348,7 +3328,7 @@ mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *
        } else {
                src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
        }
-       set_value (field->type, value, src, TRUE);
+       mono_copy_value (field->type, value, src, TRUE);
 }
 
 /**
@@ -4387,6 +4367,7 @@ mono_object_allocate (size_t size, MonoVTable *vtable)
        return o;
 }
 
+#ifndef HAVE_SGEN_GC
 /**
  * mono_object_allocate_ptrfree:
  * @size: number of bytes to allocate
@@ -4401,6 +4382,7 @@ mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
        ALLOC_PTRFREE (o, vtable, size);
        return o;
 }
+#endif
 
 static inline void *
 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
@@ -4427,7 +4409,6 @@ mono_object_new (MonoDomain *domain, MonoClass *klass)
 {
        MonoVTable *vtable;
 
-       MONO_ARCH_SAVE_REGS;
        vtable = mono_class_vtable (domain, klass);
        if (!vtable)
                return NULL;
@@ -4445,7 +4426,6 @@ mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
 {
        MonoVTable *vtable;
 
-       MONO_ARCH_SAVE_REGS;
        vtable = mono_class_vtable (domain, klass);
        if (!vtable)
                return NULL;
@@ -4469,8 +4449,6 @@ mono_object_new_specific (MonoVTable *vtable)
 {
        MonoObject *o;
 
-       MONO_ARCH_SAVE_REGS;
-       
        /* check for is_com_object for COM Interop */
        if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
        {
@@ -4645,13 +4623,9 @@ mono_object_clone (MonoObject *obj)
 
        o = mono_object_allocate (size, obj->vtable);
 
-       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 */
-               mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
-       }
+       /* If the object doesn't contain references this will do a simple memmove. */
+       mono_gc_wbarrier_object_copy (o, obj);
+
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, obj->vtable->klass);
 
@@ -4673,8 +4647,6 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest)
        uintptr_t size;
        MonoClass *klass = src->obj.vtable->klass;
 
-       MONO_ARCH_SAVE_REGS;
-
        g_assert (klass == dest->obj.vtable->klass);
 
        size = mono_array_length (src);
@@ -4710,8 +4682,6 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
        uintptr_t *sizes;
        MonoClass *klass = array->obj.vtable->klass;
 
-       MONO_ARCH_SAVE_REGS;
-
        if (array->bounds == NULL) {
                size = mono_array_length (array);
                o = mono_array_new_full (domain, klass, &size, NULL);
@@ -4921,8 +4891,6 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
 {
        MonoClass *ac;
 
-       MONO_ARCH_SAVE_REGS;
-
        ac = mono_array_class_get (eclass, 1);
        g_assert (ac);
 
@@ -4944,8 +4912,6 @@ mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
        MonoArray *ao;
        uintptr_t byte_len;
 
-       MONO_ARCH_SAVE_REGS;
-
        if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
                arith_overflow ();
                return NULL;
@@ -5050,10 +5016,10 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
        size_t size;
 
        /* check for overflow */
-       if (len < 0 || len > ((SIZE_MAX - offsetof (MonoString, chars) - 2) / 2))
+       if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
                mono_gc_out_of_memory (-1);
 
-       size = (offsetof (MonoString, chars) + ((len + 1) * 2));
+       size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
        g_assert (size > 0);
 
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
@@ -5160,8 +5126,6 @@ mono_string_new_wrapper (const char *text)
 {
        MonoDomain *domain = mono_domain_get ();
 
-       MONO_ARCH_SAVE_REGS;
-
        if (text)
                return mono_string_new (domain, text);
 
@@ -5463,22 +5427,32 @@ static MonoString*
 mono_string_is_interned_lookup (MonoString *str, int insert)
 {
        MonoGHashTable *ldstr_table;
-       MonoString *res;
+       MonoString *s, *res;
        MonoDomain *domain;
        
        domain = ((MonoObject *)str)->vtable->domain;
        ldstr_table = domain->ldstr_table;
        ldstr_lock ();
-       if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
+       res = mono_g_hash_table_lookup (ldstr_table, str);
+       if (res) {
                ldstr_unlock ();
                return res;
        }
        if (insert) {
-               str = mono_string_get_pinned (str);
-               if (str)
-                       mono_g_hash_table_insert (ldstr_table, str, str);
+               /* Allocate outside the lock */
                ldstr_unlock ();
-               return str;
+               s = mono_string_get_pinned (str);
+               if (s) {
+                       ldstr_lock ();
+                       res = mono_g_hash_table_lookup (ldstr_table, str);
+                       if (res) {
+                               ldstr_unlock ();
+                               return res;
+                       }
+                       mono_g_hash_table_insert (ldstr_table, s, s);
+                       ldstr_unlock ();
+               }
+               return s;
        } else {
                LDStrInfo ldstr_info;
                ldstr_info.orig_domain = domain;
@@ -5537,8 +5511,6 @@ mono_string_intern (MonoString *str)
 MonoString*
 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
 {
-       MONO_ARCH_SAVE_REGS;
-
        if (image->dynamic) {
                MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
                return str;
@@ -5578,18 +5550,23 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
        }
 #endif
        ldstr_lock ();
-       if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
-               ldstr_unlock ();
-               /* o will get garbage collected */
-               return interned;
-       }
+       interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
+       ldstr_unlock ();
+       if (interned)
+               return interned; /* o will get garbage collected */
 
        o = mono_string_get_pinned (o);
-       if (o)
-               mono_g_hash_table_insert (domain->ldstr_table, o, o);
-       ldstr_unlock ();
+       if (o) {
+               ldstr_lock ();
+               interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
+               if (!interned) {
+                       mono_g_hash_table_insert (domain->ldstr_table, o, o);
+                       interned = o;
+               }
+               ldstr_unlock ();
+       }
 
-       return o;
+       return interned;
 }
 
 /**
@@ -6018,6 +5995,78 @@ mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpo
        return res;
 }
 
+MonoObject *
+mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc)
+{
+       MonoAsyncCall *ac;
+       MonoObject *res;
+       MonoInternalThread *thread;
+
+       g_assert (ares);
+       g_assert (ares->async_delegate);
+
+       thread = mono_thread_internal_current ();
+
+       if (!ares->execution_context) {
+               ares->original_context = NULL;
+       } else {
+               /* use captured ExecutionContext (if available) */
+               MONO_OBJECT_SETREF (ares, original_context, mono_thread_get_execution_context ());
+               mono_thread_set_execution_context (ares->execution_context);
+       }
+
+       ac = (MonoAsyncCall*) ares->object_data;
+       if (!ac) {
+               thread->async_invoke_method = ((MonoDelegate*) ares->async_delegate)->method;
+               res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, exc);
+               thread->async_invoke_method = NULL;
+       } else {
+               MonoArray *out_args = NULL;
+               gpointer wait_event = NULL;
+
+               ac->msg->exc = NULL;
+               res = mono_message_invoke (ares->async_delegate, ac->msg, exc, &out_args);
+               MONO_OBJECT_SETREF (ac->msg, exc, *exc);
+               MONO_OBJECT_SETREF (ac, res, res);
+               MONO_OBJECT_SETREF (ac, out_args, out_args);
+
+               mono_monitor_enter ((MonoObject*) ares);
+               ares->completed = 1;
+               if (ares->handle)
+                       wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
+               mono_monitor_exit ((MonoObject*) ares);
+
+               if (wait_event != NULL)
+                       SetEvent (wait_event);
+
+               if (!ac->cb_method) {
+                       *exc = NULL;
+               } else {
+                       thread->async_invoke_method = ac->cb_method;
+                       mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, exc);
+                       thread->async_invoke_method = NULL;
+               }
+       }
+
+       /* restore original thread execution context if flow isn't suppressed, i.e. non null */
+       if (ares->original_context) {
+               mono_thread_set_execution_context (ares->original_context);
+               ares->original_context = NULL;
+       }
+
+       return res;
+}
+
+MonoObject *
+ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *this)
+{
+       MonoObject *exc = NULL;
+       MonoObject *res = mono_async_result_invoke (this, &exc);
+       if (exc)
+               mono_raise_exception ((MonoException*) exc);
+       return res;
+}
+
 void
 mono_message_init (MonoDomain *domain,
                   MonoMethodMessage *this, 
@@ -6286,7 +6335,6 @@ void
 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
 {
        MonoDelegate *delegate = (MonoDelegate *)this;
-       MonoClass *class;
 
        g_assert (this);
        g_assert (addr);
@@ -6294,7 +6342,6 @@ mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer a
        if (method)
                delegate->method = method;
 
-       class = this->vtable->klass;
        mono_stats.delegate_creations++;
 
 #ifndef DISABLE_REMOTING
@@ -6359,7 +6406,7 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *
        MonoDomain *domain = mono_domain_get ();
        MonoMethodSignature *sig = mono_method_signature (method);
        MonoMethodMessage *msg;
-       int i, count, type;
+       int i, count;
 
        msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
        
@@ -6381,7 +6428,6 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *
                else 
                        vpos = params [i];
 
-               type = sig->params [i]->type;
                class = mono_class_from_mono_type (sig->params [i]);
 
                if (class->valuetype)