[sgen] For object copies, check whether we can use memmove in the wbarrier.
[mono.git] / mono / metadata / object.c
index 03180a328e7c417f7996bd0548e20461963166fa..21df3486224604646fd7058bbc0970766b226aec 100644 (file)
@@ -144,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;
 
@@ -347,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 {
@@ -412,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 ();
@@ -460,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);
@@ -515,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
@@ -1402,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);
                        }
@@ -1950,16 +1964,12 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        if (class_size)
                vtable_slots++;
 
-       if (ARCH_USE_IMT) {
-               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 {
-                       imt_table_bytes = 0;
-               }
+       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 {
-               imt_table_bytes = sizeof (gpointer) * (class->max_interface_id + 1);
+               imt_table_bytes = 0;
        }
 
        vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
@@ -2091,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) {
@@ -2118,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);
-               }
        }
 
        /*
@@ -2282,13 +2278,9 @@ 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) {
-               imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
-               mono_stats.imt_number_of_tables++;
-               mono_stats.imt_tables_size += imt_table_bytes;
-       } else {
-               imt_table_bytes = sizeof (gpointer) * (max_interface_id + 1);
-       }
+       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);
 
@@ -2334,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));
@@ -2358,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;
@@ -2370,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
@@ -4647,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);
 
@@ -5044,7 +5016,7 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
        size_t size;
 
        /* check for overflow */
-       if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 2) / 2))
+       if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
                mono_gc_out_of_memory (-1);
 
        size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
@@ -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,