Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
[Mono]: Add support for lazy runtime init in native-to-managed wrapper, similar to NativeAOT library build.#82253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
16ef9c05a5e35bd7a63d360dfa5b5ff138ff6fe400File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
lateralusX marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| } | ||
| } | ||
| 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=<string> - \n"); | ||
| printf (" print-skipped-methods - \n"); | ||
| printf (" readonly-value=<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=<value> - Enable custom runtime init callback support for UnmanagedCallersOnly+EntryPoint native-to-managed wrappers. Requires 'static' option. Wrapper makes a direct call to <value> 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; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) | ||
lateralusX marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| 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); | ||
mdh1418 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) { | ||
mdh1418 marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| /* 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; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.