2004-03-22 Ben Maurer <bmaurer@users.sourceforge.net>
[mono.git] / mono / metadata / object.c
index 4904d3316afb103eb9ee14ef0d941fc406ca1c49..952b1f4f9f735575fe48d26cbc481ce131e73dc4 100644 (file)
@@ -3,8 +3,9 @@
  *
  * Author:
  *   Miguel de Icaza (miguel@ximian.com)
+ *   Paolo Molaro (lupus@ximian.com)
  *
- * (C) 2001 Ximian, Inc.
+ * (C) 2001-2004 Ximian, Inc.
  */
 #include <config.h>
 #include <stdlib.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/object.h>
-#include <mono/metadata/gc.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/exception.h>
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/threadpool.h>
 #include <mono/metadata/marshal.h>
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/marshal.h"
-#if HAVE_BOEHM_GC
-#include <gc/gc.h>
+#include <mono/metadata/threads.h>
+#include <mono/metadata/environment.h>
+#include "mono/metadata/profiler-private.h"
+#include <mono/os/gc_wrapper.h>
+#include <mono/utils/strenc.h>
+
+/*
+ * Enable experimental typed allocation using the GC_gcj_malloc function.
+ */
+#ifdef HAVE_GC_GCJ_MALLOC
+#define CREATION_SPEEDUP 1
 #endif
 
 void
@@ -48,26 +59,86 @@ mono_runtime_object_init (MonoObject *this)
 }
 
 /*
- * runtime_class_init:
- * @klass: klass that needs to be initialized
+ * mono_runtime_class_init:
+ * @vtable: vtable that needs to be initialized
  *
- * This routine calls the class constructor for @class.
+ * This routine calls the class constructor for @vtable.
  */
 void
-mono_runtime_class_init (MonoClass *klass)
+mono_runtime_class_init (MonoVTable *vtable)
 {
        int i;
+       MonoException *exc;
+       MonoException *exc_to_throw;
+       MonoMethod *method = NULL;
+       MonoClass *klass;
+       gchar *full_name;
+       gboolean found;
+       MonoDomain *last_domain = NULL;
+
+       MONO_ARCH_SAVE_REGS;
+
+       if (vtable->initialized || vtable->initializing)
+               return;
+
+       exc = NULL;
+       found = FALSE;
+       klass = vtable->klass;
 
        for (i = 0; i < klass->method.count; ++i) {
-               MonoMethod *method = klass->methods [i];
+               method = klass->methods [i];
                if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
                    (strcmp (".cctor", method->name) == 0)) {
-                       mono_runtime_invoke (method, NULL, NULL, NULL);
+                       found = TRUE;
+                       break;
+               }
+       }
+
+       if (found) {
+               mono_domain_lock (vtable->domain);
+               /* double check... */
+               if (vtable->initialized || vtable->initializing) {
+                       mono_domain_unlock (vtable->domain);
                        return;
                }
+               vtable->initializing = 1;
+               if (mono_domain_get () != vtable->domain) {
+                       /* Transfer into the target domain */
+                       last_domain = mono_domain_get ();
+                       if (!mono_domain_set (vtable->domain, FALSE)) {
+                               vtable->initialized = 1;
+                               vtable->initializing = 0;
+                               mono_domain_unlock (vtable->domain);
+                               mono_raise_exception (mono_get_exception_appdomain_unloaded ());
+                       }
+               }
+               mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
+               if (last_domain)
+                       mono_domain_set (last_domain, TRUE);
+               vtable->initialized = 1;
+               vtable->initializing = 0;
+               /* FIXME: if the cctor fails, the type must be marked as unusable */
+               mono_domain_unlock (vtable->domain);
+       } else {
+               vtable->initialized = 1;
+               return;
        }
 
-       /* No class constructor found */
+       if (exc == NULL ||
+           (klass->image == mono_defaults.corlib &&            
+            !strcmp (klass->name_space, "System") &&
+            !strcmp (klass->name, "TypeInitializationException")))
+               return; /* No static constructor found or avoid infinite loop */
+
+       if (klass->name_space && *klass->name_space)
+               full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
+       else
+               full_name = g_strdup (klass->name);
+
+       exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
+       g_free (full_name);
+
+       mono_raise_exception (exc_to_throw);
 }
 
 static gpointer
@@ -124,6 +195,170 @@ vtable_finalizer (void *obj, void *data) {
 }
 #endif
 
+#if CREATION_SPEEDUP
+
+#define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
+
+/*
+ * The vtables in the root appdomain are assumed to be reachable by other 
+ * roots, and we don't use typed allocation in the other domains.
+ */
+
+#define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
+
+static void
+mono_class_compute_gc_descriptor (MonoClass *class)
+{
+       MonoClassField *field;
+       guint64 bitmap;
+       guint32 bm [2];
+       int i;
+       static gboolean gcj_inited = FALSE;
+
+       if (!gcj_inited) {
+               gcj_inited = TRUE;
+
+               GC_init_gcj_malloc (5, NULL);
+       }
+
+       if (!class->inited)
+               mono_class_init (class);
+
+       if (class->gc_descr_inited)
+               return;
+
+       class->gc_descr_inited = TRUE;
+       class->gc_descr = GC_NO_DESCRIPTOR;
+
+       if (class == mono_defaults.string_class) {
+               bitmap = GC_HEADER_BITMAP;
+               class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
+       }
+       else if (class->rank) {
+               mono_class_compute_gc_descriptor (class->element_class);
+
+               if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
+                       bitmap = GC_HEADER_BITMAP;
+                       if (class->rank > 1)
+                               bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
+                       class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
+               }
+       }
+       else {
+               static int count = 0;
+               MonoClass *p;
+               guint32 pos;
+
+               /* GC 6.1 has trouble handling 64 bit descriptors... */
+               if ((class->instance_size / sizeof (gpointer)) > 30) {
+//                     printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer));
+                       return;
+               }
+
+               bitmap = GC_HEADER_BITMAP;
+
+               count ++;
+
+//             if (count > 442)
+//                     return;
+
+//             printf("KLASS: %s.\n", class->name);
+
+               for (p = class; p != NULL; p = p->parent) {
+               for (i = 0; i < p->field.count; ++i) {
+                       field = &p->fields [i];
+                       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                               continue;
+                       if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
+                               return;
+
+                       pos = field->offset / sizeof (gpointer);
+                       
+                       if (field->type->byref)
+                               return;
+
+                       switch (field->type->type) {
+                       case MONO_TYPE_BOOLEAN:
+                       case MONO_TYPE_I1:
+                       case MONO_TYPE_U1:
+                       case MONO_TYPE_I2:
+                       case MONO_TYPE_U2:
+                       case MONO_TYPE_CHAR:
+                       case MONO_TYPE_I4:
+                       case MONO_TYPE_U4:
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_U8:
+                       case MONO_TYPE_R4:
+                       case MONO_TYPE_R8:
+//                             printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap);
+                               break;
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_PTR:
+                               g_assert ((field->offset % sizeof(gpointer)) == 0);
+
+                               bitmap |= ((guint64)1) << pos;
+//                             printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap);
+                               break;
+                       case MONO_TYPE_VALUETYPE: {
+                               MonoClass *fclass = field->type->data.klass;
+                               if (!fclass->enumtype) {
+                                       mono_class_compute_gc_descriptor (fclass);
+                                       bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
+                               }
+                               break;
+                       }
+                       default:
+                               return;
+                       }
+               }
+               }
+
+//             printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap);
+               class->gc_bitmap = bitmap;
+               /* Convert to the format expected by GC_make_descriptor */
+               bm [0] = (guint32)bitmap;
+               bm [1] = (guint32)(bitmap >> 32);
+               class->gc_descr = (gpointer)GC_make_descriptor (&bm, class->instance_size / sizeof (gpointer));
+       }
+}
+#endif /* CREATION_SPEEDUP */
+
+/**
+ * field_is_special_static:
+ *
+ * Returns SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
+ * SPECIAL_STATIC_NONE otherwise.
+ */
+static gint32
+field_is_special_static (MonoClass *fklass, MonoClassField *field)
+{
+       MonoCustomAttrInfo *ainfo;
+       int i;
+       ainfo = mono_custom_attrs_from_field (fklass, field);
+       if (!ainfo)
+               return FALSE;
+       for (i = 0; i < ainfo->num_attrs; ++i) {
+               MonoClass *klass = ainfo->attrs [i].ctor->klass;
+               if (klass->image == mono_defaults.corlib) {
+                       if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
+                               mono_custom_attrs_free (ainfo);
+                               return SPECIAL_STATIC_THREAD;
+                       }
+                       else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
+                               mono_custom_attrs_free (ainfo);
+                               return SPECIAL_STATIC_CONTEXT;
+                       }
+               }
+       }
+       mono_custom_attrs_free (ainfo);
+       return SPECIAL_STATIC_NONE;
+}
+
 /**
  * mono_class_vtable:
  * @domain: the application domain
@@ -135,14 +370,14 @@ vtable_finalizer (void *obj, void *data) {
 MonoVTable *
 mono_class_vtable (MonoDomain *domain, MonoClass *class)
 {
-       MonoClass *k;
-       MonoVTable *vt;
+       MonoVTable *vt = NULL;
        MonoClassField *field;
-       guint32 cindex;
-       guint32 cols [MONO_CONSTANT_SIZE];
        const char *p;
        char *t;
        int i, len;
+       guint32 vtable_size;
+       guint32 cindex;
+       guint32 constant_cols [MONO_CONSTANT_SIZE];
 
        g_assert (class);
 
@@ -150,10 +385,6 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
        if (vt && vt->domain == domain)
                return vt;
 
-       /* can interfaces have static fields? */
-       if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
-               g_assert_not_reached ();
-
        mono_domain_lock (domain);
        if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
                mono_domain_unlock (domain);
