Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[mono.git] / mono / metadata / marshal.c
index 711bede6320378668cbbe7b55e152a98a7b40254..a9674cc1aaf944357e8575c05b6d6a84de87b4a0 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  *
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
@@ -19,6 +20,7 @@
 #include "loader.h"
 #include "cil-coff.h"
 #include "metadata/marshal.h"
+#include "metadata/marshal-internals.h"
 #include "metadata/method-builder.h"
 #include "metadata/tabledefs.h"
 #include "metadata/exception.h"
 #include "mono/metadata/remoting.h"
 #include "mono/metadata/reflection-internals.h"
 #include "mono/metadata/threadpool-ms.h"
+#include "mono/metadata/handle.h"
 #include "mono/utils/mono-counters.h"
 #include "mono/utils/mono-tls.h"
 #include "mono/utils/mono-memory-model.h"
 #include "mono/utils/atomic.h"
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
+#include <mono/utils/mono-error-internals.h>
 
 #include <string.h>
 #include <errno.h>
@@ -77,14 +82,23 @@ static MonoNativeTlsKey load_type_info_tls_id;
 
 static gboolean use_aot_wrappers;
 
+static int class_marshal_info_count;
+
+static void ftnptr_eh_callback_default (guint32 gchandle);
+
+static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default;
+
 static void
 delegate_hash_table_add (MonoDelegate *d);
 
+static void
+delegate_hash_table_remove (MonoDelegate *d);
+
 static void
 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
 
 static void
-emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
+emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
 
 static void 
 mono_struct_delete_old (MonoClass *klass, char *ptr);
@@ -96,7 +110,7 @@ static void *
 mono_marshal_string_to_utf16_copy (MonoString *s);
 
 static gpointer
-mono_string_to_lpstr (MonoString *string_obj);
+mono_string_to_utf8str (MonoString *string_obj);
 
 static MonoStringBuilder *
 mono_string_utf8_to_builder2 (char *text);
@@ -139,26 +153,91 @@ mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *ca
 
 static void init_safe_handle (void);
 
+static void*
+ves_icall_marshal_alloc (gulong size);
+
+void
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
+
+void
+mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
+
+gchar*
+mono_string_builder_to_utf8 (MonoStringBuilder *sb);
+
+gunichar2*
+mono_string_builder_to_utf16 (MonoStringBuilder *sb);
+
+void
+mono_string_to_byvalstr (gpointer dst, MonoString *src, int size);
+
+void
+mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size);
+
+gpointer
+mono_delegate_to_ftnptr (MonoDelegate *delegate);
+
+MonoDelegate*
+mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
+gpointer
+mono_marshal_asany (MonoObject *obj, MonoMarshalNative string_encoding, int param_attrs);
+
+void
+mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle);
+
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error);
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error);
+
+/* Lazy class loading functions */
+static GENERATE_GET_CLASS_WITH_CACHE (string_builder, System.Text, StringBuilder)
+static GENERATE_GET_CLASS_WITH_CACHE (date_time, System, DateTime)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, System.Runtime.InteropServices, UnmanagedFunctionPointerAttribute)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, System.Runtime.InteropServices, ICustomMarshaler)
+
 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
 static MonoMethod *sh_dangerous_add_ref;
 static MonoMethod *sh_dangerous_release;
 
-
 static void
 init_safe_handle ()
 {
        sh_dangerous_add_ref = mono_class_get_method_from_name (
-               mono_defaults.safehandle_class, "DangerousAddRef", 1);
+               mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
        sh_dangerous_release = mono_class_get_method_from_name (
-               mono_defaults.safehandle_class, "DangerousRelease", 0);
+               mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
 }
 
 static void
-register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
 {
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
 
-       mono_register_jit_icall (func, name, sig, save);
+       mono_register_jit_icall (func, name, sig, no_wrapper);
 }
 
 MonoMethodSignature*
@@ -180,6 +259,33 @@ mono_marshal_init_tls (void)
        mono_native_tls_alloc (&load_type_info_tls_id, NULL);
 }
 
+static MonoObject*
+mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
+{
+       MonoError error;
+       MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
+static MonoString*
+ves_icall_mono_string_from_utf16 (gunichar2 *data)
+{
+       MonoError error;
+       MonoString *result = mono_string_from_utf16_checked (data, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
+static char*
+ves_icall_mono_string_to_utf8 (MonoString *str)
+{
+       MonoError error;
+       char *result = mono_string_to_utf8_checked (str, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
 void
 mono_marshal_init (void)
 {
@@ -194,13 +300,13 @@ mono_marshal_init (void)
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
                register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
                register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
-               register_icall (mono_string_from_utf16, "mono_string_from_utf16", "obj ptr", FALSE);
+               register_icall (ves_icall_mono_string_from_utf16, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE);
                register_icall (mono_string_from_byvalstr, "mono_string_from_byvalstr", "obj ptr int", FALSE);
                register_icall (mono_string_from_byvalwstr, "mono_string_from_byvalwstr", "obj ptr int", FALSE);
                register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
                register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
-               register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE);
-               register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE);
+               register_icall (ves_icall_mono_string_to_utf8, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE);
+               register_icall (mono_string_to_utf8str, "mono_string_to_utf8str", "ptr obj", FALSE);
                register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
                register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
@@ -215,7 +321,7 @@ mono_marshal_init (void)
                register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
                register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
                register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
-               register_icall (mono_marshal_alloc, "mono_marshal_alloc", "ptr int32", FALSE);
+               register_icall (ves_icall_marshal_alloc, "ves_icall_marshal_alloc", "ptr int32", FALSE);
                register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
                register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE);
                register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE);
@@ -227,26 +333,31 @@ mono_marshal_init (void)
                register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
                register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
                register_icall (g_free, "g_free", "void ptr", FALSE);
-               register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
+               register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
                register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
                register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
                register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
-               register_icall (mono_compile_method, "mono_compile_method", "ptr ptr", FALSE);
                register_icall (mono_context_get, "mono_context_get", "object", FALSE);
                register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
                register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
                register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
+               register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
                register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
+               register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
+               register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
+               register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
+               register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
+               register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
+               register_icall (mono_icall_start, "mono_icall_start", "ptr ptr ptr", TRUE);
+               register_icall (mono_icall_end, "mono_icall_end", "void ptr ptr ptr", TRUE);
+               register_icall (mono_handle_new, "mono_handle_new", "ptr ptr", TRUE);
 
                mono_cominterop_init ();
                mono_remoting_init ();
 
-               if (mono_threads_is_coop_enabled ()) {
-                       register_icall (mono_threads_prepare_blocking, "mono_threads_prepare_blocking", "ptr ptr", FALSE);
-                       register_icall (mono_threads_finish_blocking, "mono_threads_finish_blocking", "void ptr ptr", FALSE);
-                       register_icall (mono_threads_reset_blocking_start, "mono_threads_reset_blocking_start","ptr ptr", TRUE);
-                       register_icall (mono_threads_reset_blocking_end, "mono_threads_reset_blocking_end","void ptr ptr", TRUE);
-               }
+               mono_counters_register ("MonoClass::class_marshal_info_count count",
+                                                               MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_marshal_info_count);
+
        }
 }
 
@@ -273,9 +384,11 @@ mono_marshal_unlock_internal (void)
        mono_marshal_unlock ();
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 gpointer
 mono_delegate_to_ftnptr (MonoDelegate *delegate)
 {
+       MonoError error;
        MonoMethod *method, *wrapper;
        MonoClass *klass;
        uint32_t target_handle = 0;
@@ -290,15 +403,18 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        g_assert (klass->delegate);
 
        method = delegate->method;
+       if (delegate->method_is_virtual)
+               method = mono_object_get_virtual_method (delegate->target, method);
 
-       if (mono_method_signature (method)->pinvoke) {
+       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                const char *exc_class, *exc_arg;
                gpointer ftnptr;
 
                ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
                if (!ftnptr) {
                        g_assert (exc_class);
-                       mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                       mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                       return NULL;
                }
                return ftnptr;
        }
@@ -310,7 +426,9 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
 
        wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
 
-       delegate->delegate_trampoline = mono_compile_method (wrapper);
+       delegate->delegate_trampoline = mono_compile_method_checked (wrapper, &error);
+       if (!is_ok (&error))
+               goto fail;
 
        // Add the delegate to the delegate hash table
        delegate_hash_table_add (delegate);
@@ -319,6 +437,12 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        mono_object_register_finalizer ((MonoObject*)delegate);
 
        return delegate->delegate_trampoline;
+
+fail:
+       if (target_handle != 0)
+               mono_gchandle_free (target_handle);
+       mono_error_set_pending_exception (&error);
+       return NULL;
 }
 
 /* 
@@ -384,23 +508,23 @@ mono_marshal_use_aot_wrappers (gboolean use)
 static void
 parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
 {
-       static MonoClass *UnmanagedFunctionPointerAttribute;
+       MonoError error;
        MonoCustomAttrInfo *cinfo;
        MonoReflectionUnmanagedFunctionPointerAttribute *attr;
 
-       if (!UnmanagedFunctionPointerAttribute)
-               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
        /* The attribute is only available in Net 2.0 */
-       if (UnmanagedFunctionPointerAttribute) {
+       if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                /* 
                 * The pinvoke attributes are stored in a real custom attribute so we have to
                 * construct it.
                 */
-               cinfo = mono_custom_attrs_from_class (klass);
+               cinfo = mono_custom_attrs_from_class_checked (klass, &error);
+               if (!mono_error_ok (&error)) {
+                       g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
+                       mono_error_cleanup (&error);
+               }
                if (cinfo && !mono_runtime_get_no_exec ()) {
-                       MonoError error;
-                       attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, UnmanagedFunctionPointerAttribute, &error);
+                       attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
                        if (attr) {
                                piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
                        } else {
@@ -415,9 +539,11 @@ parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piin
        }
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
 MonoDelegate*
 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
 {
+       MonoError error;
        guint32 gchandle;
        MonoDelegate *d;
 
@@ -451,7 +577,11 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
 
                if (use_aot_wrappers) {
                        wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
-                       this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+                       this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
+                       if (!is_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                } else {
                        memset (&piinfo, 0, sizeof (piinfo));
                        parse_unmanaged_function_pointer_attr (klass, &piinfo);
@@ -472,12 +602,23 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                        g_free (sig);
                }
 
-               d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
-               mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
+               d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
+               gpointer compiled_ptr = mono_compile_method_checked (wrapper, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
+               mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, compiled_ptr, wrapper, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
        }
 
-       if (d->object.vtable->domain != mono_domain_get ())
-               mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+       if (d->object.vtable->domain != mono_domain_get ()) {
+               mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+               return NULL;
+       }
 
        return d;
 }
@@ -518,9 +659,11 @@ mono_delegate_free_ftnptr (MonoDelegate *delegate)
        }
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
 static MonoString *
 mono_string_from_byvalstr (const char *data, int max_len)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
 
@@ -530,12 +673,17 @@ mono_string_from_byvalstr (const char *data, int max_len)
        while (len < max_len - 1 && data [len])
                len++;
 
-       return mono_string_new_len (domain, data, len);
+       MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 static MonoString *
 mono_string_from_byvalwstr (gunichar2 *data, int max_len)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
 
@@ -544,7 +692,12 @@ mono_string_from_byvalwstr (gunichar2 *data, int max_len)
 
        while (data [len]) len++;
 
-       return mono_string_new_utf16 (domain, data, MIN (len, max_len));
+       res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 gpointer
@@ -632,7 +785,7 @@ mono_free_lparray (MonoArray *array, gpointer* nativeArray)
        if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS) {
                for(i = 0; i < array->max_length; ++i)
                        mono_marshal_free_ccw (mono_array_get (array, MonoObject*, i));
-               free(nativeArray);
+               g_free (nativeArray);
        }
 #endif
 }
@@ -666,6 +819,7 @@ mono_byvalarray_to_byte_array (MonoArray *arr, gpointer native_arr, guint32 elnu
        mono_byvalarray_to_array (arr, native_arr, mono_defaults.byte_class, elnum);
 }
 
