Add part3 of the Google GCI 2010 contributions
[mono.git] / mono / metadata / object.c
index 9411fddbb11750775d60d8c8e6c325595af0fa0b..32e8b3df99c5782cca93a4cdaf61d95038f6d06c 100644 (file)
@@ -79,6 +79,9 @@ get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
 static MonoString*
 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
 
+static void
+free_main_args (void);
+
 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
 static CRITICAL_SECTION ldstr_section;
@@ -185,8 +188,14 @@ mono_type_initialization_cleanup (void)
         * mono_release_type_locks
         */
        DeleteCriticalSection (&type_initialization_section);
+       g_hash_table_destroy (type_initialization_hash);
+       type_initialization_hash = NULL;
 #endif
        DeleteCriticalSection (&ldstr_section);
+       g_hash_table_destroy (blocked_thread_hash);
+       blocked_thread_hash = NULL;
+
+       free_main_args ();
 }
 
 /**
@@ -267,7 +276,9 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                        MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
                        if (!module_vtable)
                                return NULL;
-                       mono_runtime_class_init (module_vtable);
+                       exc = mono_runtime_class_init_full (module_vtable, raise_exception);
+                       if (exc)
+                               return exc;
                }
        }
        method = mono_class_get_cctor (klass);
@@ -1347,7 +1358,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 (i));
+                               imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
                        } else {
                                imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
                        }
@@ -1833,6 +1844,9 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean
        if (!class->vtable_size)
                mono_class_setup_vtable (class);
 
+       if (class->generic_class && !class->vtable)
+               mono_class_check_vtable_constraints (class, NULL);
+
        if (class->exception_type) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
@@ -2985,8 +2999,14 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
        gboolean is_static = FALSE;
        gboolean is_ref = FALSE;
        gboolean is_literal = FALSE;
+       gboolean is_ptr = FALSE;
+       MonoError error;
+       MonoType *type = mono_field_get_type_checked (field, &error);
+
+       if (!mono_error_ok (&error))
+               mono_error_raise_exception (&error);
 
-       switch (field->type->type) {
+       switch (type->type) {
        case MONO_TYPE_STRING:
        case MONO_TYPE_OBJECT:
        case MONO_TYPE_CLASS:
@@ -3009,21 +3029,24 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
        case MONO_TYPE_I8:
        case MONO_TYPE_R8:
        case MONO_TYPE_VALUETYPE:
-               is_ref = field->type->byref;
+               is_ref = type->byref;
                break;
        case MONO_TYPE_GENERICINST:
-               is_ref = !mono_type_generic_inst_is_valuetype (field->type);
+               is_ref = !mono_type_generic_inst_is_valuetype (type);
+               break;
+       case MONO_TYPE_PTR:
+               is_ptr = TRUE;
                break;
        default:
                g_error ("type 0x%x not handled in "
-                        "mono_field_get_value_object", field->type->type);
+                        "mono_field_get_value_object", type->type);
                return NULL;
        }
 
-       if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
+       if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
                is_literal = TRUE;
 
-       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+       if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
                is_static = TRUE;
 
                if (!is_literal) {
@@ -3053,8 +3076,36 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
                return o;
        }
 
+       if (is_ptr) {
+               static MonoMethod *m;
+               gpointer args [2];
+               gpointer *ptr;
+               gpointer v;
+
+               if (!m) {
+                       MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+                       m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
+                       g_assert (m);
+               }
+
+               v = &ptr;
+               if (is_literal) {
+                       get_default_field_value (domain, field, v);
+               } else if (is_static) {
+                       mono_field_static_get_value (vtable, field, v);
+               } else {
+                       mono_field_get_value (obj, field, v);
+               }
+
+               /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
+               args [0] = *ptr;
+               args [1] = mono_type_get_object (mono_domain_get (), type);
+
+               return mono_runtime_invoke (m, NULL, args, NULL);
+       }
+
        /* boxed value type */
-       klass = mono_class_from_mono_type (field->type);
+       klass = mono_class_from_mono_type (type);
 
        if (mono_class_is_nullable (klass))
                return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
@@ -3275,7 +3326,7 @@ mono_nullable_box (guint8 *buf, MonoClass *klass)
  * mono_get_delegate_invoke:
  * @klass: The delegate class
  *
- * Returns: the MonoMethod for the "Invoke" method in the delegate klass
+ * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
  */
 MonoMethod *
 mono_get_delegate_invoke (MonoClass *klass)
