do not check order sequence if option /order was not used
[mono.git] / mono / metadata / object.c
index 86cc1ce29997fbe92ac6501c378a70b7566f6978..a1e1f884125bda056e5e0019dec2fa92c7404f80 100644 (file)
@@ -6,7 +6,8 @@
  *   Paolo Molaro (lupus@ximian.com)
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
- * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
  */
 #include <config.h>
 #ifdef HAVE_ALLOCA_H
@@ -42,6 +43,7 @@
 #include <mono/utils/strenc.h>
 #include <mono/utils/mono-counters.h>
 #include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-memory-model.h>
 #include "cominterop.h"
 
 #ifdef HAVE_BOEHM_GC
@@ -99,7 +101,8 @@ mono_runtime_object_init (MonoObject *this)
        MonoClass *klass = this->vtable->klass;
 
        method = mono_class_get_method_from_name (klass, ".ctor", 0);
-       g_assert (method);
+       if (!method)
+               g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
 
        if (method->klass->valuetype)
                this = mono_object_unbox (this);
@@ -222,8 +225,9 @@ get_type_init_exception_for_vtable (MonoVTable *vtable)
        MonoException *ex;
        gchar *full_name;
 
-       g_assert (vtable->init_failed);
-
+       if (!vtable->init_failed)
+               g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
+       
        /* 
         * If the initializing thread was rudely aborted, the exception is not stored
         * in the hash.
@@ -489,7 +493,7 @@ default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotin
 }
 
 static gpointer
-default_delegate_trampoline (MonoClass *klass)
+default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
 {
        g_assert_not_reached ();
        return NULL;
@@ -586,7 +590,7 @@ mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gbo
 gpointer
 mono_runtime_create_delegate_trampoline (MonoClass *klass)
 {
-       return arch_create_delegate_trampoline (klass);
+       return arch_create_delegate_trampoline (mono_domain_get (), klass);
 }
 
 static MonoFreeMethodFunc default_mono_free_method = NULL;
@@ -967,13 +971,13 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                mono_class_compute_gc_descriptor (class->element_class);
                if (!class->element_class->valuetype) {
                        gsize abm = 1;
-                       class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
+                       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,
                                class->name_space, class->name);*/
                } else {
                        /* remove the object header */
                        bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
-                       class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
+                       class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
                        /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
                                class->name_space, class->name);*/
                        if (bitmap != default_bitmap)
@@ -1082,9 +1086,8 @@ mono_method_get_imt_slot (MonoMethod *method)
        hashes = hashes_start;
 
        if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
-               printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
+               g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
                                method->klass->name_space, method->klass->name, method->name);
-               g_assert_not_reached ();
        }
        
        /* Initialize hashes */
@@ -1836,6 +1839,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        char *t;
        int i, vtable_slots;
        int imt_table_bytes = 0;
+       int gc_bits;
        guint32 vtable_size, class_size;
        guint32 cindex;
        gpointer iter;
@@ -1953,6 +1957,11 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
 #endif
                vt->gc_descr = class->gc_descr;
 
+       gc_bits = mono_gc_get_vtable_bits (class);
+       g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
+
+       vt->gc_bits = gc_bits;
+
        if (class_size) {
                /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
                if (class->has_static_refs) {
@@ -1990,21 +1999,23 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
                                gsize default_bitmap [4] = {0};
                                gsize *bitmap;
                                int max_set = 0;
+                               int numbits;
                                MonoClass *fclass;
                                if (mono_type_is_reference (field->type)) {
                                        default_bitmap [0] = 1;
-                                       max_set = 1;
+                                       numbits = 1;
                                        bitmap = default_bitmap;
                                } else if (mono_type_is_struct (field->type)) {
                                        fclass = mono_class_from_mono_type (field->type);
                                        bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
+                                       numbits = max_set + 1;
                                } else {
                                        default_bitmap [0] = 0;
-                                       max_set = 0;
+                                       numbits = 0;
                                        bitmap = default_bitmap;
                                }
                                size = mono_type_size (field->type, &align);
-                               offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
+                               offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
                                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));
@@ -2053,6 +2064,54 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
                }
        }
 