+/* This is a JIT icall, it sets the pending exception and returns on error */
 static void
 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
 {
@@ -677,9 +831,9 @@ mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclas
 
                as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
                if (error) {
-                       MonoException *exc = mono_get_exception_argument ("string", error->message);
+                       mono_set_pending_exception (mono_get_exception_argument ("string", error->message));
                        g_error_free (error);
-                       mono_raise_exception (exc);
+                       return;
                }
 
                memcpy (native_arr, as, MIN (strlen (as), elnum));
@@ -701,6 +855,8 @@ mono_string_builder_new (int starting_string_length)
        static MonoClass *string_builder_class;
        static MonoMethod *sb_ctor;
        static void *args [1];
+
+       MonoError error;
        int initial_len = starting_string_length;
 
        if (initial_len < 0)
@@ -710,7 +866,7 @@ mono_string_builder_new (int starting_string_length)
                MonoMethodDesc *desc;
                MonoMethod *m;
 
-               string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
+               string_builder_class = mono_class_get_string_builder_class ();
                g_assert (string_builder_class);
                desc = mono_method_desc_new (":.ctor(int)", FALSE);
                m = mono_method_desc_search_in_class (desc, string_builder_class);
@@ -724,12 +880,13 @@ mono_string_builder_new (int starting_string_length)
        // array will always be garbage collected.
        args [0] = &initial_len;
 
-       MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
-       MonoObject *exc;
-       g_assert (sb);
+       MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new_checked (mono_domain_get (), string_builder_class, &error);
+       mono_error_assert_ok (&error);
 
-       mono_runtime_invoke (sb_ctor, sb, args, &exc);
-       g_assert (!exc);
+       MonoObject *exc;
+       mono_runtime_try_invoke (sb_ctor, sb, args, &exc, &error);
+       g_assert (exc == NULL);
+       mono_error_assert_ok (&error);
 
        g_assert (sb->chunkChars->max_length >= initial_len);
 
@@ -769,13 +926,13 @@ mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
        if (!sb || !text)
                return;
 
-       int len = strlen (text);
-       if (len > mono_string_builder_capacity (sb))
-               len = mono_string_builder_capacity (sb);
-
        GError *error = NULL;
        glong copied;
-       gunichar2* ut = g_utf8_to_utf16 (text, len, NULL, &copied, &error);
+       gunichar2* ut = g_utf8_to_utf16 (text, strlen (text), NULL, &copied, &error);
+       int capacity = mono_string_builder_capacity (sb);
+
+       if (copied > capacity)
+               copied = capacity;
 
        if (!error) {
                MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
@@ -799,7 +956,6 @@ mono_string_utf8_to_builder2 (char *text)
        return sb;
 }
 
-
 void
 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
 {
@@ -823,37 +979,44 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
  *
  * Returns: a utf8 string with the contents of the StringBuilder.
  *
- * The return value must be released with g_free.
+ * The return value must be released with mono_marshal_free.
+ *
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
  */
 gchar*
 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
 {
-       GError *error = NULL;
-
+       MonoError error;
+       GError *gerror = NULL;
+       glong byte_count;
        if (!sb)
                return NULL;
 
-
        gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
 
        guint str_len = mono_string_builder_string_length (sb);
 
-       gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, NULL, &error);
+       gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, &byte_count, &gerror);
 
-       if (error) {
-               g_error_free (error);
-               g_free (str_utf16);
-               mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
+       if (gerror) {
+               g_error_free (gerror);
+               mono_marshal_free (str_utf16);
+               mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
                return NULL;
        } else {
                guint len = mono_string_builder_capacity (sb) + 1;
-               gchar *res = (gchar *)mono_marshal_alloc (len * sizeof (gchar));
-               g_assert (str_len < len);
-               memcpy (res, tmp, str_len * sizeof (gchar));
-               res[str_len] = '\0';
+               gchar *res = (gchar *)mono_marshal_alloc (MAX (byte_count+1, len * sizeof (gchar)), &error);
+               if (!mono_error_ok (&error)) {
+                       mono_marshal_free (str_utf16);
+                       g_free (tmp);
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
 
+               memcpy (res, tmp, byte_count);
+               res[byte_count] = '\0';
 
-               g_free (str_utf16);
+               mono_marshal_free (str_utf16);
                g_free (tmp);
                return res;
        }
@@ -867,11 +1030,15 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
  *
  * Returns: a utf16 string with the contents of the StringBuilder.
  *
- * The return value must not be freed.
+ * The return value must be released with mono_marshal_free.
+ *
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
  */
 gunichar2*
 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
 {
+       MonoError error;
+
        if (!sb)
                return NULL;
 
@@ -882,7 +1049,12 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb)
        if (len == 0)
                len = 1;
 
-       gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2));
+       gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2), &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+
        str[len] = '\0';
 
        if (len == 0)
@@ -908,39 +1080,15 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb)
        return str;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static gpointer