@@ -166,14 +397,36 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
        mono_stats.used_class_count++;
        mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
-       vt = mono_mempool_alloc0 (domain->mp,  sizeof (MonoVTable) + 
-                                 class->vtable_size * sizeof (gpointer));
+       vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
+
+       vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
+
        vt->klass = class;
        vt->domain = domain;
 
+#if CREATION_SPEEDUP
+       mono_class_compute_gc_descriptor (class);
+       if (domain != mono_root_domain)
+               /*
+                * We can't use typed allocation in the non-root domains, since the
+                * collector needs the GC descriptor stored in the vtable even after
+                * the mempool containing the vtable is destroyed when the domain is
+                * unloaded. An alternative might be to allocate vtables in the GC
+                * heap, but this does not seem to work (it leads to crashes inside
+                * libgc). If that approach is tried, two gc descriptors need to be
+                * allocated for each class: one for the root domain, and one for all
+                * other domains. The second descriptor should contain a bit for the
+                * vtable field in MonoObject, since we can no longer assume the 
+                * vtable is reachable by other roots after the appdomain is unloaded.
+                */
+               vt->gc_descr = GC_NO_DESCRIPTOR;
+       else
+               vt->gc_descr = class->gc_descr;
+#endif
+
        if (class->class_size) {
 #if HAVE_BOEHM_GC
-               vt->data = GC_malloc (class->class_size + 8);
+               vt->data = GC_MALLOC (class->class_size + 8);
                /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
                /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
                mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
@@ -184,30 +437,55 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                mono_stats.class_static_data_size += class->class_size + 8;
        }
 
+       cindex = -1;
        for (i = class->field.first; i < class->field.last; ++i) {
                field = &class->fields [i - class->field.first];
                if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
                        continue;
+               if (mono_field_is_deleted (field))
+                       continue;
+               if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
+                       gint32 special_static = field_is_special_static (class, field);
+                       if (special_static != SPECIAL_STATIC_NONE) {
+                               guint32 size, align, offset;
+                               size = mono_type_size (field->type, &align);
+                               offset = mono_alloc_special_static_data (special_static, size, align);
+                               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));
+                               continue;
+                       }
+               }
                if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
                        MonoClass *fklass = mono_class_from_mono_type (field->type);
                        t = (char*)vt->data + field->offset;
-                       g_assert (fklass->valuetype);
-                       memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+                       if (fklass->valuetype) {
+                               memcpy (t, field->data, mono_class_value_size (fklass, NULL));
+                       } else {
+                               /* it's a pointer type: add check */
+                               g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
+                               *t = *(char *)field->data;
+                       }
                        continue;
                }
                if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
                        continue;
-               cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
-               if (!cindex) {
-                       g_warning ("constant for field %s not found", field->name);
-                       continue;
+
+               if (!field->def_value) {
+                       cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
+                       g_assert (cindex);
+
+                       mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
+                       field->def_value = g_new0 (MonoConstant, 1);
+                       field->def_value->type = constant_cols [MONO_CONSTANT_TYPE];
+                       field->def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
                }
-               mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
-               p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
+
+               p = field->def_value->value;
                len = mono_metadata_decode_blob_size (p, &p);
                t = (char*)vt->data + field->offset;
                /* should we check that the type matches? */
-               switch (cols [MONO_CONSTANT_TYPE]) {
+               switch (field->def_value->type) {
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_U1:
                case MONO_TYPE_I1:
@@ -262,7 +540,7 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                        /* nothing to do, we malloc0 the data and the value can be 0 only */
                        break;
                default:
-                       g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
+                       g_warning ("type 0x%02x should not be in constant table", field->def_value->type);
                }
        }
 
@@ -272,15 +550,20 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                sizeof (gpointer) * (class->max_interface_id + 1));
 
        /* initialize interface offsets */
-       for (k = class; k ; k = k->parent) {
-               for (i = 0; i < k->interface_count; i++) {
-                       int slot;
-                       MonoClass *ic = k->interfaces [i];
-                       slot = class->interface_offsets [ic->interface_id];
-                       vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
-               }
+       for (i = 0; i <= class->max_interface_id; ++i) {
+               int slot = class->interface_offsets [i];
+               if (slot >= 0)
+                       vt->interface_offsets [i] = &(vt->vtable [slot]);
        }
 
+       /* 
+        * arch_create_jit_trampoline () can recursively call this function again
+        * because it compiles icall methods right away.
+        */
+       mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
+       if (!class->cached_vtable)
+               class->cached_vtable = vt;
+
        /* initialize vtable */
        for (i = 0; i < class->vtable_size; ++i) {
                MonoMethod *cm;
@@ -289,46 +572,62 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
                        vt->vtable [i] = arch_create_jit_trampoline (cm);
        }
 
-       mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
-       if (!class->cached_vtable)
-               class->cached_vtable = vt;
-
        mono_domain_unlock (domain);
 
        /* make sure the the parent is initialized */
        if (class->parent)
                mono_class_vtable (domain, class->parent);
 
-       mono_runtime_class_init (class);
-       
+       vt->type = mono_type_get_object (domain, &class->byval_arg);
+       if (class->contextbound)
+               vt->remote = 1;
+       else
+               vt->remote = 0;
+
        return vt;
 }
 
 /**
  * mono_class_proxy_vtable:
  * @domain: the application domain
- * @class: the class to proxy
+ * @remove_class: the remote class
  *
  * Creates a vtable for transparent proxies. It is basically
- * a copy of the real vtable of @class, but all function pointers invoke
- * the remoting functions, and vtable->klass points to the 
- * transparent proxy class, and not to @class.
+ * a copy of the real vtable of the class wrapped in @remote_class,
+ * but all function pointers invoke the remoting functions, and
+ * vtable->klass points to the transparent proxy class, and not to @class.
  */