@@ -3287,8 +3338,6 @@ mono_get_delegate_invoke (MonoClass *klass)
        if (klass->exception_type)
                return NULL;
        im = mono_class_get_method_from_name (klass, "Invoke", -1);
-       g_assert (im);
-
        return im;
 }
 
@@ -3342,6 +3391,16 @@ mono_runtime_get_main_args (void)
        return res;
 }
 
+static void
+free_main_args (void)
+{
+       int i;
+
+       for (i = 0; i < num_main_args; ++i)
+               g_free (main_args [i]);
+       g_free (main_args);
+}
+
 /**
  * mono_runtime_run_main:
  * @method: the method to start the application with (usually Main)
@@ -3363,6 +3422,7 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        MonoArray *args = NULL;
        MonoDomain *domain = mono_domain_get ();
        gchar *utf8_fullpath;
+       MonoMethodSignature *sig;
 
        g_assert (method != NULL);
        
@@ -3417,7 +3477,14 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        }
        argc--;
        argv++;
-       if (mono_method_signature (method)->param_count) {
+
+       sig = mono_method_signature (method);
+       if (!sig) {
+               g_print ("Unable to load Main method.\n");
+               exit (-1);
+       }
+
+       if (sig->param_count) {
                args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
                for (i = 0; i < argc; ++i) {
                        /* The encodings should all work, given that
@@ -5083,8 +5150,10 @@ mono_string_get_pinned (MonoString *str)
        MonoString *news;
        size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
        news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
-       memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
-       news->length = mono_string_length (str);
+       if (news) {
+               memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
+               news->length = mono_string_length (str);
+       }
        return news;
 }
 
@@ -5108,7 +5177,8 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
        }
        if (insert) {
                str = mono_string_get_pinned (str);
-               mono_g_hash_table_insert (ldstr_table, str, str);
+               if (str)
+                       mono_g_hash_table_insert (ldstr_table, str, str);
                ldstr_unlock ();
                return str;
        } else {
@@ -5217,7 +5287,8 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
        }
 
        o = mono_string_get_pinned (o);
-       mono_g_hash_table_insert (domain->ldstr_table, o, o);
+       if (o)
+               mono_g_hash_table_insert (domain->ldstr_table, o, o);
        ldstr_unlock ();
 
        return o;
@@ -5227,8 +5298,8 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
  * mono_string_to_utf8:
  * @s: a System.String
  *
- * Return the UTF8 representation for @s.
- * the resulting buffer nedds to be freed with g_free().
+ * Returns the UTF8 representation for @s.
+ * The resulting buffer needs to be freed with mono_free().
  *
  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
  */
@@ -5243,6 +5314,15 @@ mono_string_to_utf8 (MonoString *s)
        return result;
 }
 
+/**
+ * mono_string_to_utf8_checked:
+ * @s: a System.String
+ * @error: a MonoError.
+ * 
+ * Converts a MonoString to its UTF8 representation. May fail; check 
+ * @error to determine whether the conversion was successful.
+ * The resulting buffer should be freed with mono_free().
+ */
 char *
 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
 {
@@ -5697,6 +5777,29 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
        return ret;
 }
 
+/**
+ * mono_object_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). May be NULL.
+ *
+ * Returns: the result of calling ToString () on an object.
+ */
+MonoString *
+mono_object_to_string (MonoObject *obj, MonoObject **exc)
+{
+       static MonoMethod *to_string = NULL;
+       MonoMethod *method;
+
+       g_assert (obj);
+
+       if (!to_string)
+               to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
+
+       method = mono_object_get_virtual_method (obj, to_string);
+
+       return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
+}
+
 /**
  * mono_print_unhandled_exception:
  * @exc: The exception
@@ -5706,35 +5809,25 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
 void
 mono_print_unhandled_exception (MonoObject *exc)
 {
-       MonoError error;
-       char *message = (char *) "";
-       MonoString *str; 
-       MonoMethod *method;
-       MonoClass *klass;
+       MonoString * str;
+       char *message = (char*)"";
        gboolean free_message = FALSE;
+       MonoError error;
 
-       if (mono_object_isinst (exc, mono_defaults.exception_class)) {
-               klass = exc->vtable->klass;
-               method = NULL;
-               while (klass && method == NULL) {
-                       method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
-                       if (method == NULL)
-                               klass = klass->parent;
-               }
-
-               g_assert (method);
-
-               str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
+       if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
+               message = g_strdup ("OutOfMemoryException");
+       } 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 *)"";
+                               message = (char *) "";
                        } else {
                                free_message = TRUE;
                        }
                }
-       }                               
+       }
 
        /*
         * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,