-mono_string_to_lpstr (MonoString *s)
+mono_string_to_utf8str (MonoString *s)
 {
-#ifdef TARGET_WIN32
-       char *as, *tmp;
-       glong len;
-       GError *error = NULL;
-
-       if (s == NULL)
-               return NULL;
-
-       if (!s->length) {
-               as = CoTaskMemAlloc (1);
-               as [0] = '\0';
-               return as;
-       }
-
-       tmp = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &len, &error);
-       if (error) {
-               MonoException *exc = mono_get_exception_argument ("string", error->message);
-               g_error_free (error);
-               mono_raise_exception(exc);
-               return NULL;
-       } else {
-               as = CoTaskMemAlloc (len + 1);
-               memcpy (as, tmp, len + 1);
-               g_free (tmp);
-               return as;
-       }
-#else
-       return mono_string_to_utf8 (s);
-#endif
-}      
+       MonoError error;
+       char *result = mono_string_to_utf8_checked (s, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
 
 gpointer
 mono_string_to_ansibstr (MonoString *string_obj)
@@ -961,6 +1109,7 @@ mono_string_to_ansibstr (MonoString *string_obj)
 void
 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
 {
+       MonoError error;
        char *s;
        int len;
 
@@ -971,7 +1120,9 @@ mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
        if (!src)
                return;
 
-       s = mono_string_to_utf8 (src);
+       s = mono_string_to_utf8_checked (src, &error);
+       if (mono_error_set_pending_exception (&error))
+               return;
        len = MIN (size, strlen (s));
        if (len >= size)
                len--;
@@ -1009,10 +1160,14 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
        *((gunichar2 *) dst + len) = 0;
 }
 
+/* this is an icall, it sets the pending exception and returns NULL on error */
 static MonoString*
 mono_string_new_len_wrapper (const char *text, guint length)
 {
-       return mono_string_new_len (mono_domain_get (), text, length);
+       MonoError error;
+       MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 #ifndef DISABLE_JIT
@@ -1099,7 +1254,8 @@ guint
 mono_type_to_stind (MonoType *type)
 {
        if (type->byref)
-               return CEE_STIND_I;
+               return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
+
 
 handle_enum:
        switch (type->type) {
@@ -1195,7 +1351,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
                mono_mb_emit_op (mb, CEE_NEWARR, eklass);       
-               mono_mb_emit_byte (mb, CEE_STIND_I);
+               mono_mb_emit_byte (mb, CEE_STIND_REF);
 
                if (eklass->blittable) {
                        /* copy the elements */
@@ -1305,7 +1461,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                } else {
                        mono_mb_emit_ldloc (mb, 1);
                        mono_mb_emit_ldloc (mb, 0);
-                       mono_mb_emit_icall (mb, mono_string_from_utf16);
+                       mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                }
                mono_mb_emit_byte (mb, CEE_STIND_REF);          
                break;          
@@ -1314,13 +1470,16 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 #ifdef TARGET_WIN32
-               mono_mb_emit_icall (mb, mono_string_from_utf16);
+               mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
 #else
                mono_mb_emit_icall (mb, mono_string_new_wrapper);
 #endif
                mono_mb_emit_byte (mb, CEE_STIND_REF);  
                break;
+
+               // In Mono historically LPSTR was treated as a UTF8STR
        case MONO_MARSHAL_CONV_STR_LPSTR:
+       case MONO_MARSHAL_CONV_STR_UTF8STR:
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
@@ -1331,7 +1490,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_icall (mb, mono_string_from_utf16);
+               mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
                mono_mb_emit_byte (mb, CEE_STIND_REF);
                break;
        case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
@@ -1433,32 +1592,44 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
 }
 
 static gpointer
-conv_to_icall (MonoMarshalConv conv)
+conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
 {
+       int dummy;
+       if (!ind_store_type)
+               ind_store_type = &dummy;
+       *ind_store_type = CEE_STIND_I;
        switch (conv) {
        case MONO_MARSHAL_CONV_STR_LPWSTR:
                return mono_marshal_string_to_utf16;            
        case MONO_MARSHAL_CONV_LPWSTR_STR:
-               return mono_string_from_utf16;
+               *ind_store_type = CEE_STIND_REF;
+               return ves_icall_mono_string_from_utf16;
        case MONO_MARSHAL_CONV_LPTSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
+       case MONO_MARSHAL_CONV_UTF8STR_STR:
        case MONO_MARSHAL_CONV_LPSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
        case MONO_MARSHAL_CONV_STR_LPTSTR:
 #ifdef TARGET_WIN32
                return mono_marshal_string_to_utf16;
 #else
-               return mono_string_to_lpstr;
+               return mono_string_to_utf8str;
 #endif
+               // In Mono historically LPSTR was treated as a UTF8STR
+       case MONO_MARSHAL_CONV_STR_UTF8STR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
-               return mono_string_to_lpstr;
+               return mono_string_to_utf8str;
        case MONO_MARSHAL_CONV_STR_BSTR:
                return mono_string_to_bstr;
        case MONO_MARSHAL_CONV_BSTR_STR:
-               return mono_string_from_bstr;
+               *ind_store_type = CEE_STIND_REF;
+               return mono_string_from_bstr_icall;
        case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
                return mono_string_to_ansibstr;
+       case MONO_MARSHAL_CONV_SB_UTF8STR:
        case MONO_MARSHAL_CONV_SB_LPSTR:
                return mono_string_builder_to_utf8;
        case MONO_MARSHAL_CONV_SB_LPTSTR:
@@ -1478,16 +1649,21 @@ conv_to_icall (MonoMarshalConv conv)
        case MONO_MARSHAL_CONV_DEL_FTN:
                return mono_delegate_to_ftnptr;
        case MONO_MARSHAL_CONV_FTN_DEL:
+               *ind_store_type = CEE_STIND_REF;
                return mono_ftnptr_to_delegate;
+       case MONO_MARSHAL_CONV_UTF8STR_SB:
        case MONO_MARSHAL_CONV_LPSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_utf8_to_builder;
        case MONO_MARSHAL_CONV_LPTSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
 #ifdef TARGET_WIN32
                return mono_string_utf16_to_builder;
 #else
                return mono_string_utf8_to_builder;
 #endif
        case MONO_MARSHAL_CONV_LPWSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_utf16_to_builder;
        case MONO_MARSHAL_FREE_ARRAY:
                return mono_marshal_free_array;
@@ -1506,6 +1682,7 @@ static void
 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
 {
        int pos;
+       int stind_op;
 
        switch (conv) {
        case MONO_MARSHAL_CONV_BOOL_I4:
@@ -1521,6 +1698,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_byte (mb, CEE_NEG);
                mono_mb_emit_byte (mb, CEE_STIND_I2);
                break;
+       // In Mono historically LPSTR was treated as a UTF8STR
+       case MONO_MARSHAL_CONV_STR_UTF8STR:
        case MONO_MARSHAL_CONV_STR_LPWSTR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
        case MONO_MARSHAL_CONV_STR_LPTSTR:
@@ -1540,8 +1719,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
-               mono_mb_emit_byte (mb, CEE_STIND_I);    
+               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+               mono_mb_emit_byte (mb, stind_op);
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
@@ -1550,8 +1729,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
-               mono_mb_emit_byte (mb, CEE_STIND_I);    
+               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+               mono_mb_emit_byte (mb, stind_op);
                break;
        case MONO_MARSHAL_CONV_STR_BYVALSTR: 
        case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
@@ -1561,7 +1740,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 0);     
                mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
@@ -1740,24 +1919,31 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
        }
                
        default: {
-               char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
-               MonoException *exc = mono_get_exception_not_implemented (msg);
-               g_warning ("%s", msg);
-               g_free (msg);
-               mono_raise_exception (exc);
+               g_error ("marshalling conversion %d not implemented", conv);
+       }
        }
+}
+
+static int offset_of_first_nonstatic_field(MonoClass *klass)
+{
+       int i;
+       for (i = 0; i < klass->field.count; i++) {
+               if (!(klass->fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass->fields[i]))
+                       return klass->fields[i].offset - sizeof (MonoObject);
        }
+
+       return 0;
 }
 
 static void
 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
-                                          MonoMarshalNative string_encoding)
+                                               int offset_of_first_child_field, MonoMarshalNative string_encoding)
 {
        MonoMarshalType *info;
        int i;
 
        if (klass->parent)
-               emit_struct_conv(mb, klass->parent, to_object);
+               emit_struct_conv_full (mb, klass->parent, to_object, offset_of_first_nonstatic_field (klass), string_encoding);
 
        info = mono_marshal_load_type_info (klass);
 
@@ -1765,21 +1951,26 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                return;
 
        if (klass->blittable) {
-               int msize = mono_class_value_size (klass, NULL);
-               g_assert (msize == info->native_size);
+               int usize = mono_class_value_size (klass, NULL);
+               g_assert (usize == info->native_size);
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
-               mono_mb_emit_icon (mb, msize);
+               mono_mb_emit_icon (mb, usize);
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);
 
-               mono_mb_emit_add_to_local (mb, 0, msize);
-               mono_mb_emit_add_to_local (mb, 1, msize);
+               if (to_object) {
+                       mono_mb_emit_add_to_local (mb, 0, usize);
+                       mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
+               } else {
+                       mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
+                       mono_mb_emit_add_to_local (mb, 1, usize);
+               }
                return;
        }
 
-       if (klass != mono_defaults.safehandle_class) {
-               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+       if (klass != mono_class_try_get_safehandle_class ()) {
+               if (mono_class_is_auto_layout (klass)) {
                        char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
                                                                                 mono_type_full_name (&klass->byval_arg));
                        mono_mb_emit_exception_marshal_directive (mb, msg);
@@ -1808,13 +1999,13 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                        usize = info->fields [i + 1].offset - info->fields [i].offset;
                }
 
-               if (klass != mono_defaults.safehandle_class){
+               if (klass != mono_class_try_get_safehandle_class ()){
                        /* 
                         * FIXME: Should really check for usize==0 and msize>0, but we apply 
                         * the layout to the managed structure as well.
                         */
                        
-                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
+                       if (mono_class_is_explicit_layout (klass) && (usize == 0)) {
                                if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
                                    ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
                                        g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
@@ -1827,8 +2018,9 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                case MONO_MARSHAL_CONV_NONE: {
                        int t;
 
-                       if (ftype->byref || ftype->type == MONO_TYPE_I ||
-                           ftype->type == MONO_TYPE_U) {
+                       //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
+                       g_assert (!ftype->byref);
+                       if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
                                mono_mb_emit_ldloc (mb, 1);
                                mono_mb_emit_ldloc (mb, 0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
@@ -1977,7 +2169,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
 static void
 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
 {
-       emit_struct_conv_full (mb, klass, to_object, (MonoMarshalNative)-1);
+       emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
 }
 
 static void
@@ -2044,24 +2236,26 @@ mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
 
 #endif /* DISABLE_JIT */
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static MonoAsyncResult *
 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 {
+       MonoError error;
        MonoMulticastDelegate *mcast_delegate;
        MonoClass *klass;
        MonoMethod *method;
 
        g_assert (delegate);
        mcast_delegate = (MonoMulticastDelegate *) delegate;
-       if (mcast_delegate->delegates != NULL)
-               mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+       if (mcast_delegate->delegates != NULL) {
+               mono_set_pending_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+               return NULL;
+       }
 
 #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
-
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
                if (!mono_class_is_contextbound (tp->remote_class->proxy_class) || tp->rp->context != (MonoObject *) mono_context_get ()) {
-
                        /* If the target is a proxy, make a direct call. Is proxy's work
                        // to make the call asynchronous.
                        */
@@ -2073,17 +2267,25 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
                        MonoArray *out_args;
                        method = delegate->method;
 
-                       msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
-                       ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL);
+                       msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state, &error);
+                       if (mono_error_set_pending_exception (&error))
+                               return NULL;
+                       ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL, &error);
+                       if (mono_error_set_pending_exception (&error))
+                               return NULL;
                        MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
                        MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
                        MONO_OBJECT_SETREF (msg, async_result, ares);
                        msg->call_type = CallType_BeginInvoke;
 
                        exc = NULL;
-                       mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+                       mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                        if (exc)
-                               mono_raise_exception ((MonoException *) exc);
+                               mono_set_pending_exception ((MonoException *) exc);
                        return ares;
                }
        }
@@ -2096,7 +2298,9 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
                method = mono_get_delegate_invoke (klass);
        g_assert (method);
 
-       return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
+       MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 #ifndef DISABLE_JIT
@@ -2224,8 +2428,10 @@ mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
                return MONO_MARSHAL_CONV_STR_LPTSTR;
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_STR_BSTR;
+       case MONO_NATIVE_UTF8STR:
+               return MONO_MARSHAL_CONV_STR_UTF8STR;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2237,15 +2443,14 @@ mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarsh
        switch (encoding) {
        case MONO_NATIVE_LPWSTR:
                return MONO_MARSHAL_CONV_SB_LPWSTR;
-               break;
        case MONO_NATIVE_LPSTR:
                return MONO_MARSHAL_CONV_SB_LPSTR;
-               break;
+       case MONO_NATIVE_UTF8STR:
+               return MONO_MARSHAL_CONV_SB_UTF8STR;
        case MONO_NATIVE_LPTSTR:
                return MONO_MARSHAL_CONV_SB_LPTSTR;
-               break;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2260,6 +2465,8 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
        case MONO_NATIVE_LPWSTR:
                *need_free = FALSE;
                return MONO_MARSHAL_CONV_LPWSTR_STR;
+       case MONO_NATIVE_UTF8STR:
+               return MONO_MARSHAL_CONV_UTF8STR_STR;
        case MONO_NATIVE_LPSTR:
        case MONO_NATIVE_VBBYREFSTR:
                return MONO_MARSHAL_CONV_LPSTR_STR;
@@ -2268,7 +2475,7 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_BSTR_STR;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2287,6 +2494,8 @@ mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarsh
                 */
                *need_free = FALSE;
                return MONO_MARSHAL_CONV_LPWSTR_SB;
+       case MONO_NATIVE_UTF8STR:
+               return MONO_MARSHAL_CONV_UTF8STR_SB;
        case MONO_NATIVE_LPSTR:
                return MONO_MARSHAL_CONV_LPSTR_SB;
                break;
@@ -2294,7 +2503,7 @@ mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarsh
                return MONO_MARSHAL_CONV_LPTSTR_SB;
                break;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2474,6 +2683,11 @@ mono_marshal_method_from_wrapper (MonoMethod *wrapper)
                        return info->d.runtime_invoke.method;
                else
                        return NULL;
+       case MONO_WRAPPER_DELEGATE_INVOKE:
+               if (info)
+                       return info->d.delegate_invoke.method;
+               else
+                       return NULL;
        default:
                return NULL;
        }
@@ -2669,6 +2883,7 @@ cache_generic_delegate_wrapper (GHashTable *cache, MonoMethod *orig_method, Mono
 {
        MonoError error;
        MonoMethod *inst, *res;
+       WrapperInfo *ginfo, *info;
 
        /*
         * We use the same cache for the generic definition and the instances.
@@ -2676,6 +2891,16 @@ cache_generic_delegate_wrapper (GHashTable *cache, MonoMethod *orig_method, Mono
        inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
        g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
 
+       ginfo = mono_marshal_get_wrapper_info (def);
+       if (ginfo) {
+               info = (WrapperInfo *)mono_image_alloc0 (def->klass->image, sizeof (WrapperInfo));
+               info->subtype = ginfo->subtype;
+               if (info->subtype == WRAPPER_SUBTYPE_NONE) {
+                       info->d.delegate_invoke.method = mono_class_inflate_generic_method_checked (ginfo->d.delegate_invoke.method, ctx, &error);
+                       mono_error_assert_ok (&error);
+               }
+       }
+
        mono_memory_barrier ();
        mono_marshal_lock ();
        res = (MonoMethod *)g_hash_table_lookup (cache, orig_method->klass);
@@ -2759,9 +2984,11 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        return res;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static MonoObject *
 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoAsyncResult *ares;
        MonoMethod *method = NULL;
@@ -2775,7 +3002,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 
        if (!delegate->method_info) {
                g_assert (delegate->method);
-               MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
+               MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
+               MONO_OBJECT_SETREF (delegate, method_info, rm);
        }
 
        if (!delegate->method_info || !delegate->method_info->method)
@@ -2788,16 +3020,18 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 
        sig = mono_signature_no_pinvoke (method);
 
-       msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
+       msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
 
        ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
        if (ares == NULL) {
-               mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
+               mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
                return NULL;
        }
 
        if (ares->async_delegate != (MonoObject*)delegate) {
-               mono_raise_exception (mono_get_exception_invalid_operation (
+               mono_set_pending_exception (mono_get_exception_invalid_operation (
                        "The IAsyncResult object provided does not match this delegate."));
                return NULL;
        }
@@ -2805,30 +3039,47 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
-               msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
-               mono_message_init (domain, msg, delegate->method_info, NULL);
+               msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
+               mono_message_init (domain, msg, delegate->method_info, NULL, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
                msg->call_type = CallType_EndInvoke;
                MONO_OBJECT_SETREF (msg, async_result, ares);
-               res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+               res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
        } else
 #endif
        {
-               res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc);
+               res = mono_threadpool_ms_end_invoke (ares, &out_args, &exc, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
        }
 
        if (exc) {
                if (((MonoException*)exc)->stack_trace) {
-                       char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
-                       char  *tmp;
-                       tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
-                       g_free (strace);        
-                       MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
-                       g_free (tmp);
+                       MonoError inner_error;
+                       char *strace = mono_string_to_utf8_checked (((MonoException*)exc)->stack_trace, &inner_error);
+                       if (is_ok (&inner_error)) {
+                               char  *tmp;
+                               tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
+                               g_free (strace);        
+                               MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
+                               g_free (tmp);
+                       } else
+                               mono_error_cleanup (&inner_error); /* no stack trace, but at least throw the original exception */
                }
-               mono_raise_exception ((MonoException*)exc);
+               mono_set_pending_exception ((MonoException*)exc);
        }
 
-       mono_method_return_message_restore (method, params, out_args);
+       mono_method_return_message_restore (method, params, out_args, &error);
+       mono_error_set_pending_exception (&error);
        return res;
 }
 
@@ -3010,22 +3261,6 @@ free_signature_pointer_pair (SignaturePointerPair *pair)
        g_free (pair);
 }
 
-static MonoMethodSignature*
-sig_to_rgctx_sig (MonoMethodSignature *sig)
-{
-       // FIXME: memory allocation
-       MonoMethodSignature *res;
-       int i;
-
-       res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
-       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
-       res->param_count = sig->param_count + 1;
-       for (i = 0; i < sig->param_count; ++i)
-               res->params [i] = sig->params [i];
-       res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
-       return res;
-}
-
 MonoMethod *
 mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
 {
@@ -3035,16 +3270,16 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        MonoMethod *res;
        GHashTable *cache;
        gpointer cache_key = NULL;
-       SignaturePointerPair key;
+       SignaturePointerPair key = { NULL, NULL };
        SignaturePointerPair *new_key;
        int local_i, local_len, local_delegates, local_d, local_target, local_res;
-       int pos0, pos1, pos2, pos3, pos4;
+       int pos0, pos1, pos2;
        char *name;
        MonoClass *target_class = NULL;
        gboolean closed_over_null = FALSE;
        MonoGenericContext *ctx = NULL;
        MonoGenericContainer *container = NULL;
-       MonoMethod *orig_method = NULL;
+       MonoMethod *orig_method = method;
        WrapperInfo *info;
        WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
        gboolean found;
@@ -3063,11 +3298,13 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        if (callvirt) {
                subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
                if (target_method->is_inflated) {
+                       MonoError error;
                        MonoType *target_type;
 
                        g_assert (method->signature->hasthis);
-                       target_type = mono_class_inflate_generic_type (method->signature->params [0],
-                               mono_method_get_context (method));
+                       target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
+                               mono_method_get_context (method), &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                        target_class = mono_class_from_mono_type (target_type);
                } else {
                        target_class = target_method->klass;
@@ -3086,13 +3323,12 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
         * For generic delegates, create a generic wrapper, and return an instance to help AOT.
         */
        if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
-               orig_method = method;
                ctx = &((MonoMethodInflated*)method)->context;
                method = ((MonoMethodInflated*)method)->declaring;
 
                container = mono_method_get_generic_container (method);
                if (!container)
-                       container = method->klass->generic_container;
+                       container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
 
                invoke_sig = sig = mono_signature_no_pinvoke (method);
@@ -3202,7 +3438,6 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        mono_mb_emit_byte (mb, CEE_LDIND_REF);
        mono_mb_emit_stloc (mb, local_delegates);
 
-
        /* if (delegates == null) */
        mono_mb_emit_ldloc (mb, local_delegates);
        pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
@@ -3226,41 +3461,17 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        // FIXME:
                        mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
                } else {
-                       MonoMethodSignature *rgctx_sig;
-
-                       // FIXME: Support this for the other cases as well
-                       mono_mb_emit_ldarg (mb, 0);
-                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
-                       mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-                       /* Rgctx case */
-                       rgctx_sig = sig_to_rgctx_sig (sig);
-
                        mono_mb_emit_ldloc (mb, local_target);
                        for (i = 0; i < sig->param_count; ++i)
                                mono_mb_emit_ldarg (mb, i + 1);
                        mono_mb_emit_ldarg (mb, 0);
-                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
                        mono_mb_emit_ldarg (mb, 0);
                        mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
-                       pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
-                       /* Non-rgctx case */
-                       mono_mb_patch_branch (mb, pos3);
-                       mono_mb_emit_ldloc (mb, local_target);
-                       for (i = 0; i < sig->param_count; ++i)
-                               mono_mb_emit_ldarg (mb, i + 1);
-                       mono_mb_emit_ldarg (mb, 0);
-                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
-                       mono_mb_emit_byte (mb, CEE_LDIND_I );
-                       mono_mb_emit_op (mb, CEE_CALLI, sig);
-
-                       mono_mb_patch_branch (mb, pos4);
-
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
                        mono_mb_emit_byte (mb, CEE_RET);
                }
        
@@ -3289,16 +3500,6 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        mono_mb_emit_op (mb, CEE_CALL, target_method);
                }
        } else {
-               MonoMethodSignature *rgctx_sig;
-
-               mono_mb_emit_ldarg (mb, 0);
-               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
-               mono_mb_emit_byte (mb, CEE_LDIND_I);
-               pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-               /* Rgctx case */
-               rgctx_sig = sig_to_rgctx_sig (invoke_sig);
-
                if (static_method_with_first_arg_bound) {
                        mono_mb_emit_ldloc (mb, local_target);
                        if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
@@ -3307,29 +3508,13 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                for (i = 0; i < sig->param_count; ++i)
                        mono_mb_emit_ldarg (mb, i + 1);
                mono_mb_emit_ldarg (mb, 0);
-               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
-               mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_ldarg (mb, 0);
-               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
                mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
-               pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
-               /* Non-rgctx case */
-               mono_mb_patch_branch (mb, pos3);
-               if (static_method_with_first_arg_bound) {
-                       mono_mb_emit_ldloc (mb, local_target);
-                       if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
-                               mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
-               }
-               for (i = 0; i < sig->param_count; ++i)
-                       mono_mb_emit_ldarg (mb, i + 1);
                mono_mb_emit_ldarg (mb, 0);
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
-
-               mono_mb_patch_branch (mb, pos4);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
        }
 
        mono_mb_emit_byte (mb, CEE_RET);
@@ -3385,23 +3570,22 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        mb->skip_visibility = 1;
 #endif /* DISABLE_JIT */
 
+       info = mono_wrapper_info_create (mb, subtype);
+       info->d.delegate_invoke.method = method;
+
        if (ctx) {
                MonoMethod *def;
 
-               def = mono_mb_create_and_cache (cache, cache_key, mb, sig, sig->param_count + 16);
+               def = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
                res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
        } else if (callvirt) {
                new_key = g_new0 (SignaturePointerPair, 1);
                *new_key = key;
 
-               info = mono_wrapper_info_create (mb, subtype);
-
                res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, info, &found);
                if (found)
                        g_free (new_key);
        } else {
-               info = mono_wrapper_info_create (mb, subtype);
-
                res = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
        }
        mono_mb_free (mb);
@@ -3537,7 +3721,6 @@ handle_enum:
        case MONO_TYPE_CHAR:
                return &mono_defaults.uint16_class->byval_arg;
        case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
                return &mono_defaults.int_class->byval_arg;
        case MONO_TYPE_VALUETYPE:
                if (t->data.klass->enumtype) {
@@ -3872,11 +4055,9 @@ emit_runtime_invoke_body (MonoMethodBuilder *mb, MonoImage *image, MonoMethod *m
  * it means that the compiled code for METHOD does not have to be looked up 
  * before calling the runtime invoke wrapper. In this case, the wrapper ignores
  * its METHOD argument.
- * If PASS_RGCTX is TRUE, the signature of the called method is changed to include a 'gpointer rgctx' as the
- * last argument (after 'this').
  */
 MonoMethod *
-mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean pass_rgctx)
+mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
 {
        MonoMethodSignature *sig, *csig, *callsig;
        MonoMethodBuilder *mb;
@@ -3942,11 +4123,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean
 
        sig = mono_method_signature (method);
 
-       if (pass_rgctx) {
-               sig = sig_to_rgctx_sig (sig);
-               callsig = sig_to_rgctx_sig (callsig);
-       }
-
        target_klass = get_wrapper_target_class (method->klass->image);
 
        /* Try to share wrappers for non-corlib methods with simple signatures */
@@ -4006,7 +4182,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean
        csig->call_convention = MONO_CALL_C;
 #endif
 
-       name = mono_signature_to_name (callsig, pass_rgctx ? (virtual_ ? "runtime_invoke_virtual_rgctx" : "runtime_invoke_rgctx") : (virtual_ ? "runtime_invoke_virtual" : "runtime_invoke"));
+       name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : "runtime_invoke");
        mb = mono_mb_new (target_klass, name,  MONO_WRAPPER_RUNTIME_INVOKE);
        g_free (name);
 
@@ -4035,7 +4211,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean
 
                info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL);
                info->d.runtime_invoke.sig = callsig;
-               info->d.runtime_invoke.pass_rgctx = pass_rgctx;
 
                /* Somebody may have created it before us */
                if (!res) {
@@ -4079,7 +4254,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_, gboolean
  * ARGS should contain the this argument too.
  * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
  * is only one copy of it, which is useful in full-aot.
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod*
 mono_marshal_get_runtime_invoke_dynamic (void)
@@ -4306,7 +4480,6 @@ mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
 /*
  * generates IL code for the icall wrapper (the generated method
  * calls the unmanaged code in func)
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
@@ -4317,6 +4490,10 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon
        int i;
        WrapperInfo *info;
        
+       GHashTable *cache = get_cache (&mono_defaults.object_class->image->icall_wrapper_cache, mono_aligned_addr_hash, NULL);
+       if ((res = mono_marshal_find_in_cache (cache, (gpointer) func)))
+               return res;
+
        g_assert (sig->pinvoke);
 
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
@@ -4351,7 +4528,7 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon
 
        info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ICALL_WRAPPER);
        info->d.icall.func = (gpointer)func;
-       res = mono_mb_create (mb, csig, csig->param_count + 16, info);
+       res = mono_mb_create_and_cache_full (cache, (gpointer) func, mb, csig, csig->param_count + 16, info, NULL);
        mono_mb_free (mb);
 
        return res;
@@ -4368,6 +4545,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
                *conv_arg_type = &mono_defaults.int_class->byval_arg;
        return conv_arg;
 #else
+       MonoError error;
        MonoType *mtype;
        MonoClass *mklass;
        static MonoClass *ICustomMarshaler = NULL;
@@ -4380,7 +4558,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        int pos2;
 
        if (!ICustomMarshaler) {
-               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
+               MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
                if (!klass) {
                        exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
                        goto handle_exception;
@@ -4400,10 +4578,11 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        }
 
        if (spec->data.custom_data.image)
-               mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, spec->data.custom_data.image);
+               mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
        else
-               mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
+               mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
        g_assert (mtype != NULL);
+       mono_error_assert_ok (&error);
        mklass = mono_class_from_mono_type (mtype);
        g_assert (mklass != NULL);
 
@@ -4732,7 +4911,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
 
        klass = mono_class_from_mono_type (t);
 
-       date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
+       date_time_class = mono_class_get_date_time_class ();
 
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
@@ -4765,8 +4944,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        break;
                }
 
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype)
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
 
                conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
@@ -4812,8 +4990,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        /* Have to change the signature since the vtype is passed byref */
                        m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
 
-                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                               klass->blittable || klass->enumtype)
+                       if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                                mono_mb_emit_ldarg_addr (mb, argnum);
                        else
                                mono_mb_emit_ldloc (mb, conv_arg);
@@ -4828,8 +5005,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        break;
                }
 
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype) {
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        mono_mb_emit_ldarg (mb, argnum);
                        break;
                }                       
@@ -4861,8 +5037,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                        break;
                }
 
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype)
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
 
                if (t->byref) {
@@ -4890,15 +5065,14 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_CONV_RESULT:
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable) {
+               if (mono_class_is_explicit_layout (klass) || klass->blittable) {
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
 
                /* load pointer to returned value type */
-               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+               g_assert (m->vtaddr_var);
+               mono_mb_emit_ldloc (mb, m->vtaddr_var);
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
                /* set dst_ptr */
@@ -4910,8 +5084,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_IN:
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype) {
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        conv_arg = 0;
                        break;
                }
@@ -4943,11 +5116,8 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype) {
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
                        break;
-               }
-
                if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))
                        break;
 
