Merge pull request #4248 from Unity-Technologies/boehm-gc-alloc-fixed
[mono.git] / mono / metadata / object.c
index 61c9d61f7e586ba19550a965b89147833c85db05..52aefb176930d89ada4cb3e3b451f133f5cf4ad5 100644 (file)
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/marshal.h>
 #include "mono/metadata/debug-helpers.h"
-#include "mono/metadata/marshal.h"
 #include <mono/metadata/threads.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/environment.h>
 #include "mono/metadata/profiler-private.h"
 #include "mono/metadata/security-manager.h"
 #include "mono/metadata/mono-debug-debugger.h"
-#include <mono/metadata/gc-internals.h>
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/reflection-internals.h>
 #include <mono/metadata/w32event.h>
@@ -50,6 +48,7 @@
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/mono-threads-coop.h>
 #include "cominterop.h"
+#include <mono/utils/w32api.h>
 
 static void
 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
@@ -63,18 +62,25 @@ free_main_args (void);
 static char *
 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
 
+static void
+array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
+
+static MonoMethod*
+class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
+
 /* Class lazy loading functions */
-static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
-static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
-static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
-static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
-static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
+static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
+static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
+static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
+static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
+static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
 
 
 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
 static mono_mutex_t ldstr_section;
 
+
 /**
  * mono_runtime_object_init:
  * @this_obj: the object to initialize
@@ -147,7 +153,9 @@ typedef struct
        MonoNativeThreadId initializing_tid;
        guint32 waiting_count;
        gboolean done;
-       MonoCoopMutex initialization_section;
+       MonoCoopMutex mutex;
+       /* condvar used to wait for 'done' becoming TRUE */
+       MonoCoopCond cond;
 } TypeInitializationLock;
 
 /* for locking access to type_initialization_hash and blocked_thread_hash */
@@ -171,13 +179,13 @@ mono_type_init_lock (TypeInitializationLock *lock)
 {
        MONO_REQ_GC_NEUTRAL_MODE;
 
-       mono_coop_mutex_lock (&lock->initialization_section);
+       mono_coop_mutex_lock (&lock->mutex);
 }
 
 static void
 mono_type_init_unlock (TypeInitializationLock *lock)
 {
-       mono_coop_mutex_unlock (&lock->initialization_section);
+       mono_coop_mutex_unlock (&lock->mutex);
 }
 
 /* from vtable to lock */
@@ -309,6 +317,24 @@ mono_runtime_class_init (MonoVTable *vtable)
        mono_error_assert_ok (&error);
 }
 
+/*
+ * Returns TRUE if the lock was freed.
+ * LOCKING: Caller should hold type_initialization_lock.
+ */
+static gboolean
+unref_type_lock (TypeInitializationLock *lock)
+{
+       --lock->waiting_count;
+       if (lock->waiting_count == 0) {
+               mono_coop_mutex_destroy (&lock->mutex);
+               mono_coop_cond_destroy (&lock->cond);
+               g_free (lock);
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
+
 /**
  * mono_runtime_class_init_full:
  * @vtable that neeeds to be initialized
@@ -365,6 +391,13 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
 
        tid = mono_native_thread_id_get ();
 
+       /*
+        * Due some preprocessing inside a global lock. If we are the first thread
+        * trying to initialize this class, create a separate lock+cond var, and
+        * acquire it before leaving the global lock. The other threads will wait
+        * on this cond var.
+        */
+
        mono_type_initialization_lock ();
        /* double check... */
        if (vtable->initialized) {
@@ -391,8 +424,9 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
                                return FALSE;
                        }
                }
-               lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
-               mono_coop_mutex_init_recursive (&lock->initialization_section);
+               lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
+               mono_coop_mutex_init_recursive (&lock->mutex);
+               mono_coop_cond_init (&lock->cond);
                lock->initializing_tid = tid;
                lock->waiting_count = 1;
                lock->done = FALSE;
@@ -405,7 +439,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
                gpointer blocked;
                TypeInitializationLock *pending_lock;
 
-               if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
+               if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
                        mono_type_initialization_unlock ();
                        return TRUE;
                }