-MonoVTable *
-mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
+static MonoVTable *
+mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class)
 {
        MonoVTable *vt, *pvt;
-       int i, vtsize;
-
-       if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
-               return pvt;
+       int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
+       MonoClass *k;
+       MonoClass *class = remote_class->proxy_class;
 
        vt = mono_class_vtable (domain, class);
+       max_interface_id = vt->max_interface_id;
+
+       /* Calculate vtable space for extra interfaces */
+       for (j = 0; j < remote_class->interface_count; j++) {
+               MonoClass* iclass = remote_class->interfaces[j];
+               int method_count = iclass->method.count;
+       
+               if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
+                       continue;       /* interface implemented by the class */
+
+               for (i = 0; i < iclass->interface_count; i++)
+                       method_count += iclass->interfaces[i]->method.count;
+
+               extra_interface_vtsize += method_count * sizeof (gpointer);
+               if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
+       }
+
        vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
 
-       mono_stats.class_vtable_size += vtsize;
+       mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
 
-       pvt = mono_mempool_alloc (domain->mp, vtsize);
+       pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
        memcpy (pvt, vt, vtsize);
 
        pvt->klass = mono_defaults.transparent_proxy_class;
@@ -336,39 +635,240 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
        /* initialize vtable */
        for (i = 0; i < class->vtable_size; ++i) {
                MonoMethod *cm;
-              
+                   
                if ((cm = class->vtable [i]))
                        pvt->vtable [i] = arch_create_remoting_trampoline (cm);
        }
 
-       mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
+       if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
+       {
+               /* create trampolines for abstract methods */
+               for (k = class; k; k = k->parent) {
+                       for (i = 0; i < k->method.count; i++) {
+                               int slot = k->methods [i]->slot;
+                               if (!pvt->vtable [slot]) 
+                                       pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i]);
+                       }
+               }
+       }
+
+       pvt->max_interface_id = max_interface_id;
+       pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
+                       sizeof (gpointer) * (max_interface_id + 1));
+
+       /* initialize interface offsets */
+       for (i = 0; i <= class->max_interface_id; ++i) {
+               int slot = class->interface_offsets [i];
+               if (slot >= 0)
+                       pvt->interface_offsets [i] = &(pvt->vtable [slot]);
+       }
+
+       if (remote_class->interface_count > 0)
+       {
+               int slot = class->vtable_size;
+               MonoClass* interf;
+               MonoClass* iclass;
+               int n;
+
+               /* Create trampolines for the methods of the interfaces */
+               for (n = 0; n < remote_class->interface_count; n++) 
+               {
+                       iclass = remote_class->interfaces[n];
+                       if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
+                               continue;       /* interface implemented by the class */
+               
+                       i = -1;
+                       interf = iclass;
+                       do {
+                               pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
+       
+                               for (j = 0; j < interf->method.count; ++j) {
+                                       MonoMethod *cm = interf->methods [j];
+                                       pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm);
+                               }
+                               slot += interf->method.count;
+                               if (++i < iclass->interface_count) interf = iclass->interfaces[i];
+                               else interf = NULL;
+                               
+                       } while (interf);
+               }
+       }
 
        return pvt;
 }
 
-static MonoInvokeFunc default_mono_runtime_invoke = NULL;
+/**
+ * mono_remote_class:
+ * @domain: the application domain
+ * @class_name: name of the remote class
+ *
+ * Creates and initializes a MonoRemoteClass object for a remote type. 
+ * 
+ */
+MonoRemoteClass*
+mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
+{
+       MonoRemoteClass *rc;
+
+       mono_domain_lock (domain);
+       rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
 
-MonoObject*
-mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+       if (rc) {
+               mono_domain_unlock (domain);
+               return rc;
+       }
+
+       rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
+       rc->vtable = NULL;
+       rc->interface_count = 0;
+       rc->interfaces = NULL;
+       rc->proxy_class = mono_defaults.marshalbyrefobject_class;
+       rc->proxy_class_name = mono_string_to_utf8 (class_name);
+
+       mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
+       mono_upgrade_remote_class (domain, rc, proxy_class);
+
+       if (rc->vtable == NULL)
+               rc->vtable = mono_class_proxy_vtable (domain, rc);
+
+       mono_domain_unlock (domain);
+
+       return rc;
+}
+
+static void
+extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
 {
-       if (!default_mono_runtime_invoke) {
-               g_error ("runtime invoke called on uninitialized runtime");
-               return NULL;
+       /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
+
+       int current_size = ((remote_class->interface_count / 5) + 1) * 5;
+       remote_class->interface_count += amount;
+
+       if (remote_class->interface_count > current_size || remote_class->interfaces == NULL) 
+       {
+               int new_size = ((remote_class->interface_count / 5) + 1) * 5;
+               MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
+       
+               if (remote_class->interfaces != NULL)
+                       memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
+               
+               remote_class->interfaces = new_array;
        }
+}
+
+
+/**
+ * mono_upgrade_remote_class:
+ * @domain: the application domain
+ * @remote_class: the remote class
+ * @klass: class to which the remote class can be casted.
+ *
+ * Updates the vtable of the remote class by adding the necessary method slots
+ * and interface offsets so it can be safely casted to klass. klass can be a
+ * class or an interface.
+ */
+void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
+{
+       gboolean redo_vtable;
+
+       mono_domain_lock (domain);
 
+       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               int i;
+               redo_vtable = TRUE;
+               for (i = 0; i < remote_class->interface_count; i++)
+                       if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
+                               
+               if (redo_vtable) {
+                       extend_interface_array (domain, remote_class, 1);
+                       remote_class->interfaces [remote_class->interface_count-1] = klass;
+               }
+       }
+       else {
+               redo_vtable = (remote_class->proxy_class != klass);
+               remote_class->proxy_class = klass;
+       }
+
+       if (redo_vtable)
+               remote_class->vtable = mono_class_proxy_vtable (domain, remote_class);
+/*
+       int n;
+       printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
+       
+       for (n=0; n<remote_class->interface_count; n++)
+               printf ("  I:%s\n", remote_class->interfaces[n]->name);
+*/
+
+       mono_domain_unlock (domain);
+}
+
+/*
+ * Retrieve the MonoMethod that would to be called on obj if obj is passed as
+ * the instance of a callvirt of method.
+ */
+MonoMethod*
+mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
+       MonoClass *klass;
+       MonoMethod **vtable;
+       gboolean is_proxy;
+       MonoMethod *res = NULL;
+
+       klass = mono_object_class (obj);
+       if (klass == mono_defaults.transparent_proxy_class) {
+               klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+               is_proxy = TRUE;
+       } else {
+               is_proxy = FALSE;
+       }
+
+       if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
+                       return method;
+
+       vtable = klass->vtable;
+
+       /* check method->slot is a valid index: perform isinstance? */
+       if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               if (!is_proxy)
+                       res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
+       } else {
+               res = vtable [method->slot];
+       }
+
+       if (is_proxy) {
+               if (!res) res = method;   /* It may be an interface or abstract class method */
+               res = mono_marshal_get_remoting_invoke (res);
+       }
+
+       g_assert (res);
+       
+       return res;
+}
+
+static MonoObject*
+dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+{
+       g_error ("runtime invoke called on uninitialized runtime");
+       return NULL;
+}
+
+static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
+
+MonoObject*
+mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+{
        return default_mono_runtime_invoke (method, obj, params, exc);
 }
 
 static void
