Add a new 'MONO_DEBUGGER_EVENT_TRAMPOLINE' notification for the debugger which also...
[mono.git] / mono / metadata / object.c
index 3ffb76005e24404b5d3d81a4919a57f750313e0a..ee7ecb9e25ef4668d8f2f032e1933f91123af5af 100644 (file)
@@ -40,6 +40,7 @@
 #include <mono/metadata/gc-internal.h>
 #include <mono/utils/strenc.h>
 #include <mono/utils/mono-counters.h>
+#include "cominterop.h"
 
 #ifdef HAVE_BOEHM_GC
 #define NEED_TO_ZERO_PTRFREE 1
@@ -141,6 +142,9 @@ static GHashTable *blocked_thread_hash;
 /* Main thread */
 static MonoThread *main_thread;
 
+/* Functions supplied by the runtime */
+static MonoRuntimeCallbacks callbacks;
+
 /**
  * mono_thread_set_main:
  * @thread: thread to set as the main thread
@@ -258,7 +262,10 @@ mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
                mono_image_check_for_module_cctor (klass->image);
                if (klass->image->has_module_cctor) {
                        MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
-                       mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
+                       MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
+                       if (!module_vtable)
+                               return NULL;
+                       mono_runtime_class_init (module_vtable);
                }
        }
        method = mono_class_get_cctor (klass);
@@ -428,7 +435,7 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
 }
 
 void
-mono_release_type_locks (MonoThread *thread)
+mono_release_type_locks (MonoInternalThread *thread)
 {
        mono_type_initialization_lock ();
        g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
@@ -473,6 +480,18 @@ static MonoImtThunkBuilder imt_thunk_builder = NULL;
 #error "MONO_IMT_SIZE cannot be larger than 32"
 #endif
 
+void
+mono_install_callbacks (MonoRuntimeCallbacks *cbs)
+{
+       memcpy (&callbacks, cbs, sizeof (*cbs));
+}
+
+MonoRuntimeCallbacks*
+mono_get_runtime_callbacks (void)
+{
+       return &callbacks;
+}
+
 void
 mono_install_trampoline (MonoTrampoline func) 
 {
@@ -1644,7 +1663,7 @@ mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtab
        mono_domain_unlock (domain);
 }
 
-static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
+static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
 
 /**
  * mono_class_vtable:
@@ -1657,18 +1676,37 @@ static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoCla
  */
 MonoVTable *
 mono_class_vtable (MonoDomain *domain, MonoClass *class)