@@ -4970,16 +5140,15 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype) {
+               if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
                        mono_mb_emit_stloc (mb, 3);
                        m->retobj_var = 0;
                        break;
                }
                        
                /* load pointer to returned value type */
-               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+               g_assert (m->vtaddr_var);
+               mono_mb_emit_ldloc (mb, m->vtaddr_var);
                        
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
@@ -4990,7 +5159,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                g_assert (m->retobj_var);
                mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_CONV_I);
-               mono_mb_emit_icall (mb, mono_marshal_alloc);
+               mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_stloc (mb, 1);
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_stloc (mb, m->retobj_var);
@@ -5042,11 +5211,11 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                }
 
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                } else {
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
 
                        mono_mb_emit_stloc (mb, conv_arg);
                }
@@ -5054,7 +5223,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
 
        case MARSHAL_ACTION_CONV_OUT:
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
@@ -5087,10 +5256,11 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
                        mono_mb_emit_byte (mb, CEE_STIND_REF);
                } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+                       int stind_op;
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_ldloc (mb, conv_arg);
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                        need_free = TRUE;
                }
 
@@ -5114,14 +5284,14 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                mono_mb_emit_stloc (mb, 0);
                                
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                }
 
                mono_mb_emit_ldloc (mb, 0);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
 
                /* free the string */
@@ -5143,7 +5313,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                }
 
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
@@ -5152,27 +5322,28 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                mono_mb_emit_ldarg (mb, argnum);
                if (t->byref)
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, conv_arg);
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (t->byref) {
                        if (conv_arg) {
+                               int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                        }
                }
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
-               if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
+               if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
                        /* We need to make a copy so the caller is able to free it */
                        mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
                else
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
                break;
 
@@ -5301,7 +5472,7 @@ emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t,
                MonoMethod *ctor = NULL;
                int intptr_handle_slot;
                
-               if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
+               if (mono_class_is_abstract (t->data.klass)) {
                        mono_mb_emit_byte (mb, CEE_POP);
                        mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
                        break;
@@ -5451,7 +5622,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_stloc (mb, conv_arg);
                        } else {
                                mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                                mono_mb_emit_stloc (mb, conv_arg);
                        }
                } else if (klass == mono_defaults.stringbuilder_class) {
@@ -5471,7 +5642,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
                                break;
 
-                       if (conv == -1) {
+                       if (conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
@@ -5481,7 +5652,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else if (klass->blittable) {
                        mono_mb_emit_byte (mb, CEE_LDNULL);
@@ -5574,6 +5745,9 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                case MONO_NATIVE_LPSTR:
                                        mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
                                        break;
+                               case MONO_NATIVE_UTF8STR:
+                                       mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
+                                       break;
                                default:
                                        g_assert_not_reached ();
                                }
@@ -5583,7 +5757,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
 
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        }
 
                        if (need_free) {
@@ -5599,7 +5773,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                                mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                                mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                        break;
@@ -5682,8 +5856,10 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                        mono_mb_emit_ldloc (mb, 0);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, 3);
+               } else if (klass == mono_defaults.stringbuilder_class){
+                       // FIXME: implement
                } else {
                        /* set src */
                        mono_mb_emit_stloc (mb, 0);
@@ -5732,7 +5908,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                        break;
                }
@@ -5743,7 +5919,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
 
                        // FIXME:
-                       g_assert (encoding == MONO_NATIVE_LPSTR);
+                       g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR);
 
                        g_assert (!t->byref);
                        g_assert (encoding != -1);