-set_value (MonoType *type, void *dest, void *value) {
+set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
        int t;
        if (type->byref) {
                gpointer *p = (gpointer*)dest;
                *p = value;
                return;
        }
-handle_enum:
        t = type->type;
+handle_enum:
        switch (t) {
        case MONO_TYPE_BOOLEAN:
        case MONO_TYPE_I1:
@@ -421,7 +921,7 @@ handle_enum:
        case MONO_TYPE_ARRAY:
        case MONO_TYPE_PTR: {
                gpointer *p = (gpointer*)dest;
-               *p = value;
+               *p = deref_pointer? *(gpointer*)value: value;
                return;
        }
        case MONO_TYPE_VALUETYPE:
@@ -448,7 +948,7 @@ mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
 
        dest = (char*)obj + field->offset;
-       set_value (field->type, dest, value);
+       set_value (field->type, dest, value, FALSE);
 }
 
 void
@@ -459,7 +959,7 @@ mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
        g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
 
        dest = (char*)vt->data + field->offset;
-       set_value (field->type, dest, value);
+       set_value (field->type, dest, value, FALSE);
 }
 
 void
@@ -470,9 +970,80 @@ mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
        g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
 
        src = (char*)obj + field->offset;
-       set_value (field->type, value, src);
+       set_value (field->type, value, src, TRUE);
+}
+
+MonoObject *
+mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
+{      
+       MonoObject *o;
+       MonoClass *klass;
+       MonoVTable *vtable = NULL;
+       gchar *v;
+       gboolean is_static = FALSE;
+       gboolean is_ref = FALSE;
+
+       switch (field->type->type) {
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_SZARRAY:
+               is_ref = TRUE;
+               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_U:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_R8:
+       case MONO_TYPE_VALUETYPE:
+               is_ref = field->type->byref;
+               break;
+       default:
+               g_error ("type 0x%x not handled in "
+                        "mono_field_get_value_object", field->type->type);
+               return NULL;
+       }
+
+       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
+               is_static = TRUE;
+               vtable = mono_class_vtable (domain, field->parent);
+               if (!vtable->initialized)
+                       mono_runtime_class_init (vtable);
+       }
+       
+       if (is_ref) {
+               if (is_static) {
+                       mono_field_static_get_value (vtable, field, &o);
+               } else {
+                       mono_field_get_value (obj, field, &o);
+               }
+               return o;
+       }
+
+       /* boxed value type */
+       klass = mono_class_from_mono_type (field->type);
+       o = mono_object_new (domain, klass);
+       v = ((gchar *) o) + sizeof (MonoObject);
+       if (is_static) {
+               mono_field_static_get_value (vtable, field, v);
+       } else {
+               mono_field_get_value (obj, field, v);
+       }
+
+       return o;
 }
 
+
 void
 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
 {
@@ -481,7 +1052,7 @@ mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
        g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
 
        src = (char*)vt->data + field->offset;
-       set_value (field->type, value, src);
+       set_value (field->type, value, src, TRUE);
 }
 
 void
@@ -536,7 +1107,28 @@ mono_runtime_get_main_args (void)
        return main_args;
 }
 
-MonoMethod *mono_start_method = NULL;
+static void
+fire_process_exit_event (void)
+{
+       MonoClassField *field;
+       MonoDomain *domain = mono_domain_get ();
+       gpointer pa [2];
+       MonoObject *delegate, *exc;
+       
+       field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
+       g_assert (field);
+
+       if (domain != mono_root_domain)
+               return;
+
+       delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
+       if (delegate == NULL)
+               return;
+
+       pa [0] = domain;
+       pa [1] = NULL;
+       mono_runtime_delegate_invoke (delegate, pa, &exc);
+}
 
 /*
  * Execute a standard Main() method (argc/argv contains the
@@ -550,10 +1142,56 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        int i;
        MonoArray *args = NULL;
        MonoDomain *domain = mono_domain_get ();
-
+       gchar *utf8_fullpath;
+       int result;
+       
        main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
-       for (i = 0; i < argc; ++i) {
-               MonoString *arg = mono_string_new (domain, argv [i]);
+
+       if (!g_path_is_absolute (argv [0])) {
+               gchar *basename = g_path_get_basename (argv [0]);
+               gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
+                                                   basename,
+                                                   NULL);
+
+               utf8_fullpath = mono_utf8_from_external (fullpath);
+               if(utf8_fullpath == NULL) {
+                       /* Printing the arg text will cause glib to
+                        * whinge about "Invalid UTF-8", but at least
+                        * its relevant, and shows the problem text
+                        * string.
+                        */
+                       g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
+                       g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
+                       exit (-1);
+               }
+
+               g_free (fullpath);
+               g_free (basename);
+       } else {
+               utf8_fullpath = mono_utf8_from_external (argv[0]);
+               if(utf8_fullpath == NULL) {
+                       g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
+                       g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
+                       exit (-1);
+               }
+       }
+               
+       mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
+       g_free (utf8_fullpath);
+
+       for (i = 1; i < argc; ++i) {
+               gchar *utf8_arg;
+               MonoString *arg;
+
+               utf8_arg=mono_utf8_from_external (argv[i]);
+               if(utf8_arg==NULL) {
+                       /* Ditto the comment about Invalid UTF-8 here */
+                       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);
+               }
+               
+               arg = mono_string_new (domain, utf8_arg);
                mono_array_set (main_args, gpointer, i, arg);
        }
        argc--;
@@ -561,21 +1199,66 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        if (method->signature->param_count) {
                args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
                for (i = 0; i < argc; ++i) {
-                       MonoString *arg = mono_string_new (domain, argv [i]);
+                       /* The encodings should all work, given that
+                        * we've checked all these args for the
+                        * main_args array.
+                        */
+                       MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
                        mono_array_set (args, gpointer, i, arg);
                }
+       } else {
+               args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
        }
        
        mono_assembly_set_main (method->klass->image->assembly);
 
-       mono_start_method = mono_marshal_get_runtime_invoke (method);
-       
-       return mono_runtime_exec_main (method, args, exc);
+       result = mono_runtime_exec_main (method, args, exc);
+       fire_process_exit_event ();
+       return result;
+}
+
+/* Used in mono_unhandled_exception */
+static MonoObject *
+create_unhandled_exception_eventargs (MonoObject *exc)
+{
+       MonoClass *klass;
+       gpointer args [2];
+       MonoMethod *method = NULL;
+       MonoBoolean is_terminating = TRUE;
+       MonoObject *obj;
+       gint i;
+
+       klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
+       g_assert (klass);
+
+       mono_class_init (klass);
+
+       /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
+       for (i = 0; i < klass->method.count; ++i) {
+               method = klass->methods [i];
+               if (!strcmp (".ctor", method->name) &&
+                   method->signature->param_count == 2 &&
+                   method->flags & METHOD_ATTRIBUTE_PUBLIC)
+                       break;
+               method = NULL;
+       }
+
+       g_assert (method);
+
+       args [0] = exc;
+       args [1] = &is_terminating;
+
+       obj = mono_object_new (mono_domain_get (), klass);
+       mono_runtime_invoke (method, obj, args, NULL);
+
+       return obj;
 }
 
 /*
- * We call this function when we dectect an unhandled exception. It invokes the
- * UnhandledException event in AppDomain or print a warning to the console 
+ * We call this function when we detect an unhandled exception
+ * in the default domain.
+ * It invokes the * UnhandledException event in AppDomain or prints
+ * a warning to the console 
  */
 void
 mono_unhandled_exception (MonoObject *exc)
@@ -591,23 +1274,46 @@ mono_unhandled_exception (MonoObject *exc)
        if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
                delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
 