+{
+       return mono_class_vtable_full (domain, class, FALSE);
+}
+
+/**
+ * mono_class_vtable_full:
+ * @domain: the application domain
+ * @class: the class to initialize
+ * @raise_on_error if an exception should be raised on failure or not
+ *
+ * VTables are domain specific because we create domain specific code, and 
+ * they contain the domain specific static class data.
+ */
+MonoVTable *
+mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
 {
        MonoClassRuntimeInfo *runtime_info;
 
        g_assert (class);
 
+       if (class->exception_type) {
+               if (raise_on_error)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
+               return NULL;
+       }
+
        /* this check can be inlined in jitted code, too */
        runtime_info = class->runtime_info;
        if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
                return runtime_info->domain_vtables [domain->domain_id];
-       if (class->exception_type)
-               return NULL;
-       return mono_class_create_runtime_vtable (domain, class);
+       return mono_class_create_runtime_vtable (domain, class, raise_on_error);
 }
 
 /**
@@ -1693,7 +1731,7 @@ mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
 }
 
 static MonoVTable *
-mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
+mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
 {
        MonoVTable *vt;
        MonoClassRuntimeInfo *runtime_info, *old_info;
@@ -1715,17 +1753,36 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                return runtime_info->domain_vtables [domain->domain_id];
        }
        if (!class->inited || class->exception_type) {
-               if (!mono_class_init (class) || class->exception_type){
-                       MonoException *exc;
+               if (!mono_class_init (class) || class->exception_type) {
                        mono_domain_unlock (domain);
                        mono_loader_unlock ();
-                       exc = mono_class_get_exception_for_failure (class);
-                       g_assert (exc);
-                       mono_raise_exception (exc);
+                       if (raise_on_error)
+                               mono_raise_exception (mono_class_get_exception_for_failure (class));
+                       return NULL;
                }
        }
 
-       mono_class_init (class);
+       /* Array types require that their element type be valid*/
+       if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
+               MonoClass *element_class = class->element_class;
+               if (!element_class->inited)
+                       mono_class_init (element_class);
+
+               /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
+               if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
+                       mono_class_setup_vtable (element_class);
+               
+               if (element_class->exception_type != MONO_EXCEPTION_NONE) {
+                       /*Can happen if element_class only got bad after mono_class_setup_vtable*/
+                       if (class->exception_type == MONO_EXCEPTION_NONE)
+                               mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+                       mono_domain_unlock (domain);
+                       mono_loader_unlock ();
+                       if (raise_on_error)
+                               mono_raise_exception (mono_class_get_exception_for_failure (class));
+                       return NULL;
+               }
+       }
 
        /* 
         * For some classes, mono_class_init () already computed class->vtable_size, and 
@@ -1737,11 +1794,13 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        if (class->exception_type) {
                mono_domain_unlock (domain);
                mono_loader_unlock ();
+               if (raise_on_error)
+                       mono_raise_exception (mono_class_get_exception_for_failure (class));
                return NULL;
        }
 
        if (ARCH_USE_IMT) {
-               vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+               vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
                if (class->interface_offsets_count) {
                        imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
                        vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
@@ -1750,7 +1809,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                }
        } else {
                vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.used_class_count++;
@@ -1892,7 +1951,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
                /* this is a bounded memory retention issue: may want to 
                 * handle it differently when we'll have a rcu-like system.
                 */
-               runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
+               runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
                runtime_info->max_domain = new_size - 1;
                /* copy the stuff from the older info */
                if (old_info) {
@@ -1936,16 +1995,15 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
        mono_loader_unlock ();
 
        /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
-       if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
-               MonoException *exc = mono_class_get_exception_for_failure (class);
-               g_assert (exc);
-               mono_raise_exception (exc);
-       }
+       if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
+               mono_raise_exception (mono_class_get_exception_for_failure (class));
 
        /* make sure the parent is initialized */
+       /*FIXME shouldn't this fail the current type?*/
        if (class->parent)
-               mono_class_vtable (domain, 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 (class->contextbound)
                vt->remote = 1;
@@ -1976,6 +2034,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        gpointer *interface_offsets;
 
        vt = mono_class_vtable (domain, class);
+       g_assert (vt); /*FIXME property handle failure*/
        max_interface_id = vt->max_interface_id;
        
        /* Calculate vtable space for extra interfaces */
@@ -2015,10 +2074,10 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                mono_stats.imt_number_of_tables++;
                mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
                vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        } else {
                vtsize = sizeof (gpointer) * (max_interface_id + 1) +
-                       sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+                       MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
        }
 
        mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
@@ -2028,7 +2087,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
        else
                pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
-       memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
+       memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
 
        pvt->klass = mono_defaults.transparent_proxy_class;
        /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
@@ -2248,12 +2307,12 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        key = mp_key;
 
        if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
                rc->interface_count = 1;
                rc->interfaces [0] = proxy_class;
                rc->proxy_class = mono_defaults.marshalbyrefobject_class;
        } else {
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
                rc->interface_count = 0;
                rc->proxy_class = proxy_class;
        }
@@ -2292,7 +2351,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 
        if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
                int i,j;
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
                rc->proxy_class = remote_class->proxy_class;
                rc->interface_count = remote_class->interface_count + 1;
                
