Added MonoString<->UTF-32 conversion helper functions.
[mono.git] / mono / metadata / object.c
index 3cc9c04a45f00f324fbe4392199e435045e3865f..349e956661c6d9127fb4af5a8ae1153e248bd1e3 100644 (file)
@@ -88,9 +88,9 @@ static char *
 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
 
 
-#define ldstr_lock() EnterCriticalSection (&ldstr_section)
-#define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
-static CRITICAL_SECTION ldstr_section;
+#define ldstr_lock() mono_mutex_lock (&ldstr_section)
+#define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
+static mono_mutex_t ldstr_section;
 
 static gboolean profile_allocs = TRUE;
 
@@ -137,13 +137,13 @@ typedef struct
        guint32 initializing_tid;
        guint32 waiting_count;
        gboolean done;
-       CRITICAL_SECTION initialization_section;
+       mono_mutex_t initialization_section;
 } TypeInitializationLock;
 
 /* for locking access to type_initialization_hash and blocked_thread_hash */
-#define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
-#define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
-static CRITICAL_SECTION type_initialization_section;
+#define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
+#define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
+static mono_mutex_t type_initialization_section;
 
 /* from vtable to lock */
 static GHashTable *type_initialization_hash;
@@ -188,10 +188,10 @@ mono_thread_get_main (void)
 void
 mono_type_initialization_init (void)
 {
-       InitializeCriticalSection (&type_initialization_section);
+       mono_mutex_init_recursive (&type_initialization_section);
        type_initialization_hash = g_hash_table_new (NULL, NULL);
        blocked_thread_hash = g_hash_table_new (NULL, NULL);
-       InitializeCriticalSection (&ldstr_section);
+       mono_mutex_init_recursive (&ldstr_section);
 }
 
 void
@@ -201,11 +201,11 @@ mono_type_initialization_cleanup (void)
        /* This is causing race conditions with
         * mono_release_type_locks
         */
-       DeleteCriticalSection (&type_initialization_section);
+       mono_mutex_destroy (&type_initialization_section);
        g_hash_table_destroy (type_initialization_hash);
        type_initialization_hash = NULL;
 #endif
-       DeleteCriticalSection (&ldstr_section);
+       mono_mutex_destroy (&ldstr_section);
        g_hash_table_destroy (blocked_thread_hash);
        blocked_thread_hash = NULL;
 
@@ -334,12 +334,12 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                                }
                        }
                        lock = g_malloc (sizeof(TypeInitializationLock));
-                       InitializeCriticalSection (&lock->initialization_section);
+                       mono_mutex_init_recursive (&lock->initialization_section);
                        lock->initializing_tid = tid;
                        lock->waiting_count = 1;
                        lock->done = FALSE;
                        /* grab the vtable lock while this thread still owns type_initialization_section */
-                       EnterCriticalSection (&lock->initialization_section);
+                       mono_mutex_lock (&lock->initialization_section);
                        g_hash_table_insert (type_initialization_hash, vtable, lock);
                        do_initialization = 1;
                } else {
@@ -404,11 +404,11 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                        if (last_domain)
                                mono_domain_set (last_domain, TRUE);
                        lock->done = TRUE;
-                       LeaveCriticalSection (&lock->initialization_section);
+                       mono_mutex_unlock (&lock->initialization_section);
                } else {
                        /* this just blocks until the initializing thread is done */
-                       EnterCriticalSection (&lock->initialization_section);
-                       LeaveCriticalSection (&lock->initialization_section);
+                       mono_mutex_lock (&lock->initialization_section);
+                       mono_mutex_unlock (&lock->initialization_section);
                }
 
                mono_type_initialization_lock ();
@@ -416,7 +416,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                        g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
                --lock->waiting_count;
                if (lock->waiting_count == 0) {
-                       DeleteCriticalSection (&lock->initialization_section);
+                       mono_mutex_destroy (&lock->initialization_section);
                        g_hash_table_remove (type_initialization_hash, vtable);
                        g_free (lock);
                }