@@ -5755,7 +5931,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                }
 
                /* The class can not have an automatic layout */
-               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+               if (mono_class_is_auto_layout (klass)) {
                        mono_mb_emit_auto_layout_exception (mb, klass);
                        break;
                }
@@ -5806,10 +5982,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (klass->delegate) {
                        if (t->byref) {
+                               int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                                break;
                        }
                }
@@ -5833,7 +6010,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        /* Allocate and set dest */
                        mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                        mono_mb_emit_byte (mb, CEE_CONV_I);
-                       mono_mb_emit_icall (mb, mono_marshal_alloc);
+                       mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                        mono_mb_emit_stloc (mb, 1);
                        
                        /* Update argument pointer */
@@ -5868,13 +6045,13 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
 
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
                if (klass->delegate) {
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
 
                /* The class can not have an automatic layout */
-               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+               if (mono_class_is_auto_layout (klass)) {
                        mono_mb_emit_auto_layout_exception (mb, klass);
                        break;
                }
@@ -5897,7 +6074,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                /* Allocate and set dest */
                mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_CONV_I);
-               mono_mb_emit_icall (mb, mono_marshal_alloc);
+               mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_byte (mb, CEE_DUP);
                mono_mb_emit_stloc (mb, 1);
                mono_mb_emit_stloc (mb, 3);
@@ -6085,7 +6262,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else {
                        MonoClass *eklass;
@@ -6107,9 +6284,9 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                        }
                        else
-                               conv = (MonoMarshalConv)-1;
+                               conv = MONO_MARSHAL_CONV_INVALID;
 
-                       if (is_string && conv == -1) {
+                       if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
@@ -6165,12 +6342,13 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        /* Emit marshalling code */
 
                        if (is_string) {
+                               int stind_op;
                                mono_mb_emit_ldloc (mb, dest_ptr);
                                mono_mb_emit_ldloc (mb, src_var);
                                mono_mb_emit_ldloc (mb, index_var);
                                mono_mb_emit_byte (mb, CEE_LDELEM_REF);
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                        } else {
                                /* set the src_ptr */
                                mono_mb_emit_ldloc (mb, src_var);
@@ -6183,7 +6361,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_stloc (mb, 1);
 
                                /* emit valuetype conversion code */
-                               emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+                               emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
                        }
 
                        mono_mb_emit_add_to_local (mb, index_var, 1);
@@ -6234,7 +6412,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
                                mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
                                /* Store into argument */
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                }
 
@@ -6281,7 +6459,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                gboolean need_free2;
                                MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
 
-                               g_assert (conv != -1);
+                               g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                                /* dest */
                                mono_mb_emit_ldarg (mb, argnum);
@@ -6294,7 +6472,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_ldloc (mb, src_ptr);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
 
                                if (need_free) {
                                        /* src */
@@ -6328,7 +6506,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                        mono_mb_emit_stloc (mb, 1);
 
                                        /* emit valuetype conversion code */
-                                       emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+                                       emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
                                }
 
                                if (need_free) {
@@ -6356,7 +6534,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_REF);
                        mono_mb_emit_ldloc (mb, conv_arg);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
                }
 
                break;
@@ -6428,7 +6606,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
                }
                else
-                       conv = (MonoMarshalConv)-1;
+                       conv = MONO_MARSHAL_CONV_INVALID;
 
                mono_marshal_load_type_info (eklass);
 
@@ -6507,7 +6685,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_icon (mb, esize);
                        mono_mb_emit_byte (mb, CEE_MUL);
                        mono_mb_emit_byte (mb, CEE_PREFIX1);
-                       mono_mb_emit_byte (mb, CEE_CPBLK);                      
+                       mono_mb_emit_byte (mb, CEE_CPBLK);
+                       mono_mb_patch_branch (mb, label1);
                        break;
                }
 
@@ -6523,7 +6702,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        mono_mb_emit_ldloc (mb, conv_arg);
                        mono_mb_emit_ldloc (mb, index_var);
@@ -6531,7 +6710,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldloc (mb, src_ptr);
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_byte (mb, CEE_STELEM_REF);
                }
                else {
@@ -6591,7 +6770,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                }
                else
-                       conv = (MonoMarshalConv)-1;
+                       conv = MONO_MARSHAL_CONV_INVALID;
 
                mono_marshal_load_type_info (eklass);
 
@@ -6639,7 +6818,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       int stind_op;
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest_ptr);
@@ -6650,8 +6830,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_I);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
@@ -6673,7 +6853,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                MonoClass *eklass;
                guint32 label1, label2, label3;
                int index_var, src, dest, esize;
-               MonoMarshalConv conv = (MonoMarshalConv)-1;
+               MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
                gboolean is_string = FALSE;
                
                g_assert (!t->byref);
@@ -6719,7 +6899,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_byte (mb, CEE_ADD);
                }
                mono_mb_emit_byte (mb, CEE_MUL);
-               mono_mb_emit_icall (mb, mono_marshal_alloc);
+               mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
                mono_mb_emit_stloc (mb, dest);
                mono_mb_emit_ldloc (mb, dest);
                mono_mb_emit_stloc (mb, 3);
@@ -6736,7 +6916,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       int stind_op;
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest);
@@ -6747,8 +6928,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_I);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
@@ -7100,10 +7281,12 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
-#ifndef DISABLE_COM
+#if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
                if (spec && spec->native == MONO_NATIVE_STRUCT)
                        return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+#endif
 
+#if !defined(DISABLE_COM)
                if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
                        spec->native == MONO_NATIVE_IDISPATCH ||
                        spec->native == MONO_NATIVE_INTERFACE))
@@ -7114,8 +7297,8 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                        return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
 #endif
 
-               if (mono_defaults.safehandle_class != NULL && t->data.klass &&
-                   mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
+               if (mono_class_try_get_safehandle_class () != NULL && t->data.klass &&
+                   mono_class_is_subclass_of (t->data.klass,  mono_class_try_get_safehandle_class (), FALSE))
                        return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
                
                return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
@@ -7174,7 +7357,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
        MonoClass *klass;
        int i, argnum, *tmp_locals;
        int type, param_shift = 0;
-       static MonoMethodSignature *get_last_error_sig = NULL;
        int coop_gc_stack_dummy, coop_gc_var;
 
        memset (&m, 0, sizeof (m));
@@ -7208,7 +7390,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
        mono_mb_emit_icon (mb, 0);
        mono_mb_emit_stloc (mb, 2);
 
-       if (!MONO_TYPE_IS_VOID(sig->ret)) {
+       if (!MONO_TYPE_IS_VOID (sig->ret)) {
                /* allocate local 3 to store the return value */
                mono_mb_add_local (mb, sig->ret);
        }
@@ -7220,10 +7402,25 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        }
 
-       if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
-               /* Return type custom marshaling */
-               /*
-                * Since we can't determine the return type of the unmanaged function,
+       /*
+        * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
+        *
+        * ret = method (...);
+        *
+        * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
+        *
+        * <interrupt check>
+        *
+        * return ret;
+        */
+
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+       if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
+               /* Return type custom marshaling */
+               /*
+                * Since we can't determine the return type of the unmanaged function,
                 * we assume it returns a pointer, and pass that pointer to
                 * MarshalNativeToManaged.
                 */
@@ -7238,6 +7435,21 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
        }
 
+       // In coop mode need to register blocking state during native call
+       if (mono_threads_is_coop_enabled ()) {
+               // Perform an extra, early lookup of the function address, so any exceptions
+               // potentially resulting from the lookup occur before entering blocking mode.
+               if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
+                       mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
+               }
+
+               mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
+               mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
+               mono_mb_emit_stloc (mb, coop_gc_var);
+       }
+
        /* push all arguments */
 
        if (sig->hasthis)
@@ -7247,12 +7459,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
        }                       
 
-       if (mono_threads_is_coop_enabled ()) {
-               mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
-               mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
-               mono_mb_emit_stloc (mb, coop_gc_var);
-       }
-
        /* call the native method */
        if (func_param) {
                mono_mb_emit_byte (mb, CEE_LDARG_0);
@@ -7265,8 +7471,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
 #else
                g_assert_not_reached ();
 #endif
-       }
-       else {
+       } else {
                if (aot) {
                        /* Reuse the ICALL_ADDR opcode for pinvokes too */
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -7279,28 +7484,47 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
 
        /* Set LastError if needed */
        if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
-               if (!get_last_error_sig) {
-                       get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-                       get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
-                       get_last_error_sig->pinvoke = 1;
-               }
-
 #ifdef TARGET_WIN32
-               /* 
-                * Have to call GetLastError () early and without a wrapper, since various runtime components could
-                * clobber its value.
-                */
-               mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
-               mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+               if (!aot) {
+                       static MonoMethodSignature *get_last_error_sig = NULL;
+                       if (!get_last_error_sig) {
+                               get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+                               get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
+                               get_last_error_sig->pinvoke = 1;
+                       }
+
+                       /*
+                        * Have to call GetLastError () early and without a wrapper, since various runtime components could
+                        * clobber its value.
+                        */
+                       mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
+                       mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+               } else {
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_GET_LAST_ERROR);
+                       mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
+               }
 #else
                mono_mb_emit_icall (mb, mono_marshal_set_last_error);
 #endif
-       }               
+       }
+
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               MonoClass *klass = mono_class_from_mono_type (sig->ret);
+               mono_class_init (klass);
+               if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
+                       /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       mono_mb_emit_stloc (mb, m.vtaddr_var);
+               }
+       }
 
+       /* Unblock before converting the result, since that can involve calls into the runtime */
        if (mono_threads_is_coop_enabled ()) {
                mono_mb_emit_ldloc (mb, coop_gc_var);
                mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
-               mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+               mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
        }
 
        /* convert the result */