@@ -2307,7 +2366,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
                        rc->interfaces [j] = extra_class;
        } else {
                // Replace the old class. The interface array is the same
-               rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
+               rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
                rc->proxy_class = extra_class;
                rc->interface_count = remote_class->interface_count;
                if (rc->interface_count > 0)
@@ -2454,8 +2513,14 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
                /* generic methods demand invoke_with_check */
                if (mono_method_signature (res)->generic_param_count)
                        res = mono_marshal_get_remoting_invoke_with_check (res);
-               else
-                       res = mono_marshal_get_remoting_invoke (res);
+               else {
+#ifndef DISABLE_COM
+                       if (klass == mono_defaults.com_object_class || klass->is_com_object)
+                               res = mono_cominterop_get_invoke (res);
+                       else
+#endif
+                               res = mono_marshal_get_remoting_invoke (res);
+               }
        } else {
                if (method->is_inflated) {
                        /* Have to inflate the result */
@@ -2582,6 +2647,8 @@ set_value (MonoType *type, void *dest, void *value, int deref_pointer)
 {
        int t;
        if (type->byref) {
+               /* object fields cannot be byref, so we don't need a
+                  wbarrier here */
                gpointer *p = (gpointer*)dest;
                *p = value;
                return;
@@ -2652,12 +2719,12 @@ handle_enum:
                        t = mono_class_enum_basetype (type->data.klass)->type;
                        goto handle_enum;
                } else {
-                       int size;
-                       size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
+                       MonoClass *class = mono_class_from_mono_type (type);
+                       int size = mono_class_value_size (class, NULL);
                        if (value == NULL)
                                memset (dest, 0, size);
                        else
-                               memcpy (dest, value, size);
+                               mono_gc_wbarrier_value_copy (dest, value, 1, class);
                }
                return;
        case MONO_TYPE_GENERICINST:
@@ -2813,6 +2880,12 @@ mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObje
        if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
                is_static = TRUE;
                vtable = mono_class_vtable (domain, field->parent);
+               if (!vtable) {
+                       char *name = mono_type_get_full_name (field->parent);
+                       g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
+                       g_free (name);
+                       return NULL;
+               }
                if (!vtable->initialized)
                        mono_runtime_class_init (vtable);
        }
@@ -2999,10 +3072,14 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
        g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
 
        *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
-       if (value)
-               memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
-       else
+       if (value) {
+               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
+                       memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
+       } else {
                memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
+       }
 }
 
 /**
@@ -3023,7 +3100,10 @@ mono_nullable_box (guint8 *buf, MonoClass *klass)
 
        if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
                MonoObject *o = mono_object_new (mono_domain_get (), param_class);
-               memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
+               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
+                       memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
                return o;
        }
        else
@@ -3222,6 +3302,130 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        return result;
 }
 
+static MonoObject*
+serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *serialize_method;
+
+       void *params [1];
+       MonoObject *array;
+
+       if (!serialize_method) {
+               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+               serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
+       }
+
+       if (!serialize_method) {
+               *failure = TRUE;
+               return NULL;
+       }
+
+       g_assert (!mono_object_class (obj)->marshalbyref);
+
+       params [0] = obj;
+       *exc = NULL;
+       array = mono_runtime_invoke (serialize_method, NULL, params, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return array;
+}
+
+static MonoObject*
+deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *deserialize_method;
+
+       void *params [1];
+       MonoObject *result;
+
+       if (!deserialize_method) {
+               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
+               deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+       }
+       if (!deserialize_method) {
+               *failure = TRUE;
+               return NULL;
+       }
+
+       params [0] = obj;
+       *exc = NULL;
+       result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return result;
+}
+
+static MonoObject*
+make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+{
+       static MonoMethod *get_proxy_method;
+
+       MonoDomain *domain = mono_domain_get ();
+       MonoRealProxy *real_proxy;
+       MonoReflectionType *reflection_type;
+       MonoTransparentProxy *transparent_proxy;
+
+       if (!get_proxy_method)
+               get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+       g_assert (obj->vtable->klass->marshalbyref);
+
+       real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
+       reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+
+       MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
+       MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
+
+       *exc = NULL;
+       transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
+       if (*exc)
+               *failure = TRUE;
+
+       return (MonoObject*) transparent_proxy;
+}
+
+/**
+ * mono_object_xdomain_representation
+ * @obj: an object
+ * @target_domain: a domain
+ * @exc: pointer to a MonoObject*
+ *
+ * Creates a representation of obj in the domain target_domain.  This
+ * is either a copy of obj arrived through via serialization and
+ * deserialization or a proxy, depending on whether the object is
+ * serializable or marshal by ref.  obj must not be in target_domain.
+ *
+ * If the object cannot be represented in target_domain, NULL is
+ * returned and *exc is set to an appropriate exception.
+ */
+MonoObject*
+mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
+{
+       MonoObject *deserialized = NULL;
+       gboolean failure = FALSE;
+
+       *exc = NULL;
+
+       if (mono_object_class (obj)->marshalbyref) {
+               deserialized = make_transparent_proxy (obj, &failure, exc);
+       } else {
+               MonoDomain *domain = mono_domain_get ();
+               MonoObject *serialized;
+
+               mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
+               serialized = serialize_object (obj, &failure, exc);
+               mono_domain_set_internal_with_options (target_domain, FALSE);
+               if (!failure)
+                       deserialized = deserialize_object (serialized, &failure, exc);
+               if (domain != target_domain)
+                       mono_domain_set_internal_with_options (domain, FALSE);
+       }
+
+       return deserialized;
+}
+
 /* Used in call_unhandled_exception_delegate */
 static MonoObject *
 create_unhandled_exception_eventargs (MonoObject *exc)
@@ -3255,11 +3459,38 @@ static void
 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
        MonoObject *e = NULL;
        gpointer pa [2];
+       MonoDomain *current_domain = mono_domain_get ();
+
+       if (domain != current_domain)
+               mono_domain_set_internal_with_options (domain, FALSE);
+
+       g_assert (domain == mono_object_domain (domain->domain));
+
+       if (mono_object_domain (exc) != domain) {
+               MonoObject *serialization_exc;
+
+               exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
+               if (!exc) {
+                       if (serialization_exc) {
+                               MonoObject *dummy;
+                               exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
+                               g_assert (exc);
+                       } else {
+                               exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
+                                               "System.Runtime.Serialization", "SerializationException",
+                                               "Could not serialize unhandled exception.");
+                       }
+               }
+       }
+       g_assert (mono_object_domain (exc) == domain);
 
        pa [0] = domain->domain;
        pa [1] = create_unhandled_exception_eventargs (exc);
        mono_runtime_delegate_invoke (delegate, pa, &e);