@@ -434,9 +468,11 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
        if (do_initialization) {
                MonoException *exc = NULL;
 
+               /* We are holding the per-vtable lock, do the actual initialization */
+
                mono_threads_begin_abort_protected_block ();
                mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
-               mono_threads_end_abort_protected_block ();
+               gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
 
                //exception extracted, error will be set to the right value later
                if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
@@ -477,30 +513,36 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
 
                if (last_domain)
                        mono_domain_set (last_domain, TRUE);
+               /* Signal to the other threads that we are done */
                lock->done = TRUE;
+               mono_coop_cond_broadcast (&lock->cond);
+
                mono_type_init_unlock (lock);
+
+               //This can happen if the cctor self-aborts
                if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
                        pending_tae = exc;
+
                //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
-               if (!pending_tae)
+               if (!pending_tae && got_pending_interrupt)
                        pending_tae = mono_thread_try_resume_interruption ();
        } else {
                /* this just blocks until the initializing thread is done */
                mono_type_init_lock (lock);
+               while (!lock->done)
+                       mono_coop_cond_wait (&lock->cond, &lock->mutex);
                mono_type_init_unlock (lock);
        }
 
+       /* Do cleanup and setting vtable->initialized inside the global lock again */
        mono_type_initialization_lock ();
-       if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
+       if (!do_initialization)
                g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
-       --lock->waiting_count;
-       if (lock->waiting_count == 0) {
-               mono_coop_mutex_destroy (&lock->initialization_section);
+       gboolean deleted = unref_type_lock (lock);
+       if (deleted)
                g_hash_table_remove (type_initialization_hash, vtable);
-               g_free (lock);
-       }
-       mono_memory_barrier ();
-       if (!vtable->init_failed)
+       /* Have to set this here since we check it inside the global lock */
+       if (do_initialization && !vtable->init_failed)
                vtable->initialized = 1;
        mono_type_initialization_unlock ();
 
@@ -531,13 +573,11 @@ gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
                 * and get_type_init_exception_for_class () needs to be aware of this.
                 */
                vtable->init_failed = 1;
+               mono_coop_cond_broadcast (&lock->cond);
                mono_type_init_unlock (lock);
-               --lock->waiting_count;
-               if (lock->waiting_count == 0) {
-                       mono_coop_mutex_destroy (&lock->initialization_section);
-                       g_free (lock);
+               gboolean deleted = unref_type_lock (lock);
+               if (deleted)
                        return TRUE;
-               }
        }
        return FALSE;
 }
@@ -555,23 +595,15 @@ mono_release_type_locks (MonoInternalThread *thread)
 #ifndef DISABLE_REMOTING
 
 static gpointer
-default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
+create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
 {
-       g_error ("remoting not installed");
-       return NULL;
+       if (!callbacks.create_remoting_trampoline)
+               g_error ("remoting not installed");
+       return callbacks.create_remoting_trampoline (domain, method, target, error);
 }
 
-static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
 #endif
 
-static gpointer
-default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
-{
-       g_assert_not_reached ();
-       return NULL;
-}
-
-static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
 static MonoImtTrampolineBuilder imt_trampoline_builder;
 static gboolean always_build_imt_trampolines;
 
@@ -591,20 +623,6 @@ mono_get_runtime_callbacks (void)
        return &callbacks;
 }
 
-#ifndef DISABLE_REMOTING
-void
-mono_install_remoting_trampoline (MonoRemotingTrampoline func) 
-{
-       arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
-}
-#endif
-
-void
-mono_install_delegate_trampoline (MonoDelegateTrampoline func) 
-{
-       arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
-}
-
 void
 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
 {
@@ -650,10 +668,7 @@ mono_compile_method_checked (MonoMethod *method, MonoError *error)
 
        mono_error_init (error);
 
-       if (!callbacks.compile_method) {
-               g_error ("compile method called on uninitialized runtime");
-               return NULL;
-       }
+       g_assert (callbacks.compile_method);
        res = callbacks.compile_method (method, error);
        return res;
 }