@@ -7311,7 +7535,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                if (spec && spec->native == MONO_NATIVE_CUSTOM) {
                        emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
                } else {
-
                handle_enum:
                        switch (type) {
                        case MONO_TYPE_VOID:
@@ -7405,7 +7628,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
  *
  * generates IL code for the pinvoke wrapper (the generated method
  * calls the unmanaged code in piinfo->addr)
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
@@ -7552,11 +7774,54 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
                else
                        csig = mono_metadata_signature_dup_full (method->klass->image, sig);
 
+               //printf ("%s\n", mono_method_full_name (method, 1));
+
                /* hack - string constructors returns a value */
                if (method->string_ctor)
                        csig->ret = &mono_defaults.string_class->byval_arg;
 
 #ifndef DISABLE_JIT
+               // FIXME:
+               MonoClass *handle_stack_mark_class;
+               MonoClass *error_class;
+               int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
+               MonoMethodSignature *call_sig = csig;
+               gboolean uses_handles = FALSE;
+               (void) mono_lookup_internal_call_full (method, &uses_handles);
+
+
+               /* If it uses handles and MonoError, it had better check exceptions */
+               g_assert (!uses_handles || check_exceptions);
+
+               if (uses_handles) {
+                       MonoMethodSignature *ret;
+
+                       /* Add a MonoError argument */
+                       // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
+                       ret = mono_metadata_signature_alloc (method->klass->image, csig->param_count + 1);
+
+                       ret->param_count = csig->param_count + 1;
+                       ret->ret = csig->ret;
+                       for (int i = 0; i < csig->param_count; ++i) {
+                               // FIXME: TODO implement handle wrapping for out and inout params.
+                               g_assert (!mono_signature_param_is_out (csig, i));
+                               ret->params [i] = csig->params [i];
+                       }
+                       ret->params [csig->param_count] = &mono_get_intptr_class ()->byval_arg;
+                       call_sig = ret;
+               }
+
+               if (uses_handles) {
+                       handle_stack_mark_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
+                       error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
+
+                       thread_info_var = mono_mb_add_local (mb, &mono_get_intptr_class ()->byval_arg);
+                       stack_mark_var = mono_mb_add_local (mb, &handle_stack_mark_class->byval_arg);
+                       error_var = mono_mb_add_local (mb, &error_class->byval_arg);
+
+                       // FIXME: Change csig so it passes a handle not an objref
+               }
+
                if (sig->hasthis) {
                        int pos;
 
@@ -7568,21 +7833,58 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions,
                        pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
                        mono_mb_emit_exception (mb, "NullReferenceException", NULL);
                        mono_mb_patch_branch (mb, pos);
-
-                       mono_mb_emit_byte (mb, CEE_LDARG_0);
                }
 
-               for (i = 0; i < sig->param_count; i++)
-                       mono_mb_emit_ldarg (mb, i + sig->hasthis);
+               if (uses_handles) {
+                       mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+                       mono_mb_emit_ldloc_addr (mb, error_var);
+                       mono_mb_emit_icall (mb, mono_icall_start);
+                       mono_mb_emit_stloc (mb, thread_info_var);
+
+                       if (sig->hasthis) {
+                               mono_mb_emit_byte (mb, CEE_LDARG_0);
+                               mono_mb_emit_icall (mb, mono_handle_new);
+                       }
+                       for (i = 0; i < sig->param_count; i++) {
+                               mono_mb_emit_ldarg (mb, i + sig->hasthis);
+                               if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
+                                       mono_mb_emit_icall (mb, mono_handle_new);
+                               }
+                       }
+                       mono_mb_emit_ldloc_addr (mb, error_var);
+               } else {
+                       if (sig->hasthis)
+                               mono_mb_emit_byte (mb, CEE_LDARG_0);
+                       for (i = 0; i < sig->param_count; i++)
+                               mono_mb_emit_ldarg (mb, i + sig->hasthis);
+               }
 
                if (aot) {
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
-                       mono_mb_emit_calli (mb, csig);
+                       mono_mb_emit_calli (mb, call_sig);
                } else {
                        g_assert (piinfo->addr);
-                       mono_mb_emit_native_call (mb, csig, piinfo->addr);
+                       mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
                }
+
+               if (uses_handles) {
+                       if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
+                               // if (ret != NULL_HANDLE) {
+                               //   ret = MONO_HANDLE_RAW(ret)
+                               // }
+                               mono_mb_emit_byte (mb, CEE_DUP);
+                               int pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+                               mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
+                               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+                               mono_mb_patch_branch (mb, pos);
+                       }
+                       mono_mb_emit_ldloc (mb, thread_info_var);
+                       mono_mb_emit_ldloc_addr (mb, stack_mark_var);
+                       mono_mb_emit_ldloc_addr (mb, error_var);
+                       mono_mb_emit_icall (mb, mono_icall_end);
+               }
+
                if (check_exceptions)
                        emit_thread_interrupt_checkpoint (mb);
                mono_mb_emit_byte (mb, CEE_RET);
@@ -7800,9 +8102,10 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
        }
 #else
        MonoMethodSignature *sig, *csig;
-       int i, *tmp_locals;
+       MonoExceptionClause *clauses, *clause_finally, *clause_catch;
+       int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
+       int leave_try_pos, leave_catch_pos, ex_m1_pos;
        gboolean closed = FALSE;
-       int coop_gc_var, coop_gc_dummy_local;
 
        sig = m->sig;
        csig = m->csig;
@@ -7829,31 +8132,71 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                mono_mb_add_local (mb, sig->ret);
        }
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* local 4, the local to be used when calling the reset_blocking funcs */
-               /* tons of code hardcode 3 to be the return var */
-               coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-               /* local 5, the local used to get a stack address for suspend funcs */
-               coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       }
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
-       mono_mb_emit_icon (mb, 0);
-       mono_mb_emit_stloc (mb, 2);
+       ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
+       e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
+
+       attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
        /*
-        * Might need to attach the thread to the JIT or change the
-        * domain for the callback.
+        * guint32 ex = -1;
+        * try {
+        *   // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
+        *   mono_threads_attach_coop ();
+        *
+        *   <interrupt check>
+        *
+        *   ret = method (...);
+        * } catch (Exception e) {
+        *   ex = mono_gchandle_new (e, false);
+        * } finally {
+        *   // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
+        *   mono_threads_detach_coop ();
+        *
+        *   if (ex != -1)
+        *     mono_marshal_ftnptr_eh_callback (ex);
+        * }
+        *
+        * return ret;
         */
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* XXX can we merge reset_blocking_start with JIT_ATTACH above and save one call? */
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
-               mono_mb_emit_stloc (mb, coop_gc_var);
+       clauses = g_new0 (MonoExceptionClause, 2);
+
+       clause_catch = &clauses [0];
+       clause_catch->flags = MONO_EXCEPTION_CLAUSE_NONE;
+       clause_catch->data.catch_class = mono_defaults.exception_class;
+
+       clause_finally = &clauses [1];
+       clause_finally->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
+
+       mono_mb_emit_icon (mb, 0);
+       mono_mb_emit_stloc (mb, 2);
+
+       mono_mb_emit_icon (mb, -1);
+       mono_mb_emit_byte (mb, CEE_CONV_U4);
+       mono_mb_emit_stloc (mb, ex_local);
+
+       /* try { */
+       clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
+
+       if (!mono_threads_is_coop_enabled ()) {
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
+       } else {
+               /* mono_threads_attach_coop (); */
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
+               mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+               mono_mb_emit_icall (mb, mono_threads_attach_coop);
+               mono_mb_emit_stloc (mb, attach_cookie_local);
        }
 
+       /* <interrupt check> */
+       emit_thread_interrupt_checkpoint (mb);
+
        /* we first do all conversions */
        tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
        for (i = 0; i < sig->param_count; i ++) {
@@ -7876,8 +8219,6 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                }
        }
 
-       emit_thread_interrupt_checkpoint (mb);
-
        if (sig->hasthis) {
                if (target_handle) {
                        mono_mb_emit_icon (mb, (gint32)target_handle);
@@ -7904,8 +8245,20 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                        mono_mb_emit_ldarg (mb, i);
        }
 
+       /* ret = method (...) */
        mono_mb_emit_managed_call (mb, method, NULL);
 
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               MonoClass *klass = mono_class_from_mono_type (sig->ret);
+               mono_class_init (klass);
+               if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
+                       /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       mono_mb_emit_stloc (mb, m->vtaddr_var);
+               }
+       }
+
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
                emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
        } else if (!sig->ret->byref) { 
@@ -7982,16 +8335,63 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                }
        }
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* XXX merge reset_blocking_end with detach */
-               mono_mb_emit_ldloc (mb, coop_gc_var);
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
+       leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+       /* } [endtry] */
+
+       /* catch (Exception e) { */
+       clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
+       clause_catch->handler_offset = mono_mb_get_label (mb);
+
+       mono_mb_emit_stloc (mb, e_local);
+
+       /* ex = mono_gchandle_new (e, false); */
+       mono_mb_emit_ldloc (mb, e_local);
+       mono_mb_emit_icon (mb, 0);
+       mono_mb_emit_icall (mb, mono_gchandle_new);
+       mono_mb_emit_stloc (mb, ex_local);
+
+       leave_catch_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+       /* } [endcatch] */
+       clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
+
+       /* finally { */
+       clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
+       clause_finally->handler_offset = mono_mb_get_label (mb);
+
+       if (!mono_threads_is_coop_enabled ()) {
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+       } else {
+               /* mono_threads_detach_coop (); */
+               mono_mb_emit_ldloc (mb, attach_cookie_local);
+               mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
+               mono_mb_emit_icall (mb, mono_threads_detach_coop);
        }
 
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
+       /* if (ex != -1) */
+       mono_mb_emit_ldloc (mb, ex_local);
+       mono_mb_emit_icon (mb, -1);
+       mono_mb_emit_byte (mb, CEE_CONV_U4);
+       ex_m1_pos = mono_mb_emit_branch (mb, CEE_BEQ);
+
+       /* mono_marshal_ftnptr_eh_callback (ex) */
+       mono_mb_emit_ldloc (mb, ex_local);
+       mono_mb_emit_icall (mb, mono_marshal_ftnptr_eh_callback);
 
+       /* [ex == -1] */
+       mono_mb_patch_branch (mb, ex_m1_pos);
+
+       mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+       /* } [endfinally] */
+       clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
+
+       mono_mb_patch_branch (mb, leave_try_pos);
+       mono_mb_patch_branch (mb, leave_catch_pos);
+
+       /* return ret; */
        if (m->retobj_var) {
                mono_mb_emit_ldloc (mb, m->retobj_var);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -8003,6 +8403,8 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                mono_mb_emit_byte (mb, CEE_RET);
        }
 
+       mono_mb_set_clauses (mb, 2, clauses);
+
        if (closed)
                g_free (sig);
 #endif