-       
+
+       if (domain != current_domain)
+               mono_domain_set_internal_with_options (current_domain, FALSE);
+
        if (e) {
                gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
                g_warning ("exception inside UnhandledException handler: %s\n", msg);
@@ -3320,7 +3551,7 @@ mono_unhandled_exception (MonoObject *exc)
        g_assert (field);
 
        if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
-               gboolean abort_process = (mono_thread_current () == main_thread) ||
+               gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
                                (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
                root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
                if (current_domain != root_domain && (mono_framework_version () >= 2)) {
@@ -3378,7 +3609,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        int rval;
        MonoCustomAttrInfo* cinfo;
        gboolean has_stathread_attribute;
-       MonoThread* thread = mono_thread_current ();
+       MonoInternalThread* thread = mono_thread_internal_current ();
 
        g_assert (args);
 
@@ -3581,8 +3812,21 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                                else
                                        t = &t->data.generic_class->container_class->byval_arg;
                                goto again;
+                       case MONO_TYPE_PTR: {
+                               MonoObject *arg;
+
+                               /* The argument should be an IntPtr */
+                               arg = mono_array_get (params, MonoObject*, i);
+                               if (arg == NULL) {
+                                       pa [i] = NULL;
+                               } else {
+                                       g_assert (arg->vtable->klass == mono_defaults.int_class);
+                                       pa [i] = ((MonoIntPtr*)arg)->m_value;
+                               }
+                               break;
+                       }
                        default:
-                               g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
+                               g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
                        }
                }
        }