@@ -452,10 +452,10 @@ 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;
-               LeaveCriticalSection (&lock->initialization_section);
+               mono_mutex_unlock (&lock->initialization_section);
                --lock->waiting_count;
                if (lock->waiting_count == 0) {
-                       DeleteCriticalSection (&lock->initialization_section);
+                       mono_mutex_destroy (&lock->initialization_section);
                        g_free (lock);
                        return TRUE;
                }
@@ -1350,6 +1350,9 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                        int method_slot_in_interface;
                        for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
                                MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
+
+                               if (method->is_generic)
+                                       has_generic_virtual = TRUE;
                                add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
                        }
                        interface_offset += iface->method.count;
@@ -2970,7 +2973,7 @@ handle_enum:
                        MonoClass *class = mono_class_from_mono_type (type);
                        int size = mono_class_value_size (class, NULL);
                        if (value == NULL)
-                               mono_gc_bzero (dest, size);
+                               mono_gc_bzero_atomic (dest, size);
                        else
                                mono_gc_wbarrier_value_copy (dest, value, 1, class);
                }
@@ -3342,7 +3345,7 @@ mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *
 void
 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
 {
-       return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
+       mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
 }
 
 /**
@@ -3419,9 +3422,9 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
                if (param_class->has_references)
                        mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
                else
-                       mono_gc_memmove (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
+                       mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
        } else {
-               mono_gc_bzero (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+               mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
        }
 }
 
@@ -3449,7 +3452,7 @@ mono_nullable_box (guint8 *buf, MonoClass *klass)
                if (param_class->has_references)
                        mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
                else
-                       mono_gc_memmove (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+                       mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
                return o;
        }
        else
@@ -3540,7 +3543,7 @@ mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **
 }
 
 static char **main_args = NULL;
-static int num_main_args;
+static int num_main_args = 0;
 
 /**
  * mono_runtime_get_main_args:
@@ -3554,9 +3557,6 @@ mono_runtime_get_main_args (void)
        int i;
        MonoDomain *domain = mono_domain_get ();
 
-       if (!main_args)
-               return NULL;
-
        res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
 
        for (i = 0; i < num_main_args; ++i)
@@ -3573,6 +3573,41 @@ free_main_args (void)
        for (i = 0; i < num_main_args; ++i)
                g_free (main_args [i]);
        g_free (main_args);
+       num_main_args = 0;
+       main_args = NULL;
+}
+
+/**
+ * mono_runtime_set_main_args:
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ *
+ * Set the command line arguments from an embedding application that doesn't otherwise call
+ * mono_runtime_run_main ().
+ */
+int
+mono_runtime_set_main_args (int argc, char* argv[])
+{
+       int i;
+
+       free_main_args ();
+       main_args = g_new0 (char*, argc);
+       num_main_args = argc;
+
+       for (i = 0; i < argc; ++i) {
+               gchar *utf8_arg;
+
+               utf8_arg = mono_utf8_from_external (argv[i]);
+               if (utf8_arg == NULL) {
+                       g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
+                       g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
+                       exit (-1);
+               }
+
+               main_args [i] = utf8_arg;
+       }
+
+       return 0;
 }
 
 /**
@@ -4591,7 +4626,7 @@ mono_object_clone (MonoObject *obj)
        } else {
                int size = obj->vtable->klass->instance_size;
                /* do not copy the sync state */
-               mono_gc_memmove ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
+               mono_gc_memmove_atomic ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
        }
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, obj->vtable->klass);
@@ -4626,12 +4661,12 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest)
                if (klass->element_class->has_references)
                        mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
                else
-                       mono_gc_memmove (&dest->vector, &src->vector, size);
+                       mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
        } else {
                mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
        }
 #else
-       mono_gc_memmove (&dest->vector, &src->vector, size);
+       mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
 #endif
 }
 
@@ -4663,12 +4698,12 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
                        if (klass->element_class->has_references)
                                mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
                        else
-                               mono_gc_memmove (&o->vector, &array->vector, size);
+                               mono_gc_memmove_atomic (&o->vector, &array->vector, size);
                } else {
                        mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
                }
 #else
-               mono_gc_memmove (&o->vector, &array->vector, size);
+               mono_gc_memmove_atomic (&o->vector, &array->vector, size);
 #endif
                return o;
        }
@@ -4686,12 +4721,12 @@ mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
                if (klass->element_class->has_references)
                        mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
                else
-                       mono_gc_memmove (&o->vector, &array->vector, size);
+                       mono_gc_memmove_atomic (&o->vector, &array->vector, size);
        } else {
                mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
        }
 #else
-       mono_gc_memmove (&o->vector, &array->vector, size);
+       mono_gc_memmove_atomic (&o->vector, &array->vector, size);
 #endif
 
        return o;
@@ -4759,7 +4794,7 @@ mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
 MonoArray*
 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
 {
-       uintptr_t byte_len, len, bounds_size;
+       uintptr_t byte_len = 0, len, bounds_size;
        MonoObject *o;
        MonoArray *array;
        MonoArrayBounds *bounds;
@@ -4945,6 +4980,39 @@ mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
        return s;
 }
 
+/**
+ * mono_string_new_utf32:
+ * @text: a pointer to an utf32 string
+ * @len: the length of the string
+ *
+ * Returns: A newly created string object which contains @text.
+ */
+MonoString *
+mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
+{
+       MonoString *s;
+       mono_unichar2 *utf16_output = NULL;
+       gint32 utf16_len = 0;
+       GError *error = NULL;
+       glong items_written;
+       
+       utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
+       
+       if (error)
+               g_error_free (error);
+
+       while (utf16_output [utf16_len]) utf16_len++;
+       
+       s = mono_string_new_size (domain, utf16_len);
+       g_assert (s != NULL);
+
+       memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
+
+       g_free (utf16_output);
+       
+       return s;
+}
+
 /**
  * mono_string_new_size:
  * @text: a pointer to an utf16 string
@@ -4957,12 +5025,15 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
 {
        MonoString *s;
        MonoVTable *vtable;
-       size_t size = (sizeof (MonoString) + ((len + 1) * 2));
+       size_t size;
 
-       /* overflow ? can't fit it, can't allocate it! */
-       if (len > size)
+       /* check for overflow */
+       if (len < 0 || len > ((SIZE_MAX - sizeof (MonoString) - 2) / 2))
                mono_gc_out_of_memory (-1);
 
+       size = (sizeof (MonoString) + ((len + 1) * 2));
+       g_assert (size > 0);
+
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
        g_assert (vtable);
 
@@ -5108,7 +5179,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
 #else
 #if NO_UNALIGNED_ACCESS
-       mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
+       mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
 #else
        switch (size) {
        case 1:
@@ -5124,7 +5195,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
                *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
                break;
        default:
-               mono_gc_memmove ((char *)res + sizeof (MonoObject), value, size);
+               mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
        }
 #endif
 #endif
@@ -5650,6 +5721,31 @@ mono_string_to_utf16 (MonoString *s)
        return (gunichar2 *)(as);
 }
 
+/**
+ * mono_string_to_utf32:
+ * @s: a MonoString
+ *
+ * Return an null-terminated array of the UTF-32 (UCS-4) chars
+ * contained in @s. The result must be freed with g_free().
+ */
+mono_unichar4*
+mono_string_to_utf32 (MonoString *s)
+{
+       mono_unichar4 *utf32_output = NULL; 
+       GError *error = NULL;
+       glong items_written;
+       
+       if (s == NULL)
+               return NULL;
+               
+       utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
+       
+       if (error)
+               g_error_free (error);
+
+       return utf32_output;
+}
+
 /**
  * mono_string_from_utf16:
  * @data: the UTF16 string (LPWSTR) to convert
@@ -6291,10 +6387,10 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                                        if (class->has_references)
                                                mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
                                        else
-                                               mono_gc_memmove (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
+                                               mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
                                } else {
                                        size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
-                                       mono_gc_bzero (*((gpointer *)params [i]), size);
+                                       mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
                                }
                        }