@@ -8052,7 +8454,7 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *
 MonoMethod *
 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
 {
-       static MonoClass *UnmanagedFunctionPointerAttribute;
+       MonoError error;
        MonoMethodSignature *sig, *csig, *invoke_sig;
        MonoMethodBuilder *mb;
        MonoMethod *res, *invoke;
@@ -8063,7 +8465,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        EmitMarshalContext m;
 
        g_assert (method != NULL);
-       g_assert (!mono_method_signature (method)->pinvoke);
+       g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
 
        /* 
         * FIXME: Should cache the method+delegate type pair, since the same method
@@ -8107,12 +8509,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
 
        mono_marshal_set_callconv_from_modopt (invoke, csig);
 
-       /* Handle the UnmanagedFunctionPointerAttribute */
-       if (!UnmanagedFunctionPointerAttribute)
-               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
        /* The attribute is only available in Net 2.0 */
-       if (UnmanagedFunctionPointerAttribute) {
+       if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                MonoCustomAttrInfo *cinfo;
                MonoCustomAttrEntry *attr;
 
@@ -8121,12 +8519,13 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                 * contents of the attribute without constructing it, as that might not be
                 * possible when running in cross-compiling mode.
                 */
-               cinfo = mono_custom_attrs_from_class (delegate_klass);
+               cinfo = mono_custom_attrs_from_class_checked (delegate_klass, &error);
+               mono_error_assert_ok (&error);
                attr = NULL;
                if (cinfo) {
                        for (i = 0; i < cinfo->num_attrs; ++i) {
                                MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
-                               if (mono_class_has_parent (ctor_class, UnmanagedFunctionPointerAttribute)) {
+                               if (mono_class_has_parent (ctor_class, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
                                        attr = &cinfo->attrs [i];
                                        break;
                                }
@@ -8216,6 +8615,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
 gpointer
 mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
 {
+       MonoError error;
        MonoMethod *method;
        MonoMethodSignature *sig;
        MonoMethodBuilder *mb;
@@ -8223,7 +8623,9 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
 
        g_assert (token);
 
-       method = mono_get_method (image, token, NULL);
+       method = mono_get_method_checked (image, token, NULL, NULL, &error);
+       if (!method)
+               g_error ("Could not load vtfixup token 0x%x due to %s", token, mono_error_get_message (&error));
        g_assert (method);
 
        if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
@@ -8267,7 +8669,9 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
                                mono_metadata_free_marshal_spec (mspecs [i]);
                g_free (mspecs);
 
-               return mono_compile_method (method);
+               gpointer compiled_ptr = mono_compile_method_checked (method, &error);
+               mono_error_assert_ok (&error);
+               return compiled_ptr;
        }
 
        sig = mono_method_signature (method);
@@ -8290,7 +8694,9 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
        method = mono_mb_create (mb, sig, param_count, NULL);
        mono_mb_free (mb);
 
-       return mono_compile_method (method);
+       gpointer compiled_ptr = mono_compile_method_checked (method, &error);
+       mono_error_assert_ok (&error);
+       return compiled_ptr;
 }
 
 #ifndef DISABLE_JIT
@@ -8360,7 +8766,6 @@ generate_check_cache (int obj_arg_position, int class_arg_position, int cache_ar
 
 /*
  * This does the equivalent of mono_object_castclass_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_castclass_with_cache (void)
@@ -8421,10 +8826,14 @@ mono_marshal_get_castclass_with_cache (void)
        return cached;
 }
 
+/* this is an icall */
 static MonoObject *
 mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
 {
-       MonoObject *isinst = mono_object_isinst (obj, klass);
+       MonoError error;
+       MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
 
 #ifndef DISABLE_REMOTING
        if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
@@ -8442,7 +8851,6 @@ mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *ca
 
 /*
  * This does the equivalent of mono_object_isinst_with_cache.
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_isinst_with_cache (void)
@@ -8486,7 +8894,7 @@ mono_marshal_get_isinst_with_cache (void)
 
        // return obj
        mono_mb_patch_branch (mb, positive_cache_hit_pos);
-       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldarg (mb, obj_arg_position);
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
@@ -8619,7 +9027,6 @@ mono_marshal_get_isinst (MonoClass *klass)
  * an instance of the given type, icluding the case where the object is a proxy.
  * The generated function has the following signature:
  * MonoObject* __castclass_wrapper_ (MonoObject *obj)
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_castclass (MonoClass *klass)
@@ -8702,7 +9109,6 @@ mono_marshal_get_castclass (MonoClass *klass)
  * @klass:
  *
  * generates IL code for StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_struct_to_ptr (MonoClass *klass)
@@ -8762,7 +9168,12 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
        res = mono_mb_create (mb, mono_signature_no_pinvoke (stoptr), 0, info);
        mono_mb_free (mb);
 
-       klass->marshal_info->str_to_ptr = res;
+       mono_marshal_lock ();
+       if (!klass->marshal_info->str_to_ptr)
+               klass->marshal_info->str_to_ptr = res;
+       else
+               res = klass->marshal_info->str_to_ptr;
+       mono_marshal_unlock ();
        return res;
 }
 
@@ -8771,7 +9182,6 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
  * @klass:
  *
  * generates IL code for PtrToStructure (IntPtr src, object structure)
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_ptr_to_struct (MonoClass *klass)
@@ -8836,7 +9246,12 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
        res = mono_mb_create (mb, ptostr, 0, info);
        mono_mb_free (mb);
 
-       klass->marshal_info->ptr_to_str = res;
+       mono_marshal_lock ();
+       if (!klass->marshal_info->ptr_to_str)
+               klass->marshal_info->ptr_to_str = res;
+       else
+               res = klass->marshal_info->ptr_to_str;
+       mono_marshal_unlock ();
        return res;
 }
 
@@ -8845,7 +9260,6 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
  * This is used to avoid infinite recursion since it is hard to determine where to
  * replace a method with its synchronized wrapper, and where not.
  * The runtime should execute METHOD instead of the wrapper.
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod *
 mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
@@ -8862,7 +9276,7 @@ mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
                method = ((MonoMethodInflated*)method)->declaring;
                container = mono_method_get_generic_container (method);
                if (!container)
-                       container = method->klass->generic_container;
+                       container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
        }
 
@@ -8916,7 +9330,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
                method = ((MonoMethodInflated*)method)->declaring;
                container = mono_method_get_generic_container (method);
                if (!container)
-                       container = method->klass->generic_container;
+                       container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
                g_assert (container);
        }
 
@@ -8950,7 +9364,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
 #endif
 
        if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
-               mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+               /* FIXME Is this really the best way to signal an error here?  Isn't this called much later after class setup? -AK */
+               mono_class_set_type_load_failure (method->klass, "");
 #ifndef DISABLE_JIT
                /* This will throw the type load exception when the wrapper is compiled */
                mono_mb_emit_byte (mb, CEE_LDNULL);
@@ -8983,7 +9398,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
        if (!enter_method) {
                MonoMethodDesc *desc;
 
-               desc = mono_method_desc_new ("Monitor:enter_with_atomic_var(object,bool&)", FALSE);
+               desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
                enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
                g_assert (enter_method);
                mono_method_desc_free (desc);
@@ -9142,7 +9557,7 @@ is_monomorphic_array (MonoClass *klass)
                return FALSE;
 
        element_class = klass->element_class;
-       return (element_class->flags & TYPE_ATTRIBUTE_SEALED) || element_class->valuetype;
+       return mono_class_is_sealed (element_class) || element_class->valuetype;
 }
 
 static int
@@ -9162,7 +9577,7 @@ get_virtual_stelemref_kind (MonoClass *element_class)
        /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
        if (mono_class_is_marshalbyref (element_class) || element_class->rank || mono_class_has_variant_generic_params (element_class))
                return STELEMREF_COMPLEX;
-       if (element_class->flags & TYPE_ATTRIBUTE_SEALED)
+       if (mono_class_is_sealed (element_class))
                return STELEMREF_SEALED_CLASS;
        return STELEMREF_CLASS;
 }
@@ -9213,8 +9628,6 @@ record_slot_vstore (MonoObject *array, size_t index, MonoObject *value)
 #endif
 
 /*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- *
  * TODO:
  *     - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
  *     - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
@@ -9230,7 +9643,7 @@ get_virtual_stelemref_wrapper (int kind)
        MonoMethod *res;
        char *name;
        const char *param_names [16];
-       guint32 b1, b2, b3;
+       guint32 b1, b2, b3, b4;
        int aklass, vklass, vtable, uiid;
        int array_slot_addr;
        WrapperInfo *info;
@@ -9317,7 +9730,7 @@ get_virtual_stelemref_wrapper (int kind)
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
-               mono_mb_emit_icall (mb, mono_object_isinst);
+               mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                /* do_store: */
@@ -9431,7 +9844,7 @@ get_virtual_stelemref_wrapper (int kind)
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
-               mono_mb_emit_icall (mb, mono_object_isinst);
+               mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                /* if (vklass->idepth < aklass->idepth) goto failue */
@@ -9443,7 +9856,7 @@ get_virtual_stelemref_wrapper (int kind)
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
                mono_mb_emit_byte (mb, CEE_LDIND_U2);
 
-               b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
+               b3 = mono_mb_emit_branch (mb, CEE_BLT_UN);
 
                /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
                mono_mb_emit_ldloc (mb, vklass);
@@ -9461,7 +9874,7 @@ get_virtual_stelemref_wrapper (int kind)
                mono_mb_emit_byte (mb, CEE_LDIND_I);
 
                mono_mb_emit_ldloc (mb, aklass);
-               b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
+               b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
 
                /* do_store: */
                mono_mb_patch_branch (mb, b1);
@@ -9473,6 +9886,7 @@ get_virtual_stelemref_wrapper (int kind)
                /* do_exception: */
                mono_mb_patch_branch (mb, b2);
                mono_mb_patch_branch (mb, b3);
+               mono_mb_patch_branch (mb, b4);
 
                mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
                break;
@@ -9623,9 +10037,6 @@ mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers)
        return res;
 }
 
-/*
- * The wrapper info for the wrapper is a WrapperInfo structure.
- */
 MonoMethod*
 mono_marshal_get_stelemref (void)
 {
@@ -9757,7 +10168,7 @@ mono_marshal_get_stelemref (void)
        
        mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_ldloc (mb, aklass);
-       mono_mb_emit_icall (mb, mono_object_isinst);
+       mono_mb_emit_icall (mb, mono_object_isinst_icall);
        
        b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
        mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
@@ -9776,8 +10187,6 @@ mono_marshal_get_stelemref (void)
  * mono_marshal_get_gsharedvt_in_wrapper:
  *
  *   This wrapper handles calls from normal code to gsharedvt code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod*
 mono_marshal_get_gsharedvt_in_wrapper (void)
@@ -9812,8 +10221,6 @@ mono_marshal_get_gsharedvt_in_wrapper (void)
  * mono_marshal_get_gsharedvt_out_wrapper:
  *
  *   This wrapper handles calls from gsharedvt code to normal code.
- *
- * The wrapper info for the wrapper is a WrapperInfo structure.
  */
 MonoMethod*
 mono_marshal_get_gsharedvt_out_wrapper (void)
@@ -10112,29 +10519,59 @@ mono_marshal_get_array_accessor_wrapper (MonoMethod *method)
        return res;     
 }
 
+#ifndef HOST_WIN32
+static inline void*
+mono_marshal_alloc_co_task_mem (size_t size)
+{
+       if ((gulong)size == 0)
+               /* This returns a valid pointer for size 0 on MS.NET */
+               size = 4;
+
+       return g_try_malloc ((gulong)size);
+}
+#endif
+
 void*
-mono_marshal_alloc (gulong size)
+mono_marshal_alloc (gulong size, MonoError *error)
 {
        gpointer res;
 
-#ifdef HOST_WIN32
-       res = CoTaskMemAlloc (size);
-#else
-       res = g_try_malloc ((gulong)size);
+       mono_error_init (error);
+
+       res = mono_marshal_alloc_co_task_mem (size);
        if (!res)
-               mono_gc_out_of_memory ((gulong)size);
-#endif
+               mono_error_set_out_of_memory (error, "Could not allocate %lu bytes", size);
+
        return res;
 }
 
-void
-mono_marshal_free (gpointer ptr)
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
+static void*
+ves_icall_marshal_alloc (gulong size)
+{
+       MonoError error;
+       void *ret = mono_marshal_alloc (size, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+
+       return ret;
+}
+
+#ifndef HOST_WIN32
+static inline void
+mono_marshal_free_co_task_mem (void *ptr)
 {
-#ifdef HOST_WIN32
-       CoTaskMemFree (ptr);
-#else
        g_free (ptr);
+       return;
+}
 #endif
+
+void
+mono_marshal_free (gpointer ptr)
+{
+       mono_marshal_free_co_task_mem (ptr);
 }
 
 void
@@ -10156,13 +10593,19 @@ mono_marshal_string_to_utf16 (MonoString *s)
        return s ? mono_string_chars (s) : NULL;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static void *
 mono_marshal_string_to_utf16_copy (MonoString *s)
 {
        if (s == NULL) {
                return NULL;
        } else {
-               gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2);
+               MonoError error;
+               gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
                res [mono_string_length (s)] = 0;
                return res;
@@ -10274,17 +10717,22 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
 {
-       if (ptr == NULL) {
-               mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
-               return NULL;
-       } else {
-               return mono_string_new_len (mono_domain_get (), ptr, len);
-       }
+       MonoError error;
+       MonoString *result = NULL;
+       mono_error_init (&error);
+       if (ptr == NULL)
+               mono_error_set_argument_null (&error, "ptr", "");
+       else
+               result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
        int len = 0;
        guint16 *t = ptr;
@@ -10295,20 +10743,33 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
        while (*t++)
                len++;
 
-       return mono_string_new_utf16 (domain, ptr, len);
+       res = mono_string_new_utf16_checked (domain, ptr, len, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
 
+       mono_error_init (&error);
+
        if (ptr == NULL) {
-               mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
-               return NULL;
+               res = NULL;
+               mono_error_set_argument_null (&error, "ptr", "");
        } else {
-               return mono_string_new_utf16 (domain, ptr, len);
+               res = mono_string_new_utf16_checked (domain, ptr, len, &error);
        }
+
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
+       return res;
 }
 
 guint32 
@@ -10333,7 +10794,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty
                return 0;
        }
 
-       layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
+       layout = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK);
 
        if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
                return sizeof (gpointer);
@@ -10354,6 +10815,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty
 void
 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
 {
+       MonoError error;
        MonoMethod *method;
        gpointer pa [3];
 
@@ -10366,27 +10828,32 @@ ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj
        pa [1] = &dst;
        pa [2] = &delete_old;
 
-       mono_runtime_invoke (method, NULL, pa, NULL);
+       mono_runtime_invoke_checked (method, NULL, pa, &error);
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
 }
 
 static void
-ptr_to_structure (gpointer src, MonoObject *dst)
+ptr_to_structure (gpointer src, MonoObject *dst, MonoError *error)
 {
        MonoMethod *method;
        gpointer pa [2];
 
+       mono_error_init (error);
+
        method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
 
        pa [0] = &src;
        pa [1] = dst;
 
-       mono_runtime_invoke (method, NULL, pa, NULL);
+       mono_runtime_invoke_checked (method, NULL, pa, error);
 }
 
 void
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
 {
        MonoType *t;
+       MonoError error;
 
        MONO_CHECK_ARG_NULL (src,);
        MONO_CHECK_ARG_NULL (dst,);
@@ -10405,12 +10872,15 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, M
                return;
        }
 
-       ptr_to_structure (src, dst);
+       ptr_to_structure (src, dst, &error);
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
 }
 
 MonoObject *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
 {
+       MonoError error;
        MonoClass *klass;
        MonoDomain *domain = mono_domain_get (); 
        MonoObject *res;
@@ -10425,9 +10895,17 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s
                return NULL;
        }
 
-       res = mono_object_new (domain, klass);
+       res = mono_object_new_checked (domain, klass, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
-       ptr_to_structure (src, res);
+       ptr_to_structure (src, res, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
        return res;
 }
@@ -10435,6 +10913,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s
 int
 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
 {
+       MonoError error;
        MonoMarshalType *info;
        MonoClass *klass;
        char *fname;
@@ -10443,7 +10922,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t
        MONO_CHECK_ARG_NULL (type, 0);
        MONO_CHECK_ARG_NULL (field_name, 0);
 
-       fname = mono_string_to_utf8 (field_name);
+       fname = mono_string_to_utf8_checked (field_name, &error);
+       if (mono_error_set_pending_exception (&error))
+               return 0;
        klass = mono_class_from_mono_type (type->type);
        if (!mono_class_init (klass)) {
                mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
@@ -10489,25 +10970,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t
        return info->fields [match_index].offset;
 }
 
+#ifndef HOST_WIN32
 gpointer
 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
 {
-#ifdef HOST_WIN32
-       char* tres, *ret;
-       size_t len;
-       tres = mono_string_to_utf8 (string);
-       if (!tres)
-               return tres;
-
-       len = strlen (tres) + 1;
-       ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len);
-       memcpy (ret, tres, len);
-       g_free (tres);
+       MonoError error;
+       char *ret = mono_string_to_utf8_checked (string, &error);
+       mono_error_set_pending_exception (&error);
        return ret;
-
-#else
-       return mono_string_to_utf8 (string);
-#endif
 }
 
 gpointer
@@ -10516,17 +10986,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString
        if (string == NULL)
                return NULL;
        else {
-#ifdef TARGET_WIN32
-               gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal 
-                       ((mono_string_length (string) + 1) * 2);
-#else
                gunichar2 *res = (gunichar2 *)g_malloc ((mono_string_length (string) + 1) * 2);
-#endif
+
                memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
                res [mono_string_length (string)] = 0;
                return res;
        }
 }
+#endif /* !HOST_WIN32 */
 
 static void
 mono_struct_delete_old (MonoClass *klass, char *ptr)
@@ -10569,6 +11036,7 @@ mono_struct_delete_old (MonoClass *klass, char *ptr)
                case MONO_MARSHAL_CONV_STR_BSTR:
                case MONO_MARSHAL_CONV_STR_ANSIBSTR:
                case MONO_MARSHAL_CONV_STR_TBSTR:
+               case MONO_MARSHAL_CONV_STR_UTF8STR:
                        mono_marshal_free (*(gpointer *)cpos);
                        break;
 
@@ -10595,6 +11063,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src,
        mono_struct_delete_old (klass, (char *)src);
 }
 
+#ifndef HOST_WIN32
+static inline void *
+mono_marshal_alloc_hglobal (size_t size)
+{
+       return g_try_malloc (size);
+}
+#endif
+
 void*
 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
 {
@@ -10605,17 +11081,24 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
                /* This returns a valid pointer for size 0 on MS.NET */
                s = 4;
 
-#ifdef HOST_WIN32
-       res = GlobalAlloc (GMEM_FIXED, s);
-#else
-       res = g_try_malloc (s);
-#endif
-       if (!res)
-               mono_gc_out_of_memory (s);
+       res = mono_marshal_alloc_hglobal (s);
+
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
 
        return res;
 }
 
+#ifndef HOST_WIN32
+static inline gpointer
+mono_marshal_realloc_hglobal (gpointer ptr, size_t size)
+{
+       return g_try_realloc (ptr, size);
+}
+#endif
+
 gpointer
 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, gpointer size)
 {
@@ -10623,72 +11106,83 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, g
        size_t s = (size_t)size;
 
        if (ptr == NULL) {
-               mono_gc_out_of_memory (s);
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
                return NULL;
        }
 
-#ifdef HOST_WIN32
-       res = GlobalReAlloc (ptr, s, GMEM_MOVEABLE);
-#else
-       res = g_try_realloc (ptr, s);
-#endif
-       if (!res)
-               mono_gc_out_of_memory (s);
+       res = mono_marshal_realloc_hglobal (ptr, s);
+
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
 
        return res;
 }
 
-void
-ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
+#ifndef HOST_WIN32
+static inline void
+mono_marshal_free_hglobal (gpointer ptr)
 {
-#ifdef HOST_WIN32
-       GlobalFree (ptr);
-#else
        g_free (ptr);
+       return;
+}
 #endif
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
+{
+       mono_marshal_free_hglobal (ptr);
 }
 
 void*
 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
 {
-       void *res;
+       void *res = mono_marshal_alloc_co_task_mem (size);
 
-#ifdef HOST_WIN32
-       res = CoTaskMemAlloc (size);
-#else
-       if ((gulong)size == 0)
-               /* This returns a valid pointer for size 0 on MS.NET */
-               size = 4;
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
+       return res;
+}
 
-       res = g_try_malloc ((gulong)size);
-#endif
-       if (!res)
-               mono_gc_out_of_memory ((gulong)size);
+void*
+ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size)
+{
+       void *res = mono_marshal_alloc_co_task_mem (size);
+
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
        return res;
 }
 
 void
 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
 {
-#ifdef HOST_WIN32
-       CoTaskMemFree (ptr);
-#else
-       g_free (ptr);
-#endif
+       mono_marshal_free_co_task_mem (ptr);
+       return;
+}
+
+#ifndef HOST_WIN32
+static inline gpointer
+mono_marshal_realloc_co_task_mem (gpointer ptr, size_t size)
+{
+       return g_try_realloc (ptr, (gulong)size);
 }
+#endif
 
 gpointer
 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
 {
-       void *res;
+       void *res = mono_marshal_realloc_co_task_mem (ptr, size);
 
-#ifdef HOST_WIN32
-       res = CoTaskMemRealloc (ptr, size);
-#else
-       res = g_try_realloc (ptr, (gulong)size);
-#endif
-       if (!res)
-               mono_gc_out_of_memory ((gulong)size);
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
        return res;
 }
 
@@ -10710,6 +11204,12 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerIn
        return mono_ftnptr_to_delegate (klass, ftn);
 }
 
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate)
+{
+       return mono_delegate_to_ftnptr (delegate);
+}
+
 /**
  * mono_marshal_is_loading_type_info:
  *
@@ -10773,7 +11273,7 @@ mono_marshal_load_type_info (MonoClass* klass)
                count++;
        }
 
-       layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+       layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
 
        /* The mempool is protected by the loader lock */
        info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