-               if (!delegate) {
+               /* set exitcode only in the main thread? */
+               mono_environment_exitcode_set (1);
+               if (domain != mono_root_domain || !delegate) {
                        mono_print_unhandled_exception (exc);
                } else {
                        MonoObject *e = NULL;
                        gpointer pa [2];
 
-                       /* fixme: pass useful arguments */
-                       pa [0] = NULL;
-                       pa [1] = NULL;
+                       pa [0] = domain->domain;
+                       pa [1] = create_unhandled_exception_eventargs (exc);
                        mono_runtime_delegate_invoke (delegate, pa, &e);
                        
-                       if (e)
-                               g_warning ("exception inside UnhandledException handler!");
+                       if (e) {
+                               gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
+                               g_warning ("exception inside UnhandledException handler: %s\n", msg);
+                               g_free (msg);
+                       }
                }
        }
 }
 
+/*
+ * Launch a new thread to start all setup that requires managed code
+ * to be executed.
+ *
+ * main_func is called back from the thread with main_args as the
+ * parameter.  The callback function is expected to start Main()
+ * eventually.  This function then waits for all managed threads to
+ * finish.
+ */
+void
+mono_runtime_exec_managed_code (MonoDomain *domain,
+                               MonoMainThreadFunc main_func,
+                               gpointer main_args)
+{
+       mono_thread_create (domain, main_func, main_args);
+
+       mono_thread_manage ();
+}
+
 /*
  * Execute a standard Main() method (args doesn't contain the
  * executable name).
@@ -624,8 +1330,10 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        pa [0] = args;
 
        domain = mono_object_domain (args);
-       g_assert (!domain->entry_assembly);
-       domain->entry_assembly = method->klass->image->assembly;
+       if (!domain->entry_assembly) {
+               domain->entry_assembly = method->klass->image->assembly;
+               ves_icall_System_AppDomainSetup_InitAppDomainSetup (domain->setup);
+       }
 
        /* FIXME: check signature of method */
        if (method->signature->ret->type == MONO_TYPE_I4) {
@@ -635,12 +1343,21 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
                        rval = *(guint32 *)((char *)res + sizeof (MonoObject));
                else
                        rval = -1;
+
+               mono_environment_exitcode_set (rval);
        } else {
                mono_runtime_invoke (method, NULL, pa, exc);
                if (!exc || !*exc)
                        rval = 0;
-               else
+               else {
+                       /* If the return type of Main is void, only
+                        * set the exitcode if an exception was thrown
+                        * (we don't want to blow away an
+                        * explicitly-set exit code)
+                        */
                        rval = -1;
+                       mono_environment_exitcode_set (rval);
+               }
        }
 
        return rval;
@@ -649,7 +1366,7 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
 void
 mono_install_runtime_invoke (MonoInvokeFunc func)
 {
-       default_mono_runtime_invoke = func;
+       default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
 }
 
 MonoObject*
@@ -680,6 +1397,8 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_I4:
                        case MONO_TYPE_U8:
                        case MONO_TYPE_I8:
+                       case MONO_TYPE_R4:
+                       case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
                                pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
                                break;
@@ -688,7 +1407,10 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
-                               pa [i] = (char *)(((gpointer *)params->vector)[i]);
+                               if (sig->params [i]->byref)
+                                       pa [i] = &(((gpointer *)params->vector)[i]);
+                               else
+                                       pa [i] = (char *)(((gpointer *)params->vector)[i]);
                                break;
                        default:
                                g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
@@ -697,13 +1419,29 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
        }
 
        if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
-               obj = mono_object_new (mono_domain_get (), method->klass);
+               if (!obj) {
+                       obj = mono_object_new (mono_domain_get (), method->klass);
+                       if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
+                               method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
+                       }
+               }
                mono_runtime_invoke (method, obj, pa, exc);
                return obj;
        } else
                return mono_runtime_invoke (method, obj, pa, exc);
 }
 
+static void
+out_of_memory (size_t size)
+{
+       /* 
+        * we could allocate at program startup some memory that we could release 
+        * back to the system at this point if we're really low on memory (ie, size is
+        * lower than the memory we set apart)
+        */
+       mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+}
+
 /**
  * mono_object_allocate:
  * @size: number of bytes to allocate
@@ -713,18 +1451,35 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
  *
  * Returns: an allocated object of size @size, or NULL on failure.
  */
-void *
+static inline void *
 mono_object_allocate (size_t size)
 {
 #if HAVE_BOEHM_GC
        /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
-       void *o = GC_malloc (size);
+       void *o = GC_MALLOC (size);
 #else
        void *o = calloc (1, size);
 #endif
+       mono_stats.new_object_count++;
+
+       if (!o)
+               out_of_memory (size);
+       return o;
+}
+
+#if CREATION_SPEEDUP
+static inline void *
+mono_object_allocate_spec (size_t size, void *gcdescr)
+{
+       /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
+       void *o = GC_GCJ_MALLOC (size, gcdescr);
+       mono_stats.new_object_count++;
 
+       if (!o)
+               out_of_memory (size);
        return o;
 }
+#endif
 
 /**
  * mono_object_free:
@@ -745,38 +1500,108 @@ mono_object_free (MonoObject *o)
 #endif
 }
 
-/**
- * mono_object_new:
- * @klass: the class of the object that we want to create
- *
- * Returns: A newly created object whose definition is
- * looked up using @klass
- */
+/**
+ * mono_object_new:
+ * @klass: the class of the object that we want to create
+ *
+ * Returns: A newly created object whose definition is
+ * looked up using @klass
+ */
+MonoObject *
+mono_object_new (MonoDomain *domain, MonoClass *klass)
+{
+       MONO_ARCH_SAVE_REGS;
+       return mono_object_new_specific (mono_class_vtable (domain, klass));
+}
+
+/**
+ * mono_object_new_specific:
+ * @vtable: the vtable of the object that we want to create
+ *
+ * Returns: A newly created object with class and domain specified
+ * by @vtable
+ */
+MonoObject *
+mono_object_new_specific (MonoVTable *vtable)
+{
+       MonoObject *o;
+
+       MONO_ARCH_SAVE_REGS;
+       
+       if (vtable->remote)
+       {
+               gpointer pa [1];
+               MonoMethod *im = vtable->domain->create_proxy_for_type_method;
+
+               if (im == NULL) {
+                       MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
+                       int i;
+
+                       if (!klass->inited)
+                               mono_class_init (klass);
+
+                       for (i = 0; i < klass->method.count; ++i) {
+                               if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
+                                       klass->methods [i]->signature->param_count == 1) {
+                                       im = klass->methods [i];
+                                       break;
+                               }
+                       }
+                       g_assert (im);
+                       vtable->domain->create_proxy_for_type_method = im;
+               }
+       
+               pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
+
+               o = mono_runtime_invoke (im, NULL, pa, NULL);           
+               if (o != NULL) return o;
+       }
+
+       return mono_object_new_alloc_specific (vtable);
+}
+
 MonoObject *
-mono_object_new (MonoDomain *domain, MonoClass *klass)
+mono_object_new_fast (MonoVTable *vtable)
 {
-       return mono_object_new_specific (mono_class_vtable (domain, klass));
+       MonoObject *o;
+       MONO_ARCH_SAVE_REGS;
+
+#if CREATION_SPEEDUP
+       if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
+               o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
+       } else {
+//             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+               o = mono_object_allocate (vtable->klass->instance_size);
+               o->vtable = vtable;
+       }
+#else
+       o = mono_object_allocate (vtable->klass->instance_size);
+       o->vtable = vtable;
+#endif
+       return o;
 }
 
-/**
- * mono_object_new_specific:
- * @vtable: the vtable of the object that we want to create
- *
- * Returns: A newly created object with class and domain specified
- * by @vtable
- */
 MonoObject *