@@ -3629,6 +3873,27 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                /* obj must be already unboxed if needed */
                res = mono_runtime_invoke (method, obj, pa, exc);
 
+               if (sig->ret->type == MONO_TYPE_PTR) {
+                       MonoClass *pointer_class;
+                       static MonoMethod *box_method;
+                       void *box_args [2];
+                       MonoObject *box_exc;
+
+                       /* 
+                        * The runtime-invoke wrapper returns a boxed IntPtr, need to 
+                        * convert it to a Pointer object.
+                        */
+                       pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
+                       if (!box_method)
+                               box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
+
+                       g_assert (res->vtable->klass == mono_defaults.int_class);
+                       box_args [0] = ((MonoIntPtr*)res)->m_value;
+                       box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
+                       res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
+                       g_assert (!box_exc);
+               }
+
                if (has_byref_nullables) {
                        /* 
                         * The runtime invoke wrapper already converted byref nullables back,
@@ -3706,12 +3971,19 @@ mono_object_allocate_spec (size_t size, MonoVTable *vtable)
  * looked up using @klass.   This will not invoke any constructors, 
  * so the consumer of this routine has to invoke any constructors on
  * its own to initialize the object.
+ * 
+ * It returns NULL on failure.
  */
 MonoObject *
 mono_object_new (MonoDomain *domain, MonoClass *klass)
 {
+       MonoVTable *vtable;
+
        MONO_ARCH_SAVE_REGS;
-       return mono_object_new_specific (mono_class_vtable (domain, klass));
+       vtable = mono_class_vtable (domain, klass);
+       if (!vtable)
+               return NULL;
+       return mono_object_new_specific (vtable);
 }
 
 /**
@@ -3893,17 +4165,17 @@ MonoObject *
 mono_object_clone (MonoObject *obj)
 {
        MonoObject *o;
-       int size;
+       int size = obj->vtable->klass->instance_size;
 
-       size = obj->vtable->klass->instance_size;
        o = mono_object_allocate (size, obj->vtable);
-       /* do not copy the sync state */
-       memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
 
-#ifdef HAVE_SGEN_GC
-       if (obj->vtable->klass->has_references)
-               mono_gc_wbarrier_object (o);
-#endif
+       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 */
+               memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
+       }
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, obj->vtable->klass);
 
@@ -4039,6 +4311,24 @@ mono_array_clone (MonoArray *array)
                                         ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
 #endif
 
+gboolean
+mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
+{
+       mono_array_size_t byte_len;
+
+       byte_len = mono_array_element_size (class);
+       if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+               return FALSE;
+       byte_len *= len;
+       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
+               return FALSE;
+       byte_len += sizeof (MonoArray);
+
+       *res = byte_len;
+
+       return TRUE;
+}
+
 /**
  * mono_array_new_full:
  * @domain: domain where the object is created
@@ -4055,13 +4345,13 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
        mono_array_size_t byte_len, len, bounds_size;
        MonoObject *o;
        MonoArray *array;
+       MonoArrayBounds *bounds;
        MonoVTable *vtable;
        int i;
 
        if (!array_class->inited)
                mono_class_init (array_class);
 
-       byte_len = mono_array_element_size (array_class);
        len = 1;
 
        /* A single dimensional array with a 0 lower bound is the same as an szarray */
@@ -4082,12 +4372,9 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
                }
        }
 
-       if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+       if (!mono_array_calc_byte_len (array_class, len, &byte_len))
                mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-       byte_len *= len;
