From f295ea1adf64cdd9d46674ff410da6fb5a538a00 Mon Sep 17 00:00:00 2001 From: Johan Lorensson Date: Thu, 23 Feb 2023 18:11:23 +0100 Subject: [PATCH] [Mono]: Add support for lazy runtime init in native-to-managed wrapper, similar to NativeAOT library build. (#82253) * Add support for runtime init in native-to-managed wrapper. NativeAOT supports library mode, building all needed runtime and managed code into a static or shared library that can be loaded and used by embedding applications. NativeAOT exports managed functiond marked with UnmanagedCallersOnly attribute that can be called by embedder to run managed code. NativeAOT runtime doesn't need any initialization, meaning that calling the managed method exported using UnmanagedCallersOnly attribute will perform lazy runtime initialization on first call. This commit add similar support to MonoVM giving it possibilities to include a call to a runtime init function as part of native-to-managed wrapper used for methods marked with UnmanagedCallersOnly attribute + entry point. AOT compiler accepts a new argument, runtime-init-callback, if used like that, the native-to-managed wrapper will get a call to a default invoke callback method implemented by runtime, that will call a set callback once (thread safe). It is also possible to pass runtime-init-callback= to AOT compiler, and in that case native-to-managed wrapper will call that function and its up to implementor to do a thread safe implementation of runtime init. This capability could be used in case where the library can't set the callback before consumer of the library class the exported function. Two new runtime API's have been added in this commit, one to set the callback called by default runtime init implementation and the other is the implementation of that function used in native-to-managed wrapper if user doesn't use a custom runtime init callback function. Since this integration scenario is mainly for library build scenarios (we control the library builder), these methods are marked as MONO_COMPONENT_API and not something that should be part of the public API surface. * Split mono_marshal_get_managed_wrapper into two functions. * Drop runtime init for mono_marshal_emit_managed_wrapper. * aquire/release semantics around runtime_init_callback. * Detect MONO_JIT_ICALL_mono_dummy_runtime_init_callback in more places. * Add description of new AOT compiler options. --- src/mono/mono/metadata/jit-icall-reg.h | 1 + src/mono/mono/metadata/marshal-lightweight.c | 11 ++- src/mono/mono/metadata/marshal.c | 46 ++++++++--- src/mono/mono/metadata/marshal.h | 5 +- src/mono/mono/mini/aot-compiler.c | 87 ++++++++++++++------ src/mono/mono/mini/jit-icalls.c | 10 +++ src/mono/mono/mini/jit-icalls.h | 2 + src/mono/mono/mini/mini-runtime.c | 39 +++++++++ src/mono/mono/mini/mini-runtime.h | 8 ++ src/mono/mono/mini/mini.c | 4 +- 10 files changed, 170 insertions(+), 43 deletions(-) diff --git a/src/mono/mono/metadata/jit-icall-reg.h b/src/mono/mono/metadata/jit-icall-reg.h index a3aac59f4d458..984c26721eec5 100644 --- a/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/mono/mono/metadata/jit-icall-reg.h @@ -339,6 +339,7 @@ MONO_JIT_ICALL (ves_icall_string_new_wrapper) \ MONO_JIT_ICALL (ves_icall_thread_finish_async_abort) \ MONO_JIT_ICALL (mono_marshal_lookup_pinvoke) \ MONO_JIT_ICALL (mono_gsharedvt_constrained_call_fast) \ +MONO_JIT_ICALL (mono_dummy_runtime_init_callback) \ \ MONO_JIT_ICALL (count) \ diff --git a/src/mono/mono/metadata/marshal-lightweight.c b/src/mono/mono/metadata/marshal-lightweight.c index 9d43d0b124d52..54e37d2036d99 100644 --- a/src/mono/mono/metadata/marshal-lightweight.c +++ b/src/mono/mono/metadata/marshal-lightweight.c @@ -2491,7 +2491,7 @@ emit_managed_wrapper_validate_signature (MonoMethodSignature* sig, MonoMarshalSp } static void -emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, MonoError *error) +emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, gboolean runtime_init_callback, MonoError *error) { MonoMethodSignature *sig, *csig; int i, *tmp_locals; @@ -2550,9 +2550,18 @@ emit_managed_wrapper_ilgen (MonoMethodBuilder *mb, MonoMethodSignature *invoke_s * return ret; */ + /* delete_old = FALSE */ mono_mb_emit_icon (mb, 0); mono_mb_emit_stloc (mb, 2); + /* + * Transformed into a direct icall when runtime init callback is enabled for a native-to-managed wrapper. + * This icall is special cased in the JIT so it can be called in native-to-managed wrapper before + * runtime has been initialized. On return, runtime must be fully initialized. + */ + if (runtime_init_callback) + mono_mb_emit_icall (mb, mono_dummy_runtime_init_callback); + gc_unsafe_transition_builder_emit_enter(&gc_unsafe_builder); /* we first do all conversions */ diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 5ab899e032d0e..e7aff60aee5e2 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3910,7 +3910,7 @@ mono_marshal_get_native_func_wrapper_indirect (MonoClass *caller_class, MonoMeth /* * mono_marshal_emit_managed_wrapper: * - * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of + * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of * the delegate which wraps the managed method to be called. For closed delegates, * it could have fewer parameters than the method it wraps. * THIS_LOC is the memory location where the target of the delegate is stored. @@ -3918,7 +3918,7 @@ mono_marshal_get_native_func_wrapper_indirect (MonoClass *caller_class, MonoMeth void mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, MonoError *error) { - get_marshal_cb ()->emit_managed_wrapper (mb, invoke_sig, mspecs, m, method, target_handle, error); + get_marshal_cb ()->emit_managed_wrapper (mb, invoke_sig, mspecs, m, method, target_handle, FALSE, error); } static gboolean @@ -4017,16 +4017,8 @@ method_signature_is_usable_when_marshalling_disabled (MonoMethodSignature *sig) return check_all_types_in_method_signature (sig, &type_is_usable_when_marshalling_disabled); } -/** - * mono_marshal_get_managed_wrapper: - * Generates IL code to call managed methods from unmanaged code - * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure. - * - * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with - * UnamangedCallersOnlyAttribute. - */ -MonoMethod * -mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error) +static MonoMethod * +marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, gboolean runtime_init_callback, MonoError *error) { MonoMethodSignature *sig, *csig, *invoke_sig; MonoMethodBuilder *mb; @@ -4192,7 +4184,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mono_custom_attrs_free (cinfo); } - mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle, error); + get_marshal_cb ()->emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle, runtime_init_callback, error); res = NULL; if (is_ok (error)) { @@ -4225,6 +4217,34 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, return res; } +/** + * mono_marshal_get_managed_wrapper: + * Generates IL code to call managed methods from unmanaged code + * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure. + * + * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with + * UnamangedCallersOnlyAttribute. + */ +MonoMethod * +mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error) +{ + return marshal_get_managed_wrapper (method, delegate_klass, target_handle, FALSE, error); +} + +/** + * mono_marshal_get_runtime_init_managed_wrapper: + * Generates IL code to call managed methods from unmanaged code with lazy runtime init support + * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure. + * + * If \p delegate_klass is \c NULL, we're creating a wrapper for a function pointer to a method marked with + * UnamangedCallersOnlyAttribute. + */ +MonoMethod * +mono_marshal_get_runtime_init_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle target_handle, MonoError *error) +{ + return marshal_get_managed_wrapper (method, delegate_klass, target_handle, TRUE, error); +} + gpointer mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) { diff --git a/src/mono/mono/metadata/marshal.h b/src/mono/mono/metadata/marshal.h index 89b306d7def0c..6cd33778301f9 100644 --- a/src/mono/mono/metadata/marshal.h +++ b/src/mono/mono/metadata/marshal.h @@ -323,7 +323,7 @@ typedef struct { void (*emit_stelemref) (MonoMethodBuilder *mb); void (*emit_array_address) (MonoMethodBuilder *mb, int rank, int elem_size); void (*emit_native_wrapper) (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, MonoNativeWrapperFlags flags); - void (*emit_managed_wrapper) (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, MonoError *error); + void (*emit_managed_wrapper) (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoGCHandle target_handle, gboolean runtime_init_callback, MonoError *error); void (*emit_runtime_invoke_body) (MonoMethodBuilder *mb, const char **param_names, MonoImage *image, MonoMethod *method, MonoMethodSignature *sig, MonoMethodSignature *callsig, gboolean virtual_, gboolean need_direct_wrapper); void (*emit_runtime_invoke_dynamic) (MonoMethodBuilder *mb); void (*emit_delegate_begin_invoke) (MonoMethodBuilder *mb, MonoMethodSignature *sig); @@ -506,6 +506,9 @@ mono_marshal_get_string_ctor_signature (MonoMethod *method); MonoMethod * mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle this_loc, MonoError *exernal_error); +MonoMethod * +mono_marshal_get_runtime_init_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoGCHandle this_loc, MonoError *exernal_error); + gpointer mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type); diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index fb7ed565a7c37..4481c694d36c8 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -255,6 +255,7 @@ typedef struct MonoAotOptions { gboolean no_opt; char *clangxx; char *depfile; + char *runtime_init_callback; } MonoAotOptions; typedef enum { @@ -5303,7 +5304,11 @@ MONO_RESTORE_WARNING } mono_reflection_free_custom_attr_data_args_noalloc (decoded_args); - wrapper = mono_marshal_get_managed_wrapper (method, NULL, 0, error); + if (acfg->aot_opts.runtime_init_callback != NULL && export_name != NULL) + wrapper = mono_marshal_get_runtime_init_managed_wrapper (method, NULL, 0, error); + else + wrapper = mono_marshal_get_managed_wrapper (method, NULL, 0, error); + if (!is_ok (error)) { report_loader_error (acfg, error, FALSE, "Unable to generate native entry point '%s' due to '%s'.", mono_method_get_full_name (method), mono_error_get_message (error)); continue; @@ -6625,13 +6630,24 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui } } else if (patch_info->type == MONO_PATCH_INFO_JIT_ICALL_ID) { MonoJitICallInfo * const info = mono_find_jit_icall_info (patch_info->data.jit_icall_id); - const char * const sym = info->c_symbol; - if (!got_only && sym && acfg->aot_opts.direct_icalls && info->func == info->wrapper) { - /* Call to a jit icall without a wrapper */ - direct_call = TRUE; - external_call = TRUE; - g_assert (strlen (sym) < 1000); - direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym); + if (!got_only && info->func == info->wrapper) { + const char * sym = NULL; + if (patch_info->data.jit_icall_id == MONO_JIT_ICALL_mono_dummy_runtime_init_callback) { + g_assert (acfg->aot_opts.static_link && acfg->aot_opts.runtime_init_callback != NULL); + sym = acfg->aot_opts.runtime_init_callback; + direct_call = TRUE; + external_call = TRUE; + } else if (info->c_symbol && acfg->aot_opts.direct_icalls) { + sym = info->c_symbol; + direct_call = TRUE; + external_call = TRUE; + } + + if (sym) { + /* Call to a jit icall without a wrapper */ + g_assert (strlen (sym) < 1000); + direct_call_target = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, sym); + } } } if (direct_call) { @@ -8749,6 +8765,14 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) } } else if (str_begins_with (arg, "depfile=")) { opts->depfile = g_strdup (arg + strlen ("depfile=")); + } else if (str_begins_with (arg, "runtime-init-callback=")) { + opts->runtime_init_callback = g_strdup (arg + strlen ("runtime-init-callback=")); + if (opts->runtime_init_callback [0] == '\0') { + printf ("Missing runtime-init-callback symbol.\n"); + exit (0); + } + } else if (str_begins_with (arg, "runtime-init-callback")) { + opts->runtime_init_callback = g_strdup ("mono_invoke_runtime_init_callback"); } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) { printf ("Supported options for --aot:\n"); printf (" asmonly - \n"); @@ -8786,6 +8810,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" mibc-profile= - \n"); printf (" print-skipped-methods - \n"); printf (" readonly-value= - \n"); + printf (" runtime-init-callback - Enable default runtime init callback support for UnmanagedCallersOnly+EntryPoint native-to-managed wrappers. Requires 'static' option.\n"); + printf (" runtime-init-callback= - Enable custom runtime init callback support for UnmanagedCallersOnly+EntryPoint native-to-managed wrappers. Requires 'static' option. Wrapper makes a direct call to symbol, initializing runtime.\n"); printf (" save-temps - \n"); printf (" soft-debug - \n"); printf (" static - \n"); @@ -10290,28 +10316,30 @@ mono_aot_mark_unused_llvm_plt_entry (MonoJumpInfo *patch_info) char* mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) { + gboolean direct_calls = llvm_acfg->aot_opts.direct_icalls; const char *sym = NULL; - if (llvm_acfg->aot_opts.direct_icalls) { - if (type == MONO_PATCH_INFO_JIT_ICALL_ADDR) { - /* Call to a C function implementing a jit icall */ - sym = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data)->c_symbol; - } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { - MonoMethod *method = (MonoMethod *)data; - if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) - sym = lookup_icall_symbol_name_aot (method); - else if (is_direct_pinvoke_specified_for_method (llvm_acfg, method)) - get_pinvoke_import (llvm_acfg, method, NULL, &sym); - } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID) { - MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); - char const * const name = info->c_symbol; - if (name && info->func == info->wrapper) - sym = name; + if (direct_calls && type == MONO_PATCH_INFO_JIT_ICALL_ADDR) { + /* Call to a C function implementing a jit icall */ + sym = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data)->c_symbol; + } else if (direct_calls && type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { + MonoMethod *method = (MonoMethod *)data; + if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) + sym = lookup_icall_symbol_name_aot (method); + else if (is_direct_pinvoke_specified_for_method (llvm_acfg, method)) + get_pinvoke_import (llvm_acfg, method, NULL, &sym); + } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID && (direct_calls || (MonoJitICallId)(gsize)data == MONO_JIT_ICALL_mono_dummy_runtime_init_callback)) { + MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); + if (info->func == info->wrapper) { + if ((MonoJitICallId)(gsize)data == MONO_JIT_ICALL_mono_dummy_runtime_init_callback) { + sym = llvm_acfg->aot_opts.runtime_init_callback; + } else { + sym = info->c_symbol ? info->c_symbol : NULL; + } } - if (sym) - return g_strdup (sym); } - return NULL; + + return sym ? g_strdup (sym) : NULL; } char* @@ -13890,6 +13918,7 @@ aot_opts_free (MonoAotOptions *aot_opts) g_free (aot_opts->llvm_cpu_attr); g_free (aot_opts->clangxx); g_free (aot_opts->depfile); + g_free (aot_opts->runtime_init_callback); } static void @@ -15190,6 +15219,12 @@ mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opt goto early_exit; } + if (aot_opts.runtime_init_callback != NULL && !aot_opts.static_link) { + fprintf (stderr, "The 'runtime-init-callback' option requires the 'static' option.\n"); + res = 1; + goto early_exit; + } + if (aot_opts.dedup_include) { /* Find the assembly which will contain the dedup-ed code */ int dedup_aindex = -1; diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index a22a36ea98f5b..c26e104a09d92 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1708,6 +1708,16 @@ mono_dummy_jit_icall_val (gpointer val) { } +/* Dummy icall place holder function representing runtime init call. */ +/* When used, function will be replaced with a direct icall to a custom */ +/* runtime init function called from start of native-to-managed wrapper. */ +/* This function should never end up being called. */ +void +mono_dummy_runtime_init_callback (void) +{ + g_assert (!"Runtime incorrectly configured to support runtime init callback from native-to-managed wrapper."); +} + void mini_init_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, MonoGSharedMethodInfo *info) { diff --git a/src/mono/mono/mini/jit-icalls.h b/src/mono/mono/mini/jit-icalls.h index afd10935c5dc4..db59a7608c8da 100644 --- a/src/mono/mono/mini/jit-icalls.h +++ b/src/mono/mono/mini/jit-icalls.h @@ -238,6 +238,8 @@ ICALL_EXPORT void mono_dummy_jit_icall (void); ICALL_EXPORT void mono_dummy_jit_icall_val (gpointer ptr); +ICALL_EXPORT void mono_dummy_runtime_init_callback (void); + ICALL_EXPORT void mini_init_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, MonoGSharedMethodInfo *info); #endif /* __MONO_JIT_ICALLS_H__ */ diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 235774701cdd9..cd7117dde4143 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -157,6 +157,9 @@ static GPtrArray *profile_options; static GSList *tramp_infos; GSList *mono_interp_only_classes; +static MonoRuntimeInitCallback runtime_init_callback; +static guint64 runtime_init_thread_id = G_MAXUINT64; + static void register_icalls (void); static void runtime_cleanup (MonoDomain *domain, gpointer user_data); static void mini_invalidate_transformed_interp_methods (MonoAssemblyLoadContext *alc, uint32_t generation); @@ -5036,6 +5039,9 @@ register_icalls (void) register_icall_no_wrapper (mono_interp_entry_from_trampoline, mono_icall_sig_void_ptr_ptr); register_icall_no_wrapper (mono_interp_to_native_trampoline, mono_icall_sig_void_ptr_ptr); + /* Register dummy icall placeholder for runtime init callback support in native-to-managed wrapper */ + register_icall_no_wrapper (mono_dummy_runtime_init_callback, mono_icall_sig_void); + #ifdef MONO_ARCH_HAS_REGISTER_ICALL mono_arch_register_icall (); #endif @@ -5395,3 +5401,36 @@ mini_alloc_jinfo (MonoJitMemoryManager *jit_mm, int size) return (MonoJitInfo*)mono_mem_manager_alloc0 (jit_mm->mem_manager, size); } } + +void +mono_set_runtime_init_callback (MonoRuntimeInitCallback callback) +{ + runtime_init_callback = callback; +} + +/* +* Default implementation invoking runtime init callback in native-to-managed wrapper. +*/ +void +mono_invoke_runtime_init_callback (void) +{ + MonoRuntimeInitCallback callback = NULL; + mono_atomic_load_acquire (callback, MonoRuntimeInitCallback, &runtime_init_callback); + if (G_UNLIKELY (callback)) { + guint64 thread_id = mono_native_thread_os_id_get (); + if (callback && (mono_atomic_load_i64 ((volatile gint64 *)&runtime_init_thread_id) == thread_id)) + return; + + while (mono_atomic_cas_i64 ((volatile gint64 *)&runtime_init_thread_id, (gint64)thread_id, (gint64)G_MAXUINT64) != (gint64)G_MAXUINT64) + g_usleep (1000); + + mono_atomic_load_acquire (callback, MonoRuntimeInitCallback, &runtime_init_callback); + if (callback) { + if (!mono_thread_info_current_unchecked ()) + callback (); + mono_atomic_store_release (&runtime_init_callback, NULL); + } + + mono_atomic_xchg_i64 ((volatile gint64 *)&runtime_init_thread_id, (gint64)G_MAXUINT64); + } +} diff --git a/src/mono/mono/mini/mini-runtime.h b/src/mono/mono/mini/mini-runtime.h index 0abd8e4332334..16299ff402052 100644 --- a/src/mono/mono/mini/mini-runtime.h +++ b/src/mono/mono/mini/mini-runtime.h @@ -718,4 +718,12 @@ void mini_register_sigterm_handler (void); MONO_RESTORE_WARNING \ } while (0) +typedef void (*MonoRuntimeInitCallback) (void); + +MONO_COMPONENT_API void +mono_set_runtime_init_callback (MonoRuntimeInitCallback callback); + +MONO_COMPONENT_API void +mono_invoke_runtime_init_callback (void); + #endif /* __MONO_MINI_RUNTIME_H__ */ diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 098712ff609b8..c6dd66921ccf5 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -3178,8 +3178,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, JitFlags flags, int parts cfg->jit_mm = jit_mm_for_method (cfg->method); cfg->mem_manager = m_method_get_mem_manager (cfg->method); - if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) { - /* We can't have seq points inside gc critical regions */ + if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC || cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) { + /* We can't have seq points inside gc critical regions or native-to-managed wrapper */ cfg->gen_seq_points = FALSE; cfg->gen_sdb_seq_points = FALSE; }