@@ -675,25 +690,8 @@ mono_runtime_create_delegate_trampoline (MonoClass *klass)
 {
        MONO_REQ_GC_NEUTRAL_MODE
 
-       return arch_create_delegate_trampoline (mono_domain_get (), klass);
-}
-
-static MonoFreeMethodFunc default_mono_free_method = NULL;
-
-/**
- * mono_install_free_method:
- * @func: pointer to the MonoFreeMethodFunc used to release a method
- *
- * This is an internal VM routine, it is used for the engines to
- * register a handler to release the resources associated with a method.
- *
- * Methods are freed when no more references to the delegate that holds
- * them are left.
- */
-void
-mono_install_free_method (MonoFreeMethodFunc func)
-{
-       default_mono_free_method = func;
+       g_assert (callbacks.create_delegate_trampoline);
+       return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
 }
 
 /**
@@ -711,8 +709,8 @@ mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
 {
        MONO_REQ_GC_NEUTRAL_MODE
 
-       if (default_mono_free_method != NULL)
-               default_mono_free_method (domain, method);
+       if (callbacks.free_method)
+               callbacks.free_method (domain, method);
 
        mono_method_clear_object (domain, method);
 
@@ -785,18 +783,11 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int
 
                        type = mono_type_get_underlying_type (field->type);
                        switch (type->type) {
+                       case MONO_TYPE_U:
                        case MONO_TYPE_I:
                        case MONO_TYPE_PTR:
                        case MONO_TYPE_FNPTR:
                                break;
-                       /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
-                       case MONO_TYPE_U:
-#ifdef HAVE_SGEN_GC
-                               break;
-#else
-                               if (klass->image != mono_defaults.corlib)
-                                       break;
-#endif
                        case MONO_TYPE_STRING:
                        case MONO_TYPE_SZARRAY:
                        case MONO_TYPE_CLASS:
@@ -1015,6 +1006,7 @@ ves_icall_string_alloc (int length)
        return str;
 }
 
+/* LOCKING: Acquires the loader lock */
 void
 mono_class_compute_gc_descriptor (MonoClass *klass)
 {
@@ -1024,6 +1016,7 @@ mono_class_compute_gc_descriptor (MonoClass *klass)
        gsize *bitmap;
        gsize default_bitmap [4] = {0};
        static gboolean gcj_inited = FALSE;
+       MonoGCDescriptor gc_descr;
 
        if (!gcj_inited) {
                mono_loader_lock ();
@@ -1041,23 +1034,20 @@ mono_class_compute_gc_descriptor (MonoClass *klass)
        if (klass->gc_descr_inited)
                return;
 
-       klass->gc_descr_inited = TRUE;
-       klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
-
        bitmap = default_bitmap;
        if (klass == mono_defaults.string_class) {
-               klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
+               gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
        } else if (klass->rank) {
                mono_class_compute_gc_descriptor (klass->element_class);
                if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
                        gsize abm = 1;
-                       klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
+                       gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
                        /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
                                class->name_space, class->name);*/
                } else {
                        /* remove the object header */
                        bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
-                       klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
+                       gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
                        /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
                                class->name_space, class->name);*/
                        if (bitmap != default_bitmap)
@@ -1068,7 +1058,7 @@ mono_class_compute_gc_descriptor (MonoClass *klass)
                if (count++ > 58)
                        return;*/
                bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
-               klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
+               gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
                /*
                if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
                        g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
@@ -1077,6 +1067,13 @@ mono_class_compute_gc_descriptor (MonoClass *klass)
                if (bitmap != default_bitmap)
                        g_free (bitmap);
        }
+
+       /* Publish the data */
+       mono_loader_lock ();
+       klass->gc_descr = gc_descr;
+       mono_memory_barrier ();
+       klass->gc_descr_inited = TRUE;
+       mono_loader_unlock ();
 }
 
 /**
@@ -1403,17 +1400,18 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
 
                mono_class_setup_methods (iface);
                vt_slot = interface_offset;
-               for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
+               int mcount = mono_class_get_method_count (iface);
+               for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
                        MonoMethod *method;
 
-                       if (slot_num >= 0 && iface->is_inflated) {
+                       if (slot_num >= 0 && mono_class_is_ginst (iface)) {
                                /*
                                 * The imt slot of the method is the same as for its declaring method,
                                 * see the comment in mono_method_get_imt_slot (), so we can
                                 * avoid inflating methods which will be discarded by 
                                 * add_imt_builder_entry anyway.
                                 */
-                               method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
+                               method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
                                if (mono_method_get_imt_slot (method) != slot_num) {
                                        vt_slot ++;
                                        continue;
@@ -1438,14 +1436,15 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer*
                for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
                        MonoClass* iface = (MonoClass *)list_item->data;
                        int method_slot_in_interface;
-                       for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
+                       int mcount = mono_class_get_method_count (iface);
+                       for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
                                MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
 
                                if (method->is_generic)
                                        has_generic_virtual = TRUE;
                                add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
                        }