-mono_object_new_specific (MonoVTable *vtable)
+mono_object_new_alloc_specific (MonoVTable *vtable)
 {
        MonoObject *o;
 
-       mono_stats.new_object_count++;
-
+#if CREATION_SPEEDUP
+       if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
+               o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
+       } else {
+//             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+               o = mono_object_allocate (vtable->klass->instance_size);
+               o->vtable = vtable;
+       }
+#else
        o = mono_object_allocate (vtable->klass->instance_size);
        o->vtable = vtable;
+#endif
        if (vtable->klass->has_finalize)
                mono_object_register_finalizer (o);
        
+       mono_profiler_allocation (o, vtable->klass);
        return o;
 }
 
@@ -813,6 +1638,7 @@ mono_object_clone (MonoObject *obj)
 
        size = obj->vtable->klass->instance_size;
        o = mono_object_allocate (size);
+       mono_profiler_allocation (o, obj->vtable->klass);
 
        memcpy (o, obj, size);
 
@@ -835,6 +1661,8 @@ mono_array_clone (MonoArray *array)
        guint32 *sizes;
        MonoClass *klass = array->obj.vtable->klass;
 
+       MONO_ARCH_SAVE_REGS;
+
        if (array->bounds == NULL) {
                size = mono_array_length (array);
                o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
@@ -860,6 +1688,14 @@ mono_array_clone (MonoArray *array)
        return o;
 }
 
+/* helper macros to check for overflow when calculating the size of arrays */
+#define MYGUINT32_MAX 4294967295U
+#define CHECK_ADD_OVERFLOW_UN(a,b) \
+        (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
+#define CHECK_MUL_OVERFLOW_UN(a,b) \
+        ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
+        (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
+
 /*
  * mono_array_new_full:
  * @domain: domain where the object is created
@@ -878,6 +1714,7 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
        MonoObject *o;
        MonoArray *array;
        MonoArrayBounds *bounds;
+       MonoVTable *vtable;
        int i;
 
        if (!array_class->inited)
@@ -892,12 +1729,14 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
                len = lengths [0];
        } else {
        #if HAVE_BOEHM_GC
-               bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
+               bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
        #else
                bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
        #endif
                for (i = 0; i < array_class->rank; ++i) {
                        bounds [i].length = lengths [i];
+                       if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
+                               out_of_memory (MYGUINT32_MAX);
                        len *= lengths [i];
                }
 
@@ -906,21 +1745,36 @@ mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
                                bounds [i].lower_bound = lower_bounds [i];
        }
 
+       if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
+               out_of_memory (MYGUINT32_MAX);
        byte_len *= len;
+       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
+               out_of_memory (MYGUINT32_MAX);
+       byte_len += sizeof (MonoArray);
        /* 
         * Following three lines almost taken from mono_object_new ():
         * they need to be kept in sync.
         */
-       o = mono_object_allocate (sizeof (MonoArray) + byte_len);
-       if (!o)
-               G_BREAKPOINT ();
-       o->vtable = mono_class_vtable (domain, array_class);
+       vtable = mono_class_vtable (domain, array_class);
+#if CREATION_SPEEDUP
+       if (vtable->gc_descr != GC_NO_DESCRIPTOR)
+               o = mono_object_allocate_spec (byte_len, vtable);
+       else {
+               o = mono_object_allocate (byte_len);
+               o->vtable = vtable;
+       }
+#else
+       o = mono_object_allocate (byte_len);
+       o->vtable = vtable;
+#endif
 
        array = (MonoArray*)o;
 
        array->bounds = bounds;
        array->max_length = len;
 
+       mono_profiler_allocation (o, array_class);
+
        return array;
 }
 
@@ -937,7 +1791,9 @@ mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
 {
        MonoClass *ac;
 
-       ac = mono_array_class_get (&eclass->byval_arg, 1);
+       MONO_ARCH_SAVE_REGS;
+
+       ac = mono_array_class_get (eclass, 1);
        g_assert (ac != NULL);
 
        return mono_array_new_specific (mono_class_vtable (domain, ac), n);
@@ -956,17 +1812,34 @@ mono_array_new_specific (MonoVTable *vtable, guint32 n)
 {
        MonoObject *o;
        MonoArray *ao;
-       gsize byte_len;
-
-       byte_len = n * mono_array_element_size (vtable->klass);
-       o = mono_object_allocate (sizeof (MonoArray) + byte_len);
-       if (!o)
-               G_BREAKPOINT ();
+       guint32 byte_len, elem_size;
+
+       MONO_ARCH_SAVE_REGS;
+
+       elem_size = mono_array_element_size (vtable->klass);
+       if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
+               out_of_memory (MYGUINT32_MAX);
+       byte_len = n * elem_size;
+       if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
+               out_of_memory (MYGUINT32_MAX);
+       byte_len += sizeof (MonoArray);
+#if CREATION_SPEEDUP
+       if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
+               o = mono_object_allocate_spec (byte_len, vtable);
+       } else {
+//             printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+               o = mono_object_allocate (byte_len);
+               o->vtable = vtable;
+       }
+#else
+       o = mono_object_allocate (byte_len);
        o->vtable = vtable;
+#endif
 
        ao = (MonoArray *)o;
        ao->bounds = NULL;
        ao->max_length = n;
+       mono_profiler_allocation (o, vtable->klass);
 
        return ao;
 }
@@ -1002,23 +1875,24 @@ MonoString *
 mono_string_new_size (MonoDomain *domain, gint32 len)
 {
        MonoString *s;
+       MonoVTable *vtable;
 
-       /* 
-        * enable to get a good speedup: we still need to figure out
-        * how the sync structure is freed.
-        */
-#if 0
-       s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
-       s->object.synchronisation = 0;
-       mono_string_chars (s) [len] = 0;
+       vtable = mono_class_vtable (domain, mono_defaults.string_class);
+
+#if CREATION_SPEEDUP
+       if (vtable->gc_descr != GC_NO_DESCRIPTOR)
+               s = mono_object_allocate_spec (sizeof (MonoString) + ((len + 1) * 2), vtable);
+       else {
+               s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+               s->object.vtable = vtable;
+       }
 #else
        s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+       s->object.vtable = vtable;
 #endif
-       if (!s)
-               G_BREAKPOINT ();
 
-       s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
        s->length = len;
+       mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
 
        return s;
 }
@@ -1038,7 +1912,6 @@ 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);
 
        if (!error)
@@ -1091,6 +1964,8 @@ mono_string_new_wrapper (const char *text)
 {
        MonoDomain *domain = mono_domain_get ();
 
+       MONO_ARCH_SAVE_REGS;
+
        if (text)
                return mono_string_new (domain, text);
 
@@ -1109,12 +1984,15 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 {
        MonoObject *res;
        int size;
+       MonoVTable *vtable;
 
        g_assert (class->valuetype);
 
+       vtable = mono_class_vtable (domain, class);
        size = mono_class_instance_size (class);
        res = mono_object_allocate (size);
-       res->vtable = mono_class_vtable (domain, class);
+       res->vtable = vtable;
+       mono_profiler_allocation (res, class);
 
        size = size - sizeof (MonoObject);
 
@@ -1143,6 +2021,13 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        return res;
 }
 
+gpointer
+mono_object_unbox (MonoObject *obj)
+{
+       /* add assert for valuetypes? */
+       return ((char*)obj) + sizeof (MonoObject);
+}
+
 /**
  * mono_object_isinst:
  * @obj: an object
@@ -1153,40 +2038,114 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 MonoObject *
 mono_object_isinst (MonoObject *obj, MonoClass *klass)
 {
-       MonoVTable *vt;
-       MonoClass *oklass;
+       if (!klass->inited)
+               mono_class_init (klass);
+
+       if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
+               return mono_object_isinst_mbyref (obj, klass);
 
        if (!obj)
                return NULL;
 
-       vt = obj->vtable;
-       oklass = vt->klass;
+       return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
+}
 
-       if (!klass->inited)
-               mono_class_init (klass);
+MonoObject *
+mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
+{
+       MonoVTable *vt;
+
+       if (!obj)
+               return NULL;
 
+       vt = obj->vtable;
+       
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-               if ((klass->interface_id <= oklass->max_interface_id) &&
-                   vt->interface_offsets [klass->interface_id])
+               if ((klass->interface_id <= vt->max_interface_id) &&
+                   (vt->interface_offsets [klass->interface_id] != 0))
                        return obj;
-       } else {
-               if (oklass == mono_defaults.transparent_proxy_class) {
-                       /* fixme: add check for IRemotingTypeInfo */
-                       oklass = ((MonoTransparentProxy *)obj)->klass;
+       }
+       else {
+               MonoClass *oklass = vt->klass;
+               if ((oklass == mono_defaults.transparent_proxy_class))
+                       oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+       
+               if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
+                       return obj;
+       }
+
+       if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
+       {
+               MonoDomain *domain = mono_domain_get ();
+               MonoObject *res;
+               MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
+               MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
+               MonoMethod *im = NULL;
+               gpointer pa [2];
+               int i;
+       
+               for (i = 0; i < rpklass->method.count; ++i) {
+                       if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
+                               im = rpklass->methods [i];
+                               break;
+                       }
                }