-       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
-               mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-       byte_len += sizeof (MonoArray);
+
        if (bounds_size) {
                /* align */
                if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
@@ -4101,7 +4388,8 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
         */
-       vtable = mono_class_vtable (domain, array_class);
+       vtable = mono_class_vtable_full (domain, array_class, TRUE);
+#ifndef HAVE_SGEN_GC
        if (!array_class->has_references) {
                o = mono_object_allocate_ptrfree (byte_len, vtable);
 #if NEED_TO_ZERO_PTRFREE
@@ -4117,8 +4405,21 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size
        array->max_length = len;
 
        if (bounds_size) {
-               MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
+               bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
                array->bounds = bounds;
+       }
+#else
+       if (bounds_size)
+               o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
+       else
+               o = mono_gc_alloc_vector (vtable, byte_len, len);
+       array = (MonoArray*)o;
+       mono_stats.new_object_count++;
+
+       bounds = array->bounds;
+#endif
+
+       if (bounds_size) {
                for (i = 0; i < array_class->rank; ++i) {
                        bounds [i].length = lengths [i];
                        if (lower_bounds)
@@ -4150,7 +4451,7 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
        ac = mono_array_class_get (eclass, 1);
        g_assert (ac);
 
-       return mono_array_new_specific (mono_class_vtable (domain, ac), n);
+       return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
 }
 
 /**
@@ -4166,7 +4467,7 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
 {
        MonoObject *o;
        MonoArray *ao;
-       guint32 byte_len, elem_size;
+       guint32 byte_len;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -4174,18 +4475,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
                arith_overflow ();
                return NULL;
        }
-       
-       elem_size = mono_array_element_size (vtable->klass);
-       if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
-               mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
-               return NULL;
-       }
-       byte_len = n * elem_size;
-       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
+
+       if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
                mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
                return NULL;
        }
-       byte_len += sizeof (MonoArray);
+#ifndef HAVE_SGEN_GC
        if (!vtable->klass->has_references) {
                o = mono_object_allocate_ptrfree (byte_len, vtable);
 #if NEED_TO_ZERO_PTRFREE
@@ -4201,6 +4496,12 @@ mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
 
        ao = (MonoArray *)o;
        ao->max_length = n;
+#else
+       o = mono_gc_alloc_vector (vtable, byte_len, n);
+       ao = (MonoArray*)o;
+       mono_stats.new_object_count++;
+#endif
+
        if (G_UNLIKELY (profile_allocs))
                mono_profiler_allocation (o, vtable->klass);
 
@@ -4246,6 +4547,7 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
                mono_gc_out_of_memory (-1);
 
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
+       g_assert (vtable);
 
        s = mono_object_allocate_ptrfree (size, vtable);
 
@@ -4371,6 +4673,8 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
                return mono_nullable_box (value, class);
 
        vtable = mono_class_vtable (domain, class);
+       if (!vtable)
+               return NULL;
        size = mono_class_instance_size (class);
        res = mono_object_new_alloc_specific (vtable);
        if (G_UNLIKELY (profile_allocs))
@@ -4379,9 +4683,9 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        size = size - sizeof (MonoObject);
 
 #ifdef HAVE_SGEN_GC
+       g_assert (size == mono_class_value_size (class, NULL));
        mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
-#endif
-
+#else
 #if NO_UNALIGNED_ACCESS
        memcpy ((char *)res + sizeof (MonoObject), value, size);
 #else
@@ -4401,6 +4705,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        default:
                memcpy ((char *)res + sizeof (MonoObject), value, size);
        }
+#endif
 #endif
        if (class->has_finalize)
                mono_object_register_finalizer (res);
@@ -4419,9 +4724,7 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 void
 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
 {
-       int size = mono_class_value_size (klass, NULL);
        mono_gc_wbarrier_value_copy (dest, src, 1, klass);
-       memcpy (dest, src, size);
 }
 
 /*
@@ -4440,8 +4743,8 @@ mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
 {
        int size = mono_array_element_size (dest->obj.vtable->klass);
        char *d = mono_array_addr_with_size (dest, size, dest_idx);
+       g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
        mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
-       memmove (d, src, size * count);
 }
 
 /**
@@ -4943,7 +5246,7 @@ mono_raise_exception (MonoException *ex)
         */
 
        if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
-               MonoThread *thread = mono_thread_current ();
+               MonoInternalThread *thread = mono_thread_internal_current ();
                g_assert (ex->object.vtable->domain == mono_domain_get ());
                MONO_OBJECT_SETREF (thread, abort_exc, ex);
        }
@@ -4965,11 +5268,11 @@ mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
        gpointer params [1];
        static MonoMethod *handle_set;
 
-       res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
+       res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
 
        /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
        if (!handle_set)
-               handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
+               handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
 
        params [0] = &handle;
        mono_runtime_invoke (handle_set, res, params, NULL);
@@ -4984,8 +5287,8 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle)
        static MonoClassField *f_safe_handle;
 
        if (!f_os_handle && !f_safe_handle) {
-               f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
-               f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
+               f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
+               f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
        }
 
        if (f_os_handle) {
@@ -5296,7 +5599,7 @@ mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer a
                method = mono_marshal_get_remoting_invoke (method);
                delegate->method_ptr = mono_compile_method (method);
                MONO_OBJECT_SETREF (delegate, target, target);
-       } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
+       } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
                method = mono_marshal_get_unbox_wrapper (method);
                delegate->method_ptr = mono_compile_method (method);
                MONO_OBJECT_SETREF (delegate, target, target);