@@ -10837,6 +11337,9 @@ mono_marshal_load_type_info (MonoClass* klass)
                j++;
        }
 
+       if (klass->byval_arg.type == MONO_TYPE_PTR)
+               info->native_size = sizeof (gpointer);
+
        if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
                info->native_size = MAX (native_size, info->native_size);
                /*
@@ -10876,6 +11379,7 @@ mono_marshal_load_type_info (MonoClass* klass)
                /*We do double-checking locking on marshal_info */
                mono_memory_barrier ();
                klass->marshal_info = info;
+               ++class_marshal_info_count;
        }
        mono_marshal_unlock ();
 
@@ -11035,6 +11539,7 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
        case MONO_NATIVE_BSTR:
        case MONO_NATIVE_ANSIBSTR:
        case MONO_NATIVE_TBSTR:
+       case MONO_NATIVE_UTF8STR:
        case MONO_NATIVE_LPARRAY:
        case MONO_NATIVE_SAFEARRAY:
        case MONO_NATIVE_IUNKNOWN:
@@ -11086,9 +11591,11 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
        return 0;
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 gpointer
 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
 {
+       MonoError error;
        MonoType *t;
        MonoClass *klass;
 
@@ -11116,10 +11623,10 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
                switch (string_encoding) {
                case MONO_NATIVE_LPWSTR:
                        return mono_marshal_string_to_utf16_copy ((MonoString*)o);
-                       break;
                case MONO_NATIVE_LPSTR:
-                       return mono_string_to_lpstr ((MonoString*)o);
-                       break;
+               case MONO_NATIVE_UTF8STR:
+                       // Same code path, because in Mono, we treated strings as Utf8
+                       return mono_string_to_utf8str ((MonoString*)o);
                default:
                        g_warning ("marshaling conversion %d not implemented", string_encoding);
                        g_assert_not_reached ();
@@ -11134,14 +11641,17 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
 
                klass = t->data.klass;
 
-               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+               if (mono_class_is_auto_layout (klass))
                        break;
 
-               if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                       klass->blittable || klass->enumtype))
+               if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
                        return mono_object_unbox (o);
 
-               res = mono_marshal_alloc (mono_class_native_size (klass, NULL));
+               res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
 
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
                        method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
@@ -11150,7 +11660,11 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
                        pa [1] = &res;
                        pa [2] = &delete_old;
 
-                       mono_runtime_invoke (method, NULL, pa, NULL);
+                       mono_runtime_invoke_checked (method, NULL, pa, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                }
 
                return res;
@@ -11158,13 +11672,15 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
        default:
                break;
        }
-       mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
+       mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
        return NULL;
 }
 
+/* This is a JIT icall, it sets the pending exception */
 void
 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
 {
+       MonoError error;
        MonoType *t;
        MonoClass *klass;
 
@@ -11177,6 +11693,7 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
                switch (string_encoding) {
                case MONO_NATIVE_LPWSTR:
                case MONO_NATIVE_LPSTR:
+               case MONO_NATIVE_UTF8STR:
                        mono_marshal_free (ptr);
                        break;
                default:
@@ -11188,8 +11705,7 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
        case MONO_TYPE_VALUETYPE: {
                klass = t->data.klass;
 
-               if (klass->valuetype && (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                                                                klass->blittable || klass->enumtype))
+               if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
                        break;
 
                if (param_attrs & PARAM_ATTRIBUTE_OUT) {
@@ -11199,7 +11715,11 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
                        pa [0] = &ptr;
                        pa [1] = o;
 
-                       mono_runtime_invoke (method, NULL, pa, NULL);
+                       mono_runtime_invoke_checked (method, NULL, pa, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return;
+                       }
                }
 
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
@@ -11323,10 +11843,12 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
        GHashTable *cache;
        MonoMethod *res;
        int i, param_count, sig_size, pos_leave;
-       int coop_gc_var, coop_gc_dummy_local;
 
        g_assert (method);
 
+       // FIXME: we need to store the exception into a MonoHandle
+       g_assert (!mono_threads_is_coop_enabled ());
+
        klass = method->klass;
        image = method->klass->image;
 
@@ -11376,26 +11898,11 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
        if (!MONO_TYPE_IS_VOID (sig->ret))
                mono_mb_add_local (mb, sig->ret);
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* local 4, the local to be used when calling the reset_blocking funcs */
-               /* tons of code hardcode 3 to be the return var */
-               coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-               /* local 5, the local used to get a stack address for suspend funcs */
-               coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       }
-
        /* clear exception arg */
        mono_mb_emit_ldarg (mb, param_count - 1);
        mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_STIND_REF);
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* FIXME this is technically wrong as the callback itself must be executed in gc unsafe context. */
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
-               mono_mb_emit_stloc (mb, coop_gc_var);
-       }
-
        /* try */
        clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
        clause->try_offset = mono_mb_get_label (mb);
@@ -11465,13 +11972,6 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
                        mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
        }
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* XXX merge reset_blocking_end with detach */
-               mono_mb_emit_ldloc (mb, coop_gc_var);
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
-       }
-
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
@@ -11511,3 +12011,57 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method)
        if (marshal_mutex_initialized)
                mono_marshal_unlock ();
 }
+
+static void
+mono_marshal_ftnptr_eh_callback (guint32 gchandle)
+{
+       g_assert (ftnptr_eh_callback);
+       ftnptr_eh_callback (gchandle);
+}
+
+static void
+ftnptr_eh_callback_default (guint32 gchandle)
+{
+       MonoException *exc;
+       gpointer stackdata;
+
+       mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata);
+
+       exc = (MonoException*) mono_gchandle_get_target (gchandle);
+
+       mono_gchandle_free (gchandle);
+
+       mono_raise_exception (exc);
+}
+
+/*
+ * mono_install_ftnptr_eh_callback:
+ *
+ *   Install a callback that should be called when there is a managed exception
+ *   in a native-to-managed wrapper. This is mainly used by iOS to convert a
+ *   managed exception to a native exception, to properly unwind the native
+ *   stack; this native exception will then be converted back to a managed
+ *   exception in their managed-to-native wrapper.
+ */
+void
+mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
+{
+       ftnptr_eh_callback = callback;
+}
+
+static MonoThreadInfo*
+mono_icall_start (HandleStackMark *stackmark, MonoError *error)
+{
+       MonoThreadInfo *info = mono_thread_info_current ();
+
+       mono_stack_mark_init (info, stackmark);
+       mono_error_init (error);
+       return info;
+}
+
+static void
+mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error)
+{
+       mono_stack_mark_pop (info, stackmark);
+       mono_error_set_pending_exception (error);
+}