-               if (klass->rank) {
-                       if (oklass->rank == klass->rank && 
-                           (oklass->element_class->baseval - klass->element_class->baseval) <= 
-                           klass->element_class->diffval)
-                               return obj;
-                       
-               } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
+       
+               im = mono_object_get_virtual_method (rp, im);
+               g_assert (im);
+       
+               pa [0] = mono_type_get_object (domain, &klass->byval_arg);
+               pa [1] = obj;
+
+               res = mono_runtime_invoke (im, rp, pa, NULL);
+       
+               if (*(MonoBoolean *) mono_object_unbox(res)) {
+                       /* Update the vtable of the remote type, so it can safely cast to this new type */
+                       mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
+                       obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
                        return obj;
+               }
        }
 
        return NULL;
 }
 
+/**
+ * mono_object_castclass_mbyref:
+ * @obj: an object
+ * @klass: a pointer to a class 
+ *
+ * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
+ */
+MonoObject *
+mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
+{
+       if (!obj) return NULL;
+       if (mono_object_isinst_mbyref (obj, klass)) return obj;
+               
+       mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
+                                                       "System",
+                                                       "InvalidCastException"));
+       return NULL;
+}
+
+typedef struct {
+       MonoDomain *orig_domain;
+       char *ins;
+       MonoString *res;
+} LDStrInfo;
+
+static void
+str_lookup (MonoDomain *domain, gpointer user_data)
+{
+       LDStrInfo *info = user_data;
+       if (info->res || domain == info->orig_domain)
+               return;
+       mono_domain_lock (domain);
+       info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
+       mono_domain_unlock (domain);
+}
+
 static MonoString*
 mono_string_is_interned_lookup (MonoString *str, int insert)
 {
@@ -1195,15 +2154,12 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
        MonoDomain *domain;
        char *ins = g_malloc (4 + str->length * 2);
        char *p;
-       int bloblen;
        
        /* Encode the length */
+       /* Same code as in mono_image_insert_string () */
        p = ins;
-       mono_metadata_encode_value (2 * str->length, p, &p);
-       bloblen = p - ins;
-       p = ins;
-       mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
-       bloblen = (p - ins) + 2 * str->length;
+       mono_metadata_encode_value (1 | (2 * str->length), p, &p);
+
        /*
         * ins is stored in the hash table as a key and needs to have the same
         * representation as in the metadata: we swap the character bytes on big
@@ -1212,7 +2168,7 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
        {
                int i;
-               char *p2 = mono_string_chars (str);
+               char *p2 = (char *)mono_string_chars (str);
                for (i = 0; i < str->length; ++i) {
                        *p++ = p2 [1];
                        *p++ = p2 [0];
@@ -1234,6 +2190,22 @@ mono_string_is_interned_lookup (MonoString *str, int insert)
                mono_g_hash_table_insert (ldstr_table, ins, str);
                mono_domain_unlock (domain);
                return str;
+       } else {
+               LDStrInfo ldstr_info;
+               ldstr_info.orig_domain = domain;
+               ldstr_info.ins = ins;
+               ldstr_info.res = NULL;
+
+               mono_domain_foreach (str_lookup, &ldstr_info);
+               if (ldstr_info.res) {
+                       /* 
+                        * the string was already interned in some other domain:
+                        * intern it in the current one as well.
+                        */
+                       mono_g_hash_table_insert (ldstr_table, ins, str);
+                       mono_domain_unlock (domain);
+                       return str;
+               }
        }
        mono_domain_unlock (domain);
        g_free (ins);
@@ -1266,8 +2238,13 @@ mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
        const char *str, *sig;
        MonoString *o;
        size_t len2;
-               
-       sig = str = mono_metadata_user_string (image, idx);
+
+       MONO_ARCH_SAVE_REGS;
+
+       if (image->dynamic)
+               return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
+       else
+               sig = str = mono_metadata_user_string (image, idx);
 
        mono_domain_lock (domain);
        if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
@@ -1315,8 +2292,10 @@ mono_string_to_utf8 (MonoString *s)
                return g_strdup ("");
 
        as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
-       if (error)
+       if (error) {
                g_warning (error->message);
+               g_error_free (error);
+       }
 
        return as;
 }
@@ -1350,11 +2329,29 @@ mono_string_to_utf16 (MonoString *s)
        return (gunichar2 *)(as);
 }
 
+/*
+ * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
+ */
+MonoString *
+mono_string_from_utf16 (gunichar2 *data)
+{
+       MonoDomain *domain = mono_domain_get ();
+       int len = 0;
+
+       if (!data)
+               return NULL;
+
+       while (data [len]) len++;
+
+       return mono_string_new_utf16 (domain, data, len);
+}
+
 static void
 default_ex_handler (MonoException *ex)
 {
        MonoObject *o = (MonoObject*)ex;
        g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
+       exit (1);
 }
 
 static MonoExceptionFunc ex_handler = default_ex_handler;
@@ -1374,6 +2371,13 @@ mono_install_handler        (MonoExceptionFunc func)
 void
 mono_raise_exception (MonoException *ex) 
 {
+       /*
+        * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
+        * 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.
+        */
+
        ex_handler (ex);
 }
 
@@ -1398,7 +2402,9 @@ mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpo
 
        res->data = data;
        res->async_state = state;
-       res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
+       if (handle != NULL)
+               res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
+
        res->sync_completed = FALSE;
        res->completed = FALSE;
 
@@ -1421,6 +2427,8 @@ mono_message_init (MonoDomain *domain,
 
        this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
        this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
+       this->async_result = NULL;
+       this->call_type = CallType_Sync;
 
        names = g_new (char *, sig->param_count);
        mono_method_get_param_names (method->method, (const char **) names);
@@ -1432,7 +2440,6 @@ mono_message_init (MonoDomain *domain,
        }
 
        g_free (names);
-       
        for (i = 0, j = 0; i < sig->param_count; i++) {
 
                if (sig->params [i]->byref) {
@@ -1442,12 +2449,11 @@ mono_message_init (MonoDomain *domain,
                                j++;
                        }
                        arg_type = 2;
-                       if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
+                       if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
                                arg_type |= 1;
                } else {
                        arg_type = 1;
                }
-
                mono_array_set (this->arg_types, guint8, i, arg_type);
        }
 }