@@ -5420,42 +5723,22 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        arg = mono_array_get (out_args, gpointer, j);
                        type = pt->type;
 
-                       switch (type) {
-                       case MONO_TYPE_VOID:
-                               g_assert_not_reached ();
-                               break;
-                       case MONO_TYPE_U1:
-                       case MONO_TYPE_I1:
-                       case MONO_TYPE_BOOLEAN:
-                       case MONO_TYPE_U2:
-                       case MONO_TYPE_I2:
-                       case MONO_TYPE_CHAR:
-                       case MONO_TYPE_U4:
-                       case MONO_TYPE_I4:
-                       case MONO_TYPE_I8:
-                       case MONO_TYPE_U8:
-                       case MONO_TYPE_R4:
-                       case MONO_TYPE_R8:
-                       case MONO_TYPE_VALUETYPE: {
+                       g_assert (type != MONO_TYPE_VOID);
+
+                       if (MONO_TYPE_IS_REFERENCE (pt)) {
+                               mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
+                       } else {
                                if (arg) {
-                                       size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
-                                       memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
-                               }
-                               else {
+                                       MonoClass *class = ((MonoObject*)arg)->vtable->klass;
+                                       size = mono_class_value_size (class, NULL);
+                                       if (class->has_references)
+                                               mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
+                                       else
+                                               memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
+                               } else {
                                        size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
                                        memset (*((gpointer *)params [i]), 0, size);
                                }
-                               break;
-                       }
-                       case MONO_TYPE_STRING:
-                       case MONO_TYPE_CLASS: 
-                       case MONO_TYPE_ARRAY:
-                       case MONO_TYPE_SZARRAY:
-                       case MONO_TYPE_OBJECT:
-                               **((MonoObject ***)params [i]) = (MonoObject *)arg;
-                               break;
-                       default:
-                               g_assert_not_reached ();
                        }
 
                        j++;
@@ -5704,49 +5987,24 @@ mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField
  * mono_create_ftnptr:
  *
  *   Given a function address, create a function descriptor for it.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
 {
-#ifdef __ia64__
-       gpointer *desc;
-
-       desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
-
-       desc [0] = addr;
-       desc [1] = NULL;
-
-       return desc;
-#elif defined(__ppc64__) || defined(__powerpc64__)
-       gpointer *desc;
-
-       desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
-
-       desc [0] = addr;
-       desc [1] = NULL;
-       desc [2] = NULL;
-
-       return desc;
-#else
-       return addr;
-#endif
+       return callbacks.create_ftnptr (domain, addr);
 }
 
 /*
  * mono_get_addr_from_ftnptr:
  *
  *   Given a pointer to a function descriptor, return the function address.
- * This is only needed on IA64 and PPC64.
+ * This is only needed on some platforms.
  */
 gpointer
 mono_get_addr_from_ftnptr (gpointer descr)
 {
-#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
-       return *(gpointer*)descr;
-#else
-       return descr;
-#endif
+       return callbacks.get_addr_from_ftnptr (descr);
 }      
 
 #if 0