-                       interface_offset += iface->method.count;
+                       interface_offset += mcount;
                }
        }
        for (i = 0; i < MONO_IMT_SIZE; ++i) {
@@ -1905,7 +1904,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        if (!klass->vtable_size)
                mono_class_setup_vtable (klass);
 
-       if (klass->generic_class && !klass->vtable)
+       if (mono_class_is_ginst (klass) && !klass->vtable)
                mono_class_check_vtable_constraints (klass, NULL);
 
        /* Initialize klass->has_finalize */
@@ -2202,7 +2201,8 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        MONO_REQ_GC_UNSAFE_MODE;
 
        MonoVTable *vt, *pvt;
-       int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
+       int i, j, vtsize, extra_interface_vtsize = 0;
+       guint32 max_interface_id;
        MonoClass *k;
        GSList *extra_interfaces = NULL;
        MonoClass *klass = remote_class->proxy_class;
@@ -2283,21 +2283,21 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                MonoMethod *cm;
                    
                if ((cm = klass->vtable [i])) {
-                       pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+                       pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
                        if (!is_ok (error))
                                goto failure;
                } else
                        pvt->vtable [i] = NULL;
        }
 
-       if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
+       if (mono_class_is_abstract (klass)) {
                /* create trampolines for abstract methods */
                for (k = klass; k; k = k->parent) {
                        MonoMethod* m;
                        gpointer iter = NULL;
                        while ((m = mono_class_get_methods (k, &iter)))
                                if (!pvt->vtable [m->slot]) {
-                                       pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
+                                       pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
                                        if (!is_ok (error))
                                                goto failure;
                                }
@@ -2333,7 +2333,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        iter = NULL;
                        j = 0;
                        while ((cm = mono_class_get_methods (interf, &iter))) {
-                               pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+                               pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
                                if (!is_ok (error))
                                        goto failure;
                        }
@@ -2448,7 +2448,7 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
        int i, j;
        
        if (remote_class == NULL) {
-               if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               if (mono_class_is_interface (extra_class)) {
                        key = (void **)g_malloc (sizeof(gpointer) * 3);
                        key [0] = GINT_TO_POINTER (2);
                        key [1] = mono_defaults.marshalbyrefobject_class;
@@ -2459,7 +2459,7 @@ create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
                        key [1] = extra_class;
                }
        } else {
-               if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
+               if (extra_class != NULL && mono_class_is_interface (extra_class)) {
                        key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
                        key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
                        key [1] = remote_class->proxy_class;
@@ -2516,7 +2516,7 @@ copy_remote_class_key (MonoDomain *domain, gpointer *key)
  * On failure returns NULL and sets @error
  */
 MonoRemoteClass*
-mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
+mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
@@ -2537,7 +2537,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
                return rc;
        }
 
-       name = mono_string_to_utf8_mp (domain->mp, class_name, error);
+       name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
        if (!is_ok (error)) {
                g_free (key);
                mono_domain_unlock (domain);
@@ -2548,7 +2548,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        g_free (key);
        key = mp_key;
 
-       if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+       if (mono_class_is_interface (proxy_class)) {
                rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
                rc->interface_count = 1;
                rc->interfaces [0] = proxy_class;
@@ -2563,7 +2563,7 @@ mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_
        rc->xdomain_vtable = NULL;
        rc->proxy_class_name = name;
 #ifndef DISABLE_PERFCOUNTERS
-       mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
+       mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
 #endif
 
        g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
@@ -2595,7 +2595,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
        g_free (key);
        key = mp_key;
 
-       if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
+       if (mono_class_is_interface (extra_class)) {
                int i,j;
                rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
                rc->proxy_class = remote_class->proxy_class;
@@ -2629,7 +2629,7 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 }
 
 gpointer
-mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
+mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
@@ -2637,7 +2637,8 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
 
        mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
        mono_domain_lock (domain);
-       if (rp->target_domain_id != -1) {
+       gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
+       if (target_domain_id != -1) {
                if (remote_class->xdomain_vtable == NULL)
                        remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
                mono_domain_unlock (domain);
@@ -2646,10 +2647,11 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
                return remote_class->xdomain_vtable;
        }
        if (remote_class->default_vtable == NULL) {
-               MonoType *type;
-               MonoClass *klass;
-               type = ((MonoReflectionType *)rp->class_to_proxy)->type;
-               klass = mono_class_from_mono_type (type);
+               MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
+               MONO_HANDLE_GET (reftype, rp, class_to_proxy);
+               
+               MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
+               MonoClass *klass = mono_class_from_mono_type (type);
 #ifndef DISABLE_COM
                if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
                        remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
@@ -2681,22 +2683,17 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
  * class or an interface.  On success returns TRUE, on failure returns FALSE and sets @error.
  */
 gboolean
-mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
+mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoTransparentProxy *tproxy;
-       MonoRemoteClass *remote_class;
-       gboolean redo_vtable;
-
        mono_error_init (error);
-       mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
-       mono_domain_lock (domain);
 
-       tproxy = (MonoTransparentProxy*) proxy_object;
-       remote_class = tproxy->remote_class;
+       MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
+       MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
        
-       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+       gboolean redo_vtable;
+       if (mono_class_is_interface (klass)) {
                int i;
                redo_vtable = TRUE;
                for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
@@ -2707,9 +2704,14 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
                redo_vtable = (remote_class->proxy_class != klass);
        }
 
+       mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
+       mono_domain_lock (domain);
        if (redo_vtable) {
-               tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
-               proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
+               MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
+               MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
+               MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
+               MONO_HANDLE_GET (real_proxy, tproxy, rp);
+               MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
                if (!is_ok (error))
                        goto leave;
        }
@@ -2731,28 +2733,51 @@ leave:
  * the instance of a callvirt of method.
  */
 MonoMethod*
-mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
+mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
 {
        MONO_REQ_GC_UNSAFE_MODE;
+       HANDLE_FUNCTION_ENTER ();
+       MonoError error;
+       MONO_HANDLE_DCL (MonoObject, obj);
+       MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
+       mono_error_assert_ok (&error);
+       HANDLE_FUNCTION_RETURN_VAL (result);
+}
 
-       MonoClass *klass;
-       MonoMethod **vtable;
-       gboolean is_proxy = FALSE;
-       MonoMethod *res = NULL;
+/**
+ * mono_object_get_virtual_method:
+ * @obj: object to operate on.
+ * @method: method 
+ *
+ * Retrieves the MonoMethod that would be called on obj if obj is passed as
+ * the instance of a callvirt of method.
+ */
+MonoMethod*
+mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
+{
+       mono_error_init (error);
 
-       klass = mono_object_class (obj);
-#ifndef DISABLE_REMOTING
-       if (klass == mono_defaults.transparent_proxy_class) {
-               klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+       gboolean is_proxy = FALSE;
+       MonoClass *klass = mono_handle_class (obj);
+       if (mono_class_is_transparent_proxy (klass)) {
+               MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
+               klass = remote_class->proxy_class;
                is_proxy = TRUE;
        }
-#endif
+       return class_get_virtual_method (klass, method, is_proxy, error);
+}
+
+static MonoMethod*
+class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
+{
+       mono_error_init (error);
+
 
        if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
                        return method;
 
        mono_class_setup_vtable (klass);
-       vtable = klass->vtable;
+       MonoMethod **vtable = klass->vtable;
 
        if (method->slot == -1) {
                /* method->slot might not be set for instances of generic methods */
@@ -2765,9 +2790,10 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
                }
        }
 
+       MonoMethod *res = NULL;
        /* check method->slot is a valid index: perform isinstance? */
        if (method->slot != -1) {
-               if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               if (mono_class_is_interface (method->klass)) {
                        if (!is_proxy) {
                                gboolean variance_used = FALSE;
                                int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
@@ -2800,15 +2826,11 @@ mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
 #endif
        {
                if (method->is_inflated) {
-                       MonoError error;
                        /* Have to inflate the result */
-                       res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
-                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+                       res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
                }
        }
 
-       g_assert (res);
-       
        return res;
 }
 
@@ -3745,7 +3767,7 @@ mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
 
        MonoClass *param_class = klass->cast_class;
 
-       mono_class_setup_fields_locking (klass);
+       mono_class_setup_fields (klass);
        g_assert (klass->fields_inited);
                                
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
@@ -3779,7 +3801,7 @@ mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
        mono_error_init (error);
        MonoClass *param_class = klass->cast_class;
 
-       mono_class_setup_fields_locking (klass);
+       mono_class_setup_fields (klass);
        g_assert (klass->fields_inited);
 
        g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
@@ -5048,7 +5070,7 @@ mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        mono_error_assert_ok (error);
                        g_assert (obj); /*maybe we should raise a TLE instead?*/
 #ifndef DISABLE_REMOTING
-                       if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
+                       if (mono_object_is_transparent_proxy (obj)) {
                                method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
                        }
 #endif
@@ -5575,6 +5597,13 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest)
        size = mono_array_length (src);
        g_assert (size == mono_array_length (dest));
        size *= mono_array_element_size (klass);
+
+       array_full_copy_unchecked_size (src, dest, klass, size);
+}
+
+static void
+array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
+{
 #ifdef HAVE_SGEN_GC
        if (klass->element_class->valuetype) {
                if (klass->element_class->has_references)
@@ -5598,62 +5627,51 @@ mono_array_full_copy (MonoArray *src, MonoArray *dest)
  * This routine returns a copy of the array that is hosted on the
  * specified MonoDomain.  On failure returns NULL and sets @error.
  */
-MonoArray*
-mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
+MonoArrayHandle
+mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoArray *o;
-       uintptr_t size, i;
-       uintptr_t *sizes;
-       MonoClass *klass = array->obj.vtable->klass;
+       MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
+       uintptr_t size = 0;
+       MonoClass *klass = mono_handle_class (array_handle);
 
        mono_error_init (error);
 
-       if (array->bounds == NULL) {
-               size = mono_array_length (array);
-               o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
-               return_val_if_nok (error, NULL);
-
-               size *= mono_array_element_size (klass);
-#ifdef HAVE_SGEN_GC
-               if (klass->element_class->valuetype) {
-                       if (klass->element_class->has_references)
-                               mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
-                       else
-                               mono_gc_memmove_atomic (&o->vector, &array->vector, size);
-               } else {
-                       mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
-               }
-#else
-               mono_gc_memmove_atomic (&o->vector, &array->vector, size);
-#endif
-               return o;
-       }
+       /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
+       uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
        
-       sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
-       size = mono_array_element_size (klass);
-       for (i = 0; i < klass->rank; ++i) {
-               sizes [i] = array->bounds [i].length;
-               size *= array->bounds [i].length;
-               sizes [i + klass->rank] = array->bounds [i].lower_bound;
-       }
-       o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
-       return_val_if_nok (error, NULL);
-#ifdef HAVE_SGEN_GC
-       if (klass->element_class->valuetype) {
-               if (klass->element_class->has_references)
-                       mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
-               else
-                       mono_gc_memmove_atomic (&o->vector, &array->vector, size);
+       MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
+       MonoArrayHandle o;
+       if (array_bounds == NULL) {
+               size = mono_array_handle_length (array_handle);
+               o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
+               if (!is_ok (error))
+                       goto leave;
+               size *= mono_array_element_size (klass);
        } else {
-               mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
+               uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
+               intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
+               size = mono_array_element_size (klass);
+               for (int i = 0; i < klass->rank; ++i) {
+                       sizes [i] = array_bounds [i].length;
+                       size *= array_bounds [i].length;
+                       lower_bounds [i] = array_bounds [i].lower_bound;
+               }
+               o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
+               if (!is_ok (error))
+                       goto leave;
        }
-#else
-       mono_gc_memmove_atomic (&o->vector, &array->vector, size);
-#endif
 
-       return o;
+       uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
+       array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
+       mono_gchandle_free (dst_handle);
+
+       MONO_HANDLE_ASSIGN (result, o);
+
+leave:
+       mono_gchandle_free (src_handle);
+       return result;
 }
 
 /**
@@ -5682,11 +5700,15 @@ mono_array_clone (MonoArray *array)
  * failure returns NULL and sets @error.
  */
 MonoArray*
-mono_array_clone_checked (MonoArray *array, MonoError *error)
+mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
 {
-
        MONO_REQ_GC_UNSAFE_MODE;
-       return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
+       HANDLE_FUNCTION_ENTER ();
+       /* FIXME: callers of mono_array_clone_checked should use handles */
+       mono_error_init (error);
+       MONO_HANDLE_DCL (MonoArray, array);
+       MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
+       HANDLE_FUNCTION_RETURN_OBJ (result);
 }
 
 /* helper macros to check for overflow when calculating the size of arrays */
@@ -5953,6 +5975,31 @@ ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
        return arr;
 }
 
+/**
+ * mono_string_empty_wrapper:
+ *
+ * Returns: The same empty string instance as the managed string.Empty
+ */
+MonoString*
+mono_string_empty_wrapper (void)
+{
+       MonoDomain *domain = mono_domain_get ();
+       return mono_string_empty (domain);
+}
+
+/**
+ * mono_string_empty:
+ *
+ * Returns: The same empty string instance as the managed string.Empty
+ */
+MonoString*
+mono_string_empty (MonoDomain *domain)
+{
+       g_assert (domain);
+       g_assert (domain->empty_string);
+       return domain->empty_string;
+}
+
 /**
  * mono_string_new_utf16:
  * @text: a pointer to an utf16 string
@@ -5998,6 +6045,21 @@ mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 l
        return s;
 }
 
+/**
+ * mono_string_new_utf16_handle:
+ * @text: a pointer to an utf16 string
+ * @len: the length of the string
+ * @error: written on error.
+ *
+ * Returns: A newly created string object which contains @text.
+ * On error, returns NULL and sets @error.
+ */
+MonoStringHandle
+mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
+{
+       return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
+}
+
 /**
  * mono_string_new_utf32:
  * @text: a pointer to an utf32 string
@@ -6455,14 +6517,16 @@ mono_object_unbox (MonoObject *obj)
  * Returns: @obj if @obj is derived from @klass or NULL otherwise.
  */
 MonoObject *
-mono_object_isinst (MonoObject *obj, MonoClass *klass)
+mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       HANDLE_FUNCTION_ENTER ();
+       MONO_HANDLE_DCL (MonoObject, obj);
        MonoError error;
-       MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+       MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
        mono_error_cleanup (&error);
-       return result;
+       HANDLE_FUNCTION_RETURN_OBJ (result);
 }
        
 
@@ -6476,76 +6540,111 @@ mono_object_isinst (MonoObject *obj, MonoClass *klass)
  * On failure returns NULL and sets @error.
  */
 MonoObject *
-mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       HANDLE_FUNCTION_ENTER ();
        mono_error_init (error);
-       
-       MonoObject *result = NULL;
+       MONO_HANDLE_DCL (MonoObject, obj);
+       MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
+       HANDLE_FUNCTION_RETURN_OBJ (result);
+}
 
+/**
+ * mono_object_handle_isinst:
+ * @obj: an object
+ * @klass: a pointer to a class 
+ * @error: set on error
+ *
+ * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
+ * On failure returns NULL and sets @error.
+ */
+MonoObjectHandle
+mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
+{
+       mono_error_init (error);
+       
        if (!klass->inited)
                mono_class_init (klass);
 
-       if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
-               result = mono_object_isinst_mbyref_checked (obj, klass, error);
-               return result;
+       if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
+               return mono_object_handle_isinst_mbyref (obj, klass, error);
        }
 
-       if (!obj)
-               return NULL;
+       MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
 
-       return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
+       if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
+               MONO_HANDLE_ASSIGN (result, obj);
+       return result;
 }
 
 MonoObject *
-mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
+mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       HANDLE_FUNCTION_ENTER ();
        MonoError error;
-       MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
+       MONO_HANDLE_DCL (MonoObject, obj);
+       MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
        mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
-       return result;
+       HANDLE_FUNCTION_RETURN_OBJ (result);
 }
 
-MonoObject *
-mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
+MonoObjectHandle
+mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
 {
-       MONO_REQ_GC_UNSAFE_MODE;
-
-       MonoVTable *vt;
-
        mono_error_init (error);
 
-       if (!obj)
-               return NULL;
+       MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
+
+       if (MONO_HANDLE_IS_NULL (obj))
+               goto leave;
 
-       vt = obj->vtable;
+       MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
        
-       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+       if (mono_class_is_interface (klass)) {
                if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
-                       return obj;
+                       MONO_HANDLE_ASSIGN (result, obj);
+                       goto leave;
+               }
+
+               /* casting an array one of the invariant interfaces that must act as such */
+               if (klass->is_array_special_interface) {
+                       if (mono_class_is_assignable_from (klass, vt->klass)) {
+                               MONO_HANDLE_ASSIGN (result, obj);
+                               goto leave;
+                       }
                }
 
                /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
-               if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
-                       return obj;
+               else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
+                       MONO_HANDLE_ASSIGN (result, obj);
+                       goto leave;
+               }
        } else {
                MonoClass *oklass = vt->klass;
-               if (mono_class_is_transparent_proxy (oklass))
-                       oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+               if (mono_class_is_transparent_proxy (oklass)){
+                       MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
+                       oklass = remote_class->proxy_class;
+               }
 
                mono_class_setup_supertypes (klass);    
-               if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
-                       return obj;
+               if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
+                       MONO_HANDLE_ASSIGN (result, obj);
+                       goto leave;
+               }
        }
 #ifndef DISABLE_REMOTING
-       if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info
+       if (mono_class_is_transparent_proxy (vt->klass)
        {
+               MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
+               if (!custom_type_info)
+                       goto leave;
                MonoDomain *domain = mono_domain_get ();
-               MonoObject *res;
-               MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
+               MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
+               MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
                MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
                MonoMethod *im = NULL;
                gpointer pa [2];
@@ -6553,27 +6652,34 @@ mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError
                im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
                if (!im) {
                        mono_error_set_not_supported (error, "Linked away.");
-                       return NULL;
+                       goto leave;
                }
-               im = mono_object_get_virtual_method (rp, im);
+               im = mono_object_handle_get_virtual_method (rp, im, error);
+               if (!is_ok (error))
+                       goto leave;
                g_assert (im);
        
-               pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
-               return_val_if_nok (error, NULL);
-               pa [1] = obj;
+               MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
+               if (!is_ok (error))
+                       goto leave;
 
-               res = mono_runtime_invoke_checked (im, rp, pa, error);
-               return_val_if_nok (error, NULL);
+               pa [0] = MONO_HANDLE_RAW (reftype);
+               pa [1] = MONO_HANDLE_RAW (obj);
+               MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
+               if (!is_ok (error))
+                       goto leave;
 
                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, obj, klass, error);
-                       return_val_if_nok (error, NULL);
-                       return obj;
+                       if (!is_ok (error))
+                               goto leave;
+                       MONO_HANDLE_ASSIGN (result, obj);
                }
        }
 #endif /* DISABLE_REMOTING */
-       return NULL;
+leave:
+       return result;
 }
 
 /**
@@ -6584,15 +6690,19 @@ mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError
  * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
  */
 MonoObject *
-mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
+mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
 {
        MONO_REQ_GC_UNSAFE_MODE;
+       HANDLE_FUNCTION_ENTER ();
        MonoError error;
-
-       if (!obj) return NULL;
-       if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
+       MONO_HANDLE_DCL (MonoObject, obj);
+       MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
+       if (MONO_HANDLE_IS_NULL (obj))
+               goto leave;
+       MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
        mono_error_cleanup (&error);
-       return NULL;
+leave:
+       HANDLE_FUNCTION_RETURN_OBJ (result);
 }
 
 typedef struct {
@@ -6951,6 +7061,12 @@ mono_string_to_utf8_checked (MonoString *s, MonoError *error)
        return as;
 }
 
+char *
+mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
+{
+       return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
+}
+
 /**
  * mono_string_to_utf8_ignore:
  * @s: a MonoString
@@ -7212,11 +7328,11 @@ mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s,
  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
  */
 char *
-mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
+mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
+       return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
 }
 
 /**
@@ -7697,6 +7813,15 @@ mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
 
 
 
+static char *
+get_native_backtrace (MonoException *exc_raw)
+{
+       HANDLE_FUNCTION_ENTER ();
+       MONO_HANDLE_DCL(MonoException, exc);
+       char * trace = mono_exception_handle_get_native_backtrace (exc);
+       HANDLE_FUNCTION_RETURN_VAL (trace);
+}
+
 /**
  * mono_print_unhandled_exception:
  * @exc: The exception
@@ -7722,7 +7847,7 @@ mono_print_unhandled_exception (MonoObject *exc)
        } else {
                
                if (((MonoException*)exc)->native_trace_ips) {
-                       message = mono_exception_get_native_backtrace ((MonoException*)exc);
+                       message = get_native_backtrace ((MonoException*)exc);
                        free_message = TRUE;
                } else {
                        MonoObject *other_exc = NULL;
@@ -7796,7 +7921,7 @@ mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpoint
        mono_stats.delegate_creations++;
 
 #ifndef DISABLE_REMOTING
-       if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
+       if (target && mono_object_is_transparent_proxy (target)) {
                g_assert (method);
                method = mono_marshal_get_remoting_invoke (method);
                delegate->method_ptr = mono_compile_method_checked (method, error);
@@ -7809,7 +7934,7 @@ mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpoint
                MONO_OBJECT_SETREF (delegate, target, target);
        }
 
-       delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
+       delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
        if (callbacks.init_delegate)
                callbacks.init_delegate (delegate);
        return TRUE;
@@ -7843,7 +7968,7 @@ mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, Mon
                ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
        if (ji) {
                method = mono_jit_info_get_method (ji);
-               g_assert (!method->klass->generic_container);
+               g_assert (!mono_class_is_gtd (method->klass));
        }
 
        return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
@@ -8312,6 +8437,21 @@ mono_string_length (MonoString *s)
        return s->length;
 }
 
+/**
+ * mono_string_handle_length:
+ * @s: MonoString
+ *
+ * Returns the lenght in characters of the string
+ */
+int
+mono_string_handle_length (MonoStringHandle s)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       return MONO_HANDLE_GETVAL (s, length);
+}
+
+
 /**
  * mono_array_length:
  * @array: a MonoArray*