@@ -1470,12 +2476,11 @@ MonoObject *
 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
                      MonoObject **exc, MonoArray **out_args)
 {
-       static MonoMethod *im = NULL;
+       MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
        gpointer pa [4];
 
        /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
 
-       /* FIXME: make this domain dependent */
        if (!im) {
                MonoClass *klass;
                int i;
@@ -1491,6 +2496,7 @@ mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
                }
        
                g_assert (im);
+               real_proxy->vtable->domain->private_invoke_method = im;
        }
 
        pa [0] = real_proxy;
@@ -1505,36 +2511,43 @@ MonoObject *
 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
                     MonoObject **exc, MonoArray **out_args) 
 {
-       if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
+       MonoDomain *domain; 
+       MonoMethod *method;
+       MonoMethodSignature *sig;
+       int i, j, outarg_count = 0;
 
-               return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp, 
-                                            msg, exc, out_args);
+       if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
 
-       } else {
-               MonoDomain *domain = mono_domain_get (); 
-               MonoMethod *method = msg->method->method;
-               MonoMethodSignature *sig = method->signature;
-               int i, j, outarg_count = 0;
-
-               for (i = 0; i < sig->param_count; i++) {
-                       if (sig->params [i]->byref) 
-                               outarg_count++;
+               MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
+               if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
+                       target = tp->rp->unwrapped_server;
+               } else {
+                       return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
                }
+       }
 
-               *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
-               *exc = NULL;
+       domain = mono_domain_get (); 
+       method = msg->method->method;
+       sig = method->signature;
 
-               for (i = 0, j = 0; i < sig->param_count; i++) {
-                       if (sig->params [i]->byref) {
-                               gpointer arg;
-                               arg = mono_array_get (msg->args, gpointer, i);
-                               mono_array_set (*out_args, gpointer, j, arg);
-                               j++;
-                       }
-               }
+       for (i = 0; i < sig->param_count; i++) {
+               if (sig->params [i]->byref) 
+                       outarg_count++;
+       }
 
-               return mono_runtime_invoke_array (method, target, msg->args, exc);
+       *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
+       *exc = NULL;
+
+       for (i = 0, j = 0; i < sig->param_count; i++) {
+               if (sig->params [i]->byref) {
+                       gpointer arg;
+                       arg = mono_array_get (msg->args, gpointer, i);
+                       mono_array_set (*out_args, gpointer, j, arg);
+                       j++;
+               }
        }
+
+       return mono_runtime_invoke_array (method, target, msg->args, exc);
 }
 
 void
@@ -1669,7 +2682,7 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *
                mono_array_set (msg->args, gpointer, i, arg);
        }
 
-       if (invoke) {
+       if (cb != NULL && state != NULL) {
                *cb = *((MonoDelegate **)params [i]);
                i++;
                *state = *((MonoObject **)params [i]);
@@ -1688,16 +2701,13 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
 {
        MonoMethodSignature *sig = method->signature;
        int i, j, type, size;
-       
        for (i = 0, j = 0; i < sig->param_count; i++) {
                MonoType *pt = sig->params [i];
 
-               size = mono_type_stack_size (pt, NULL);
-
                if (pt->byref) {
                        char *arg = mono_array_get (out_args, gpointer, j);
                        type = pt->type;
-                       
+
                        switch (type) {
                        case MONO_TYPE_VOID:
                                g_assert_not_reached ();
@@ -1715,6 +2725,7 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE: {
+                               size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
                                memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
                                break;
                        }
@@ -1722,7 +2733,7 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        case MONO_TYPE_CLASS: 
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
-                               *((MonoObject **)params [i]) = (MonoObject *)arg;
+                               **((MonoObject ***)params [i]) = (MonoObject *)arg;
                                break;
                        default:
                                g_assert_not_reached ();
@@ -1752,6 +2763,7 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
 {
        static MonoMethod *getter = NULL;
        MonoDomain *domain = mono_domain_get ();
+       MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
        MonoClass *field_class;
        MonoMethodMessage *msg;
        MonoArray *out_args;
@@ -1763,6 +2775,11 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
        if (!res)
                res = &tmp;
 
+       if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
+               mono_field_get_value (tp->rp->unwrapped_server, field, res);
+               return res;
+       }
+       
        if (!getter) {
                int i;
 
@@ -1786,7 +2803,9 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
        mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
        mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
 
-       mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
+       mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
+
+       if (exc) mono_raise_exception ((MonoException *)exc);
 
        *res = mono_array_get (out_args, MonoObject *, 0);
 
@@ -1796,6 +2815,63 @@ mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fiel
                return res;
 }
 
+MonoObject *
+mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
+{
+       static MonoMethod *getter = NULL;
+       MonoDomain *domain = mono_domain_get ();
+       MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
+       MonoClass *field_class;
+       MonoMethodMessage *msg;
+       MonoArray *out_args;
+       MonoObject *exc, *res;
+
+       g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
+
+       field_class = mono_class_from_mono_type (field->type);
+
+       if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
+               gpointer val;
+               if (field_class->valuetype) {
+                       res = mono_object_new (domain, field_class);
+                       val = ((gchar *) res) + sizeof (MonoObject);
+               } else {
+                       val = &res;
+               }
+               mono_field_get_value (tp->rp->unwrapped_server, field, val);
+               return res;
+       }
+
+       if (!getter) {
+               int i;
+
+               for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
+                       MonoMethod *cm = mono_defaults.object_class->methods [i];
+              
+                       if (!strcmp (cm->name, "FieldGetter")) {
+                               getter = cm;
+                               break;
+                       }
+               }
+               g_assert (getter);
+       }
+       
+       msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+       out_args = mono_array_new (domain, mono_defaults.object_class, 1);
+       mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
+
+       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
+       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+
+       mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
+
+       if (exc) mono_raise_exception ((MonoException *)exc);
+
+       res = mono_array_get (out_args, MonoObject *, 0);
+
+       return res;
+}
+
 /**
  * mono_store_remote_field:
  * @this: pointer to an object
@@ -1812,6 +2888,7 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
 {
        static MonoMethod *setter = NULL;
        MonoDomain *domain = mono_domain_get ();
+       MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
        MonoClass *field_class;
        MonoMethodMessage *msg;
        MonoArray *out_args;
@@ -1820,6 +2897,14 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
 
        g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
 
+       field_class = mono_class_from_mono_type (field->type);
+
+       if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
+               if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
+               else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
+               return;
+       }
+
        if (!setter) {
                int i;
 
@@ -1834,8 +2919,6 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
                g_assert (setter);
        }
 
-       field_class = mono_class_from_mono_type (field->type);
-
        if (field_class->valuetype)
                arg = mono_value_box (domain, field_class, val);
        else 
@@ -1849,9 +2932,55 @@ mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *fie
        mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
        mono_array_set (msg->args, gpointer, 2, arg);
 
-       mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
+       mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
+
+       if (exc) mono_raise_exception ((MonoException *)exc);
 }
 
+void
+mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
+{
+       static MonoMethod *setter = NULL;
+       MonoDomain *domain = mono_domain_get ();
+       MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
+       MonoClass *field_class;
+       MonoMethodMessage *msg;
+       MonoArray *out_args;
+       MonoObject *exc;
+
+       g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
+
+       field_class = mono_class_from_mono_type (field->type);
+
+       if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
+               if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
+               else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
+               return;
+       }
+
+       if (!setter) {
+               int i;
+
+               for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
+                       MonoMethod *cm = mono_defaults.object_class->methods [i];
+              
+                       if (!strcmp (cm->name, "FieldSetter")) {
+                               setter = cm;
+                               break;
+                       }
+               }
+               g_assert (setter);
+       }
+
+       msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+       mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
+
+       mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
+       mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
+       mono_array_set (msg->args, gpointer, 2, arg);
 
+       mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
 
+       if (exc) mono_raise_exception ((MonoException *)exc);
+}