Merge pull request #3349 from lambdageek/handle-icalls-in-jit
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Mon, 8 Aug 2016 20:39:13 +0000 (16:39 -0400)
committerGitHub <noreply@github.com>
Mon, 8 Aug 2016 20:39:13 +0000 (16:39 -0400)
[handles] Add coop handles in wrapper to icalls with HANDLES() declaration

mcs/class/corlib/Mono/RuntimeStructs.cs
mono/metadata/handle.h
mono/metadata/icall-def.h
mono/metadata/icall.c
mono/metadata/loader.h
mono/metadata/marshal.c

index ae4550632088f8f90a6bb408a699180857c097b5..6225954fb7011b60ec882c966f4199b7a9021874 100644 (file)
@@ -13,7 +13,10 @@ using System;
 using System.Runtime.InteropServices;
 
 namespace Mono {
-       internal class RuntimeStructs {
+       //
+       // Managed representations of mono runtime types
+       //
+       internal static class RuntimeStructs {
                // class-internals.h MonoRemoteClass
                [StructLayout(LayoutKind.Sequential)]
                internal unsafe struct RemoteClass {
@@ -43,6 +46,20 @@ namespace Mono {
                        internal IntPtr* data;
                        internal int len;
                }
+
+               // handle.h HandleStackMark
+               struct HandleStackMark {
+                       int size;
+                       IntPtr chunk;
+               }
+
+               // mono-error.h MonoError
+               struct MonoError {
+                       ushort error_code;
+                       ushort hidden_0;
+                       IntPtr hidden_1, hidden_2, hidden_3, hidden_4, hidden_5, hidden_6, hidden_7, hidden_8;
+                       IntPtr hidden_11, hidden_12, hidden_13, hidden_14, hidden_15, hidden_16, hidden_17, hidden_18;
+               }
        }
 
        //Maps to metadata-internals.h:: MonoAssemblyName
index b34036958110e02635f658282157dafad6848134..aa4c324372e7aa9c9f0a2e52e9f1394c8a7aff65 100644 (file)
@@ -187,6 +187,7 @@ void mono_handle_verify (MonoRawHandle handle);
 
 #define TYPED_HANDLE_PAYLOAD_NAME(TYPE) TYPE ## HandlePayload
 #define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
+
 /*
  * typedef struct {
  *   MonoObject *__obj;
@@ -194,7 +195,8 @@ void mono_handle_verify (MonoRawHandle handle);
  *
  * typedef MonoObjectHandlePayload* MonoObjectHandle;
  */
-#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE);
+#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE)
+#define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_STRUCT_OFFSET(TYPED_HANDLE_PAYLOAD_NAME (TYPE), __obj)
 
 #define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
 #define NULL_HANDLE mono_null_value_handle
@@ -244,9 +246,11 @@ This is why we evaluate index and value before any call to MONO_HANDLE_RAW or ot
 
 
 /* Baked typed handles we all want */
-TYPED_HANDLE_DECL (MonoString)
-TYPED_HANDLE_DECL (MonoArray)
-TYPED_HANDLE_DECL (MonoObject)
+TYPED_HANDLE_DECL (MonoString);
+TYPED_HANDLE_DECL (MonoArray);
+TYPED_HANDLE_DECL (MonoObject);
+
+#define NULL_HANDLE_STRING MONO_HANDLE_CAST(MonoString, NULL_HANDLE)
 
 /*
 This is the constant for a handle that points nowhere.
index d529af28d6c79fc479268620d7795659c05b27d8..82fc1734c29102d1e84d8d806a8e0c800e430b18 100644 (file)
  * you need to insert a method in the middle, don't bother renaming all the symbols.
  * Remember to change also the first_icall_id argument in the ICALL_TYPE 
  * declaration if you add a new icall at the beginning of a type's icall list.
+ *
+ *
+ * *** (Experimental) Cooperative GC support via Handles and MonoError ***
+ * An icall can use the coop GC handles infrastructure from handles.h to avoid some
+ * boilerplate when manipulating managed objects from runtime code and to use MonoError for
+ * threading exceptions out to managed callerrs:
+ *
+ * HANDLES(ICALL(icallid, methodname, cfuncptr))
+ *
+ * An icall with a HANDLES() declaration wrapped around it will have a generated wrapper
+ * that:
+ *   (1) Updates the coop handle stack on entry and exit
+ *   (2) Call the cfuncptr with a new signature:
+ *     (a) All managed object reference in arguments will be wrapped in a handle
+ *         (ie, MonoString* becomes MonoStringHandle)
+ *     (b) the same for the return value (MonoObject* return becomes MonoObjectHandle)
+ *     (c) An additional final argument is added of type MonoError*
+ *     example:    class object {
+ *                     [MethodImplOptions(InternalCall)]
+ *                     String some_icall (object[] x);
+ *                 }
+ *     should be implemented as:
+ *        MonoStringHandle some_icall (MonoObjectHandle this_handle, MonoArrayHandle x_handle, MonoError *error);
+ *   (3) The wrapper will automatically call mono_error_set_pending_exception (error) and raise the resulting exception.
+ * Note:  valuetypes use the same calling convention as normal.
+ * Limitations: "out" and "ref" arguments are not supported yet. 
  */
 
 #ifndef DISABLE_PROCESS_HANDLING
@@ -767,7 +793,7 @@ ICALL(RT_28, "IsTypeExportedToWindowsRuntime", ves_icall_System_RuntimeType_IsTy
 ICALL(RT_29, "IsWindowsRuntimeObjectType", ves_icall_System_RuntimeType_IsWindowsRuntimeObjectType)
 ICALL(RT_17, "MakeGenericType", ves_icall_RuntimeType_MakeGenericType)
 ICALL(RT_18, "MakePointerType", ves_icall_RuntimeType_MakePointerType)
-ICALL(RT_19, "getFullName", ves_icall_System_MonoType_getFullName)
+HANDLES(ICALL(RT_19, "getFullName", ves_icall_System_RuntimeType_getFullName))
 ICALL(RT_21, "get_DeclaringMethod", ves_icall_RuntimeType_get_DeclaringMethod)
 ICALL(RT_22, "get_DeclaringType", ves_icall_RuntimeType_get_DeclaringType)
 ICALL(RT_23, "get_Name", ves_icall_RuntimeType_get_Name)
index 2e3240354898d39ce5f3facc3d931fe501e45420..a9d68804dc1c604fd51231fae2e4a3381da873c9 100644 (file)
@@ -82,6 +82,7 @@
 #include <mono/metadata/runtime.h>
 #include <mono/metadata/file-mmap.h>
 #include <mono/metadata/seq-points-data.h>
+#include <mono/metadata/handle.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/monobitset.h>
 #include <mono/utils/mono-time.h>
@@ -110,6 +111,8 @@ extern MonoString* ves_icall_System_Environment_GetOSVersionString (void);
 
 ICALL_EXPORT MonoReflectionAssembly* ves_icall_System_Reflection_Assembly_GetCallingAssembly (void);
 
+TYPED_HANDLE_DECL (MonoReflectionType);
+
 /* Lazy class loading functions */
 static GENERATE_GET_CLASS_WITH_CACHE (system_version, System, Version)
 static GENERATE_GET_CLASS_WITH_CACHE (assembly_name, System.Reflection, AssemblyName)
@@ -5297,13 +5300,14 @@ ves_icall_System_Reflection_Assembly_GetCallingAssembly (void)
        return result;
 }
 
-ICALL_EXPORT MonoString *
-ves_icall_System_MonoType_getFullName (MonoReflectionType *object, gboolean full_name,
-                                      gboolean assembly_qualified)
+ICALL_EXPORT MonoStringHandle
+ves_icall_System_RuntimeType_getFullName (MonoReflectionTypeHandle object, gboolean full_name,
+                                                                                 gboolean assembly_qualified, MonoError *error)
 {
-       MonoDomain *domain = mono_object_domain (object); 
+       MonoDomain *domain = mono_object_domain (MONO_HANDLE_RAW (object));
+       MonoType *type = MONO_HANDLE_RAW (object)->type;
        MonoTypeNameFormat format;
-       MonoString *res;
+       MonoStringHandle res;
        gchar *name;
 
        if (full_name)
@@ -5313,16 +5317,16 @@ ves_icall_System_MonoType_getFullName (MonoReflectionType *object, gboolean full
        else
                format = MONO_TYPE_NAME_FORMAT_REFLECTION;
  
-       name = mono_type_get_name_full (object->type, format);
+       name = mono_type_get_name_full (type, format);
        if (!name)
-               return NULL;
+               return NULL_HANDLE_STRING;
 
-       if (full_name && (object->type->type == MONO_TYPE_VAR || object->type->type == MONO_TYPE_MVAR)) {
+       if (full_name && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR)) {
                g_free (name);
-               return NULL;
+               return NULL_HANDLE_STRING;
        }
 
-       res = mono_string_new (domain, name);
+       res = mono_string_new_handle (domain, name);
        g_free (name);
 
        return res;
@@ -8218,6 +8222,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
 
 #define ICALL_TYPE(id,name,first)
 #define ICALL(id,name,func) Icall_ ## id,
+#define HANDLES(inner) inner
 
 enum {
 #include "metadata/icall-def.h"
@@ -8228,6 +8233,8 @@ enum {
 #undef ICALL
 #define ICALL_TYPE(id,name,first) Icall_type_ ## id,
 #define ICALL(id,name,func)
+#undef HANDLES
+#define HANDLES(inner) inner
 enum {
 #include "metadata/icall-def.h"
        Icall_type_num
@@ -8237,6 +8244,8 @@ enum {
 #undef ICALL
 #define ICALL_TYPE(id,name,firstic) {(Icall_ ## firstic)},
 #define ICALL(id,name,func)
+#undef HANDLES
+#define HANDLES(inner) inner
 typedef struct {
        guint16 first_icall;
 } IcallTypeDesc;
@@ -8249,6 +8258,8 @@ icall_type_descs [] = {
 
 #define icall_desc_num_icalls(desc) ((desc) [1].first_icall - (desc) [0].first_icall)
 
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #define ICALL_TYPE(id,name,first)
 #undef ICALL
@@ -8320,6 +8331,8 @@ icall_names [] = {
 
 #endif /* !HAVE_ARRAY_ELEM_INIT */
 
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #undef ICALL
 #define ICALL_TYPE(id,name,first)
@@ -8331,6 +8344,8 @@ icall_functions [] = {
 };
 
 #ifdef ENABLE_ICALL_SYMBOL_MAP
+#undef HANDLES
+#define HANDLES(inner) inner
 #undef ICALL_TYPE
 #undef ICALL
 #define ICALL_TYPE(id,name,first)
@@ -8342,6 +8357,19 @@ icall_symbols [] = {
 };
 #endif
 
+#undef ICALL_TYPE
+#undef ICALL
+#define ICALL_TYPE(id,name,first)
+#define ICALL(id,name,func) 0,
+#undef HANDLES
+#define HANDLES(inner) 1,
+static const guchar
+icall_uses_handles [] = {
+#include "metadata/icall-def.h"
+#undef ICALL
+#undef HANDLES
+};
+
 #endif /* DISABLE_ICALL_TABLES */
 
 static mono_mutex_t icall_mutex;
@@ -8462,13 +8490,31 @@ compare_method_imap (const void *key, const void *elem)
        return strcmp (key, method_name);
 }
 
-static gpointer
-find_method_icall (const IcallTypeDesc *imap, const char *name)
+static gsize
+find_slot_icall (const IcallTypeDesc *imap, const char *name)
 {
        const guint16 *nameslot = (const guint16 *)mono_binary_search (name, icall_names_idx + imap->first_icall, icall_desc_num_icalls (imap), sizeof (icall_names_idx [0]), compare_method_imap);
        if (!nameslot)
+               return -1;
+       return (nameslot - &icall_names_idx [0]);
+}
+
+static gboolean
+find_uses_handles_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
+               return FALSE;
+       return (gboolean)icall_uses_handles [slotnum];
+}
+
+static gpointer
+find_method_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
                return NULL;
-       return (gpointer)icall_functions [(nameslot - &icall_names_idx [0])];
+       return (gpointer)icall_functions [slotnum];
 }
 
 static int
@@ -8496,13 +8542,31 @@ compare_method_imap (const void *key, const void *elem)
        return strcmp (key, *method_name);
 }
 
-static gpointer
-find_method_icall (const IcallTypeDesc *imap, const char *name)
+static gsize
+find_slot_icall (const IcallTypeDesc *imap, const char *name)
 {
        const char **nameslot = mono_binary_search (name, icall_names + imap->first_icall, icall_desc_num_icalls (imap), sizeof (icall_names [0]), compare_method_imap);
        if (!nameslot)
+               return -1;
+       return nameslot - icall_names;
+}
+
+static gpointer
+find_method_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
                return NULL;
-       return (gpointer)icall_functions [(nameslot - icall_names)];
+       return (gpointer)icall_functions [slotnum];
+}
+
+static gboolean
+find_uses_handles_icall (const IcallTypeDesc *imap, const char *name)
+{
+       gsize slotnum = find_slot_icall (imap, name);
+       if (slotnum == -1)
+               return FALSE;
+       return (gboolean)icall_uses_handles [slotnum];
 }
 
 static int
@@ -8554,8 +8618,19 @@ no_icall_table (void)
 }
 #endif
 
+/**
+ * mono_lookup_internal_call_full:
+ * @method: the method to look up
+ * @uses_handles: out argument if method needs handles around managed objects.
+ *
+ * Returns a pointer to the icall code for the given method.  If
+ * uses_handles is not NULL, it will be set to TRUE if the method
+ * needs managed objects wrapped using the infrastructure in handle.h
+ *
+ * If the method is not found, warns and returns NULL.
+ */
 gpointer
-mono_lookup_internal_call (MonoMethod *method)
+mono_lookup_internal_call_full (MonoMethod *method, mono_bool *uses_handles)
 {
        char *sigstart;
        char *tmpsig;
@@ -8616,6 +8691,8 @@ mono_lookup_internal_call (MonoMethod *method)
 
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = FALSE;
                mono_icall_unlock ();;
                return res;
        }
@@ -8623,6 +8700,8 @@ mono_lookup_internal_call (MonoMethod *method)
        *sigstart = 0;
        res = g_hash_table_lookup (icall_hash, mname);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = FALSE;
                mono_icall_unlock ();
                return res;
        }
@@ -8643,6 +8722,8 @@ mono_lookup_internal_call (MonoMethod *method)
        }
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = find_uses_handles_icall (imap, sigstart - mlen);
                mono_icall_unlock ();
                return res;
        }
@@ -8650,6 +8731,8 @@ mono_lookup_internal_call (MonoMethod *method)
        *sigstart = '(';
        res = find_method_icall (imap, sigstart - mlen);
        if (res) {
+               if (uses_handles)
+                       *uses_handles = find_uses_handles_icall (imap, sigstart - mlen);
                mono_icall_unlock ();
                return res;
        }
@@ -8668,6 +8751,12 @@ mono_lookup_internal_call (MonoMethod *method)
 #endif
 }
 
+gpointer
+mono_lookup_internal_call (MonoMethod *method)
+{
+       return mono_lookup_internal_call_full (method, NULL);
+}
+
 #ifdef ENABLE_ICALL_SYMBOL_MAP
 static int
 func_cmp (gconstpointer key, gconstpointer p)
index 774c9b8a47fbe13024a3db9799635992107af351..a2c6d349ddf15fcc186278750843b8289e4a6c96 100644 (file)
@@ -60,6 +60,10 @@ mono_add_internal_call     (const char *name, const void* method);
 MONO_API void*
 mono_lookup_internal_call (MonoMethod *method);
 
+void*
+mono_lookup_internal_call_full (MonoMethod *method, mono_bool *uses_handles);
+
+
 MONO_API const char*
 mono_lookup_icall_symbol (MonoMethod *m);
 
index 2876a387a353adcda16b1f6f06b5fb58faf57d05..0132f53fbed8ae08a5777249e87796ad5ee92050 100644 (file)
@@ -40,6 +40,7 @@
 #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"
@@ -203,6 +204,12 @@ 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)
@@ -338,6 +345,9 @@ mono_marshal_init (void)
                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 ();
@@ -7745,11 +7755,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;
+               (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;
 
@@ -7761,21 +7814,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);
@@ -11920,3 +12010,20 @@ 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);
+}