+       /* Initialize vtable */
+       if (callbacks.get_vtable_trampoline) {
+               // This also covers the AOT case
+               for (i = 0; i < class->vtable_size; ++i) {
+                       vt->vtable [i] = callbacks.get_vtable_trampoline (i);
+               }
+       } else {
+               mono_class_setup_vtable (class);
+
+               for (i = 0; i < class->vtable_size; ++i) {
+                       MonoMethod *cm;
+
+                       if ((cm = class->vtable [i]))
+                               vt->vtable [i] = arch_create_jit_trampoline (cm);
+               }
+       }
+
+       if (ARCH_USE_IMT && 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);
+               }
+       }
+
+       /*
+        * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
+        * re-acquire them and check if another thread has created the vtable in the meantime.
+        */
+       /* Special case System.MonoType to avoid infinite recursion */
+       if (class != mono_defaults.monotype_class) {
+               /*FIXME check for OOM*/
+               vt->type = mono_type_get_object (domain, &class->byval_arg);
+               if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
+                       /* This is unregistered in
+                          unregister_vtable_reflection_type() in
+                          domain.c. */
+                       MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
+       }
+
+       if (class->contextbound)
+               vt->remote = 1;
+       else
+               vt->remote = 0;
+
        /*  class_vtable_array keeps an array of created vtables
         */
        g_ptr_array_add (domain->class_vtable_array, vt);
@@ -2060,10 +2119,15 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
         * it it enlarged and when it is stored info.
         */
 
+       /*
+        * Store the vtable in class->runtime_info.
+        * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
+        */
+       mono_memory_barrier ();
+
        old_info = class->runtime_info;
        if (old_info && old_info->max_domain >= domain->domain_id) {
                /* someone already created a large enough runtime info */
-               mono_memory_barrier ();
                old_info->domain_vtables [domain->domain_id] = vt;
        } else {
                int new_size = domain->domain_id;
@@ -2090,32 +2154,14 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
                class->runtime_info = runtime_info;
        }
 
-       /* Initialize vtable */
-       if (callbacks.get_vtable_trampoline) {
-               // This also covers the AOT case
-               for (i = 0; i < class->vtable_size; ++i) {
-                       vt->vtable [i] = callbacks.get_vtable_trampoline (i);
-               }
-       } else {
-               mono_class_setup_vtable (class);
-
-               for (i = 0; i < class->vtable_size; ++i) {
-                       MonoMethod *cm;
-
-                       if ((cm = class->vtable [i]))
-                               vt->vtable [i] = arch_create_jit_trampoline (cm);
-               }
-       }
-
-       if (ARCH_USE_IMT && 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);
-               }
+       if (class == mono_defaults.monotype_class) {
+               /*FIXME check for OOM*/
+               vt->type = mono_type_get_object (domain, &class->byval_arg);
+               if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
+                       /* This is unregistered in
+                          unregister_vtable_reflection_type() in
+                          domain.c. */
+                       MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
        }
 
        mono_domain_unlock (domain);
@@ -2130,18 +2176,6 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        if (class->parent)
                mono_class_vtable_full (domain, class->parent, raise_on_error);
 
-       /*FIXME check for OOM*/
-       vt->type = mono_type_get_object (domain, &class->byval_arg);
-       if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
-               /* This is unregistered in
-                  unregister_vtable_reflection_type() in
-                  domain.c. */
-               MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
-       if (class->contextbound)
-               vt->remote = 1;
-       else
-               vt->remote = 0;
-
        return vt;
 }
 
@@ -2929,8 +2963,7 @@ handle_enum:
                t = type->data.generic_class->container_class->byval_arg.type;
                goto handle_enum;
        default:
-               g_warning ("got type %x", type->type);
-               g_assert_not_reached ();
+               g_error ("got type %x", type->type);
        }
 }
 
@@ -3365,6 +3398,9 @@ void
 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
 {
        MonoClass *param_class = klass->cast_class;
+
+       mono_class_setup_fields_locking (klass);
+       g_assert (klass->fields_inited);
                                
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
        g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
@@ -3393,6 +3429,9 @@ mono_nullable_box (guint8 *buf, MonoClass *klass)
 {
        MonoClass *param_class = klass->cast_class;
 
+       mono_class_setup_fields_locking (klass);
+       g_assert (klass->fields_inited);
+
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
        g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
 
@@ -3444,9 +3483,11 @@ MonoObject*
 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
 {
        MonoMethod *im;
+       MonoClass *klass = delegate->vtable->klass;
 
-       im = mono_get_delegate_invoke (delegate->vtable->klass);
-       g_assert (im);
+       im = mono_get_delegate_invoke (klass);
+       if (!im)
+               g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
 
        return mono_runtime_invoke (im, delegate, params, exc);
 }
@@ -3856,9 +3897,9 @@ mono_unhandled_exception (MonoObject *exc)
                }
 
                /* set exitcode only if we will abort the process */
-               if (abort_process)
-                       mono_environment_exitcode_set (1);
                if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
+                       if (abort_process)
+                               mono_environment_exitcode_set (1);
                        mono_print_unhandled_exception (exc);
                } else {
                        if (root_appdomain_delegate) {
@@ -4905,7 +4946,7 @@ mono_string_new_len (MonoDomain *domain, const char *text, guint length)
        guint16 *ut;
        glong items_written;
 
-       ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
+       ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
 
        if (!error)
                o = mono_string_new_utf16 (domain, ut, items_written);
@@ -5184,9 +5225,10 @@ mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
                        return obj;
        } else {
                MonoClass *oklass = vt->klass;
-               if ((oklass == mono_defaults.transparent_proxy_class))
+               if (oklass == mono_defaults.transparent_proxy_class)
                        oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
-       
+
+               mono_class_setup_supertypes (klass);    
                if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
                        return obj;
        }
@@ -5664,26 +5706,13 @@ mono_raise_exception (MonoException *ex)
         * that will cause gcc to omit the function epilog, causing problems when
         * the JIT tries to walk the stack, since the return address on the stack
         * will point into the next function in the executable, not this one.
-        */
-
-       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
-               MonoInternalThread *thread = mono_thread_internal_current ();
-               g_assert (ex->object.vtable->domain == mono_domain_get ());
-               MONO_OBJECT_SETREF (thread, abort_exc, ex);
-       }
-       
+        */     
        eh_callbacks.mono_raise_exception (ex);
 }
 
 void
 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
 {
-       if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
-               MonoInternalThread *thread = mono_thread_internal_current ();
-               g_assert (ex->object.vtable->domain == mono_domain_get ());
-               MONO_OBJECT_SETREF (thread, abort_exc, ex);
-       }
-       
        eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
 }
 
@@ -5807,23 +5836,18 @@ mono_message_init (MonoDomain *domain,
        if (!object_array_klass) {
                MonoClass *klass;
 
-               klass = mono_array_class_get (mono_defaults.object_class, 1);
-               g_assert (klass);
-
-               mono_memory_barrier ();
-               object_array_klass = klass;
-
                klass = mono_array_class_get (mono_defaults.byte_class, 1);
                g_assert (klass);
-
-               mono_memory_barrier ();
                byte_array_klass = klass;
 
                klass = mono_array_class_get (mono_defaults.string_class, 1);
                g_assert (klass);
-
-               mono_memory_barrier ();
                string_array_klass = klass;
+
+               klass = mono_array_class_get (mono_defaults.object_class, 1);
+               g_assert (klass);
+
+               mono_atomic_store_release (&object_array_klass, klass);
        }
 
        MONO_OBJECT_SETREF (this, method, method);
@@ -5996,15 +6020,22 @@ mono_print_unhandled_exception (MonoObject *exc)
 
        if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
                message = g_strdup ("OutOfMemoryException");
+               free_message = TRUE;
        } else {
-               str = mono_object_to_string (exc, NULL);
-               if (str) {
-                       message = mono_string_to_utf8_checked (str, &error);
-                       if (!mono_error_ok (&error)) {
-                               mono_error_cleanup (&error);
-                               message = (char *) "";
-                       } else {
-                               free_message = TRUE;
+               
+               if (((MonoException*)exc)->native_trace_ips) {
+                       message = mono_exception_get_native_backtrace ((MonoException*)exc);
+                       free_message = TRUE;
+               } else {
+                       str = mono_object_to_string (exc, NULL);
+                       if (str) {
+                               message = mono_string_to_utf8_checked (str, &error);
+                               if (!mono_error_ok (&error)) {
+                                       mono_error_cleanup (&error);
+                                       message = (char *) "";
+                               } else {
+                                       free_message = TRUE;
+                               }
                        }
                }
        }
@@ -6013,7 +6044,7 @@ mono_print_unhandled_exception (MonoObject *exc)
         * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
         *         exc->vtable->klass->name, message);
         */
-       g_printerr ("\nUnhandled Exception: %s\n", message);
+       g_printerr ("\nUnhandled Exception:\n%s\n", message);
        
        if (free_message)
                g_free (message);
@@ -6060,7 +6091,7 @@ mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer a
                MONO_OBJECT_SETREF (delegate, target, target);
        }
 
-       delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
+       delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
 }
 
 /**
@@ -6080,7 +6111,11 @@ mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
 
        g_assert (addr);
 
-       if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
+       ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
+       /* Shared code */
+       if (!ji && domain != mono_get_root_domain ())
+               ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
+       if (ji) {
                method = ji->method;
                g_assert (!method->klass->generic_container);
        }