From 516d7f18b879a0b895d6ef51e075cc3ac5681d66 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:05:40 -0500 Subject: [PATCH 01/38] [mono] Relocate get_pinvoke_import for usage in is_direct_callable direct_pinvoke helper function --- src/mono/mono/mini/aot-compiler.c | 76 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index cf7a164eb3e82a..ef98fc10986db3 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6111,6 +6111,44 @@ method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method) } } +#ifdef MONO_ARCH_AOT_SUPPORTED +static const char * +get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) +{ + MonoImage *image = m_class_get_image (method->klass); + MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; + MonoTableInfo *tables = image->tables; + MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP]; + guint32 im_cols [MONO_IMPLMAP_SIZE]; + char *import; + + import = (char *)g_hash_table_lookup (acfg->method_to_pinvoke_import, method); + if (import != NULL) + return import; + + if (piinfo->implmap_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_IMPLMAP, piinfo->implmap_idx)) + return NULL; + + mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE); + + int module_idx = im_cols [MONO_IMPLMAP_SCOPE]; + if (module_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_MODULEREF, module_idx)) + return NULL; + + import = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); + + g_hash_table_insert (acfg->method_to_pinvoke_import, method, import); + + return import; +} +#else +static const char * +get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) +{ + return NULL; +} +#endif + /* * is_direct_callable: * @@ -6178,44 +6216,6 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc return FALSE; } -#ifdef MONO_ARCH_AOT_SUPPORTED -static const char * -get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) -{ - MonoImage *image = m_class_get_image (method->klass); - MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; - MonoTableInfo *tables = image->tables; - MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP]; - guint32 im_cols [MONO_IMPLMAP_SIZE]; - char *import; - - import = (char *)g_hash_table_lookup (acfg->method_to_pinvoke_import, method); - if (import != NULL) - return import; - - if (piinfo->implmap_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_IMPLMAP, piinfo->implmap_idx)) - return NULL; - - mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE); - - int module_idx = im_cols [MONO_IMPLMAP_SCOPE]; - if (module_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_MODULEREF, module_idx)) - return NULL; - - import = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); - - g_hash_table_insert (acfg->method_to_pinvoke_import, method, import); - - return import; -} -#else -static const char * -get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) -{ - return NULL; -} -#endif - static gint compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b) { From ceb5bf3fc248ec70f9f22f7b4d6cfdc9bbe0b5f6 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:40:01 -0500 Subject: [PATCH 02/38] [mono] Initialize direct pinvoke fields and parameter parsing --- src/mono/mono/mini/aot-compiler.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index ef98fc10986db3..93159ba96e259a 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -208,6 +208,8 @@ typedef struct MonoAotOptions { gboolean gen_msym_dir; char *gen_msym_dir_path; gboolean direct_pinvoke; + GList *direct_pinvokes; + GList *direct_pinvoke_lists; gboolean direct_icalls; gboolean direct_extern_calls; gboolean no_direct_calls; @@ -307,6 +309,7 @@ typedef struct MonoAotCompile { GHashTable *method_to_cfg; GHashTable *token_info_hash; GHashTable *method_to_pinvoke_import; + GHashTable *direct_pinvokes; GHashTable *method_to_external_icall_symbol_name; GPtrArray *extra_methods; GPtrArray *image_table; @@ -8503,6 +8506,10 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->gen_msym_dir_path = g_strdup (arg + strlen ("msym_dir=")); } else if (str_begins_with (arg, "direct-pinvoke")) { opts->direct_pinvoke = TRUE; + } else if (str_begins_with (arg, "direct-pinvokes")) { + opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (arg + strlen ("direct-pinvokes="))); + } else if (str_begins_with (arg, "direct-pinvoke-lists")) { + opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (arg + strlen ("direct-pinvoke-lists="))); } else if (str_begins_with (arg, "direct-icalls")) { opts->direct_icalls = TRUE; } else if (str_begins_with (arg, "direct-extern-calls")) { @@ -8618,6 +8625,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" data-outfile=\n"); printf (" direct-icalls\n"); printf (" direct-pinvoke\n"); + printf (" direct-pinvokes=\n"); + printf (" direct-pinvoke-lists=\n"); printf (" dwarfdebug\n"); printf (" full\n"); printf (" hybrid\n"); @@ -13698,6 +13707,7 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->method_to_cfg = g_hash_table_new (NULL, NULL); acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL); acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free); + acfg->direct_pinvokes = g_hash_table_new_full (NULL, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy); acfg->method_to_external_icall_symbol_name = g_hash_table_new_full (NULL, NULL, NULL, g_free); acfg->image_hash = g_hash_table_new (NULL, NULL); acfg->image_table = g_ptr_array_new (); @@ -13767,6 +13777,7 @@ acfg_free (MonoAotCompile *acfg) g_hash_table_destroy (acfg->method_to_cfg); g_hash_table_destroy (acfg->token_info_hash); g_hash_table_destroy (acfg->method_to_pinvoke_import); + g_hash_table_destroy (acfg->direct_pinvokes); g_hash_table_destroy (acfg->method_to_external_icall_symbol_name); g_hash_table_destroy (acfg->image_hash); g_hash_table_destroy (acfg->unwind_info_offsets); From 29e72b52176e28a70964328d1fd90ba4de681b0d Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:41:53 -0500 Subject: [PATCH 03/38] [mono] Process direct pinvoke parameters to populate hash table --- src/mono/mono/mini/aot-compiler.c | 86 +++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 93159ba96e259a..18b18099fa1e68 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14127,6 +14127,50 @@ init_options (MonoAotOptions *aot_opts) aot_opts->clangxx = g_strdup ("clang++"); } +static gboolean +mono_aot_add_direct_pinvoke (MonoAotCompile *acfg, char *dpi) +{ + char *direct_pinvoke = g_strdup (dpi); + if (!direct_pinvoke) + return TRUE; + + if (direct_pinvoke[0] == '#') + return TRUE; + + g_strstrip (direct_pinvoke); + if (!direct_pinvoke) + return TRUE; + + char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", -1); + char *library_name = g_strdup (direct_pinvoke_split[0]); + if (!direct_pinvoke_split[1]) { + g_hash_table_insert (acfg->direct_pinvokes, library_name, NULL); + g_strfreev (direct_pinvoke_split); + return TRUE; + } + if (direct_pinvoke_split[2]) { + aot_printerrf (acfg, "The provided 'direct_pinvoke' AOT option '%s' shouldn't contain multiple '!'\n", dpi); + g_strfreev (direct_pinvoke_split); + return FALSE; + } + + char *entrypoint_name = g_strdup (direct_pinvoke_split[1]); + if (g_hash_table_contains (acfg->direct_pinvokes, library_name)) { + GHashTable *val = g_hash_table_lookup (acfg->direct_pinvokes, library_name); + if (!val || g_hash_table_contains (val, entrypoint_name)) { + g_strfreev (direct_pinvoke_split); + return TRUE; + } + g_hash_table_insert (val, entrypoint_name, NULL); + } else { + GHashTable *val = g_hash_table_new_full (NULL, g_str_equal, g_free, NULL); + g_hash_table_insert (val, entrypoint_name, NULL); + g_hash_table_insert (acfg->direct_pinvokes, library_name, val); + } + g_strfreev (direct_pinvoke_split); + return TRUE; +} + static int aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) { @@ -14210,9 +14254,45 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) } #endif - if (acfg->aot_opts.direct_pinvoke && !acfg->aot_opts.static_link) { - aot_printerrf (acfg, "The 'direct-pinvoke' AOT option also requires the 'static' AOT option.\n"); - return 1; + if (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) { + if (!acfg->aot_opts.static_link) { + aot_printerrf (acfg, "The 'direct-pinvokes' and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); + return 1; + } + char *any_module = (char *)g_malloc0(2); + any_module[0] = '*'; + g_hash_table_insert (acfg->direct_pinvokes, any_module, NULL); + } + gboolean added_direct_pinvoke = TRUE; + if (acfg->aot_opts.direct_pinvokes) { + GList *l; + + for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { + added_direct_pinvoke = mono_aot_add_direct_pinvoke (acfg, (char*)l->data); + if (!added_direct_pinvoke) + return 1; + } + } + if (acfg->aot_opts.direct_pinvoke_lists) { + GList *l; + + for (l = acfg->aot_opts.direct_pinvoke_lists; l; l = l->next) { + char *direct_pinvoke_list = (char*)l->data; + FILE *direct_pinvoke_list_file = fopen (direct_pinvoke_list, "r"); + if (!direct_pinvoke_list_file) { + aot_printerrf (acfg, "Failed to open the provided 'direct-pinvoke-list' '%s', fopen failed.\n", direct_pinvoke_list); + return 1; + } + + char *line = NULL; + size_t line_len = 0; + while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { + added_direct_pinvoke = mono_aot_add_direct_pinvoke (acfg, line); + } + fclose (direct_pinvoke_list_file); + if (!added_direct_pinvoke) + return 1; + } } if (acfg->aot_opts.static_link) From 2ef0b7aec134ae1aa0bfde10990c877695f0d4b3 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:43:14 -0500 Subject: [PATCH 04/38] [mono] Add logic to check method for specified direct pinvoke match --- src/mono/mono/mini/aot-compiler.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 18b18099fa1e68..2ffdd9a62836a1 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6152,6 +6152,25 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) } #endif +/* + * mono_aot_direct_pinvoke_enabled_for_method + * + * Return whether the method is specified to be directly pinvoked + */ +static gboolean +mono_aot_direct_pinvoke_enabled_for_method (MonoAotCompile *acfg, MonoMethod *method) +{ + const char *sym = get_pinvoke_import (acfg, method); + const char *module_name = acfg->image->module_name; + if (g_hash_table_contains (acfg->direct_pinvokes, module_name)) { + GHashTable *val = g_hash_table_lookup (acfg->direct_pinvokes, module_name); + if (!val) + return TRUE; + return g_hash_table_contains (val, sym); + } + return FALSE; +} + /* * is_direct_callable: * From 28210774ba2b2780ed6bd5ccf60af1278bb9417a Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:44:29 -0500 Subject: [PATCH 05/38] [mono] Deprecate direct_pinvoke boolean flag in favor of direct_pinvokes and direct_pinvoke_lists fields --- src/mono/mono/mini/aot-compiler.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 2ffdd9a62836a1..6cd1f9724fede7 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -207,7 +207,6 @@ typedef struct MonoAotOptions { gboolean log_instances; gboolean gen_msym_dir; char *gen_msym_dir_path; - gboolean direct_pinvoke; GList *direct_pinvokes; GList *direct_pinvoke_lists; gboolean direct_icalls; @@ -6227,7 +6226,7 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc /* Cross assembly calls */ return method_is_externally_callable (acfg, patch_info->data.method); } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { - if (acfg->aot_opts.direct_pinvoke) + if (mono_aot_direct_pinvoke_enabled_for_method (acfg, patch_info->data.method)) return TRUE; } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (acfg->aot_opts.direct_icalls) @@ -8523,8 +8522,6 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) mini_debug_options.no_seq_points_compact_data = FALSE; opts->gen_msym_dir = TRUE; opts->gen_msym_dir_path = g_strdup (arg + strlen ("msym_dir=")); - } else if (str_begins_with (arg, "direct-pinvoke")) { - opts->direct_pinvoke = TRUE; } else if (str_begins_with (arg, "direct-pinvokes")) { opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (arg + strlen ("direct-pinvokes="))); } else if (str_begins_with (arg, "direct-pinvoke-lists")) { @@ -8643,7 +8640,6 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" bitcode\n"); printf (" data-outfile=\n"); printf (" direct-icalls\n"); - printf (" direct-pinvoke\n"); printf (" direct-pinvokes=\n"); printf (" direct-pinvoke-lists=\n"); printf (" dwarfdebug\n"); @@ -9156,7 +9152,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS); if (acfg->aot_opts.no_direct_calls) flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS); - if (acfg->aot_opts.direct_pinvoke) + if (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) flags = (JitFlags)(flags | JIT_FLAG_DIRECT_PINVOKE); if (acfg->aot_opts.interp) flags = (JitFlags)(flags | JIT_FLAG_INTERP); @@ -10175,7 +10171,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) sym = lookup_icall_symbol_name_aot (method); - else if (llvm_acfg->aot_opts.direct_pinvoke) + else if (mono_aot_direct_pinvoke_enabled_for_method (llvm_acfg, method)) sym = get_pinvoke_import (llvm_acfg, method); } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID) { MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); From 9013dd0a49a2a796b8b1dcd24cfab538a7eac0fc Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 15:50:43 -0500 Subject: [PATCH 06/38] [mono] Add mibc-profile option to help prompt --- src/mono/mono/mini/aot-compiler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 6cd1f9724fede7..3a6df11ffb175a 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -8666,6 +8666,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" outfile=\n"); printf (" profile=\n"); printf (" profile-only\n"); + printf (" mibc-profile=\n"); printf (" print-skipped-methods\n"); printf (" readonly-value=\n"); printf (" save-temps\n"); From 3f6303b33f105c5d4cd1af85256642a0a8b0701e Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 15 Dec 2022 16:00:53 -0500 Subject: [PATCH 07/38] [task] Hook in mono aot direct pinvoke parameters into MonoAOTCompiler task --- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 37 +++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index e6aac82177f048..119b0f03e2f2eb 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -101,10 +101,14 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task public bool UseDirectIcalls { get; set; } /// - /// When this option is specified, P/Invoke methods are invoked directly instead of going through the operating system symbol lookup operation - /// This requires UseStaticLinking=true. + /// PInvokes to call directly. /// - public bool UseDirectPInvoke { get; set; } + public string[] DirectPInvokes { get; set; } = Array.Empty(); + + /// + /// File with list of PInvokes to call directly. + /// + public string[] DirectPInvokeLists { get; set; } = Array.Empty(); /// /// Instructs the AOT compiler to emit DWARF debugging information. @@ -364,9 +368,16 @@ private bool ProcessAndValidateArguments() throw new LogAsErrorException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'."); } - if (UseDirectPInvoke && !UseStaticLinking) + if (DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0) { - throw new LogAsErrorException($"'{nameof(UseDirectPInvoke)}' can only be used with '{nameof(UseStaticLinking)}=true'."); + if (!UseStaticLinking) + throw new LogAsErrorException($"'{nameof(DirectPInvokes)}' and '{nameof(DirectPInvokeLists)}' can only be used with '{nameof(UseStaticLinking)}=true'."); + + foreach (var directPInvokeList in DirectPInvokeLists) + { + if (!File.Exists(directPInvokeList)) + throw new LogAsErrorException($"Could not find file '{directPInvokeList}'."); + } } if (UseStaticLinking && (parsedOutputType == MonoAotOutputType.Library)) @@ -611,6 +622,22 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st aotArgs.Add($"static"); } + if (DirectPInvokes.Length > 0) + { + foreach (var directPInvoke in DirectPInvokes) + { + aotArgs.Add($"direct-pinvokes={directPInvoke}"); + } + } + + if (DirectPInvokeLists.Length > 0) + { + foreach (var directPInvokeList in DirectPInvokeLists) + { + aotArgs.Add($"direct-pinvoke-list={directPInvokeList}"); + } + } + if (UseDwarfDebug) { aotArgs.Add($"dwarfdebug"); From 68f5684decb7399b63ff500e4940a88fec63ce81 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 16 Dec 2022 17:34:27 -0500 Subject: [PATCH 08/38] Address feedback --- src/mono/mono/mini/aot-compiler.c | 84 ++++++++++++++++++------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 3a6df11ffb175a..6d6562da570021 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6161,8 +6161,8 @@ mono_aot_direct_pinvoke_enabled_for_method (MonoAotCompile *acfg, MonoMethod *me { const char *sym = get_pinvoke_import (acfg, method); const char *module_name = acfg->image->module_name; - if (g_hash_table_contains (acfg->direct_pinvokes, module_name)) { - GHashTable *val = g_hash_table_lookup (acfg->direct_pinvokes, module_name); + GHashTable *val; + if (g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { if (!val) return TRUE; return g_hash_table_contains (val, sym); @@ -6226,8 +6226,7 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc /* Cross assembly calls */ return method_is_externally_callable (acfg, patch_info->data.method); } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { - if (mono_aot_direct_pinvoke_enabled_for_method (acfg, patch_info->data.method)) - return TRUE; + return mono_aot_direct_pinvoke_enabled_for_method (acfg, patch_info->data.method); } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (acfg->aot_opts.direct_icalls) return TRUE; @@ -8522,9 +8521,9 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) mini_debug_options.no_seq_points_compact_data = FALSE; opts->gen_msym_dir = TRUE; opts->gen_msym_dir_path = g_strdup (arg + strlen ("msym_dir=")); - } else if (str_begins_with (arg, "direct-pinvokes")) { + } else if (str_begins_with (arg, "direct-pinvokes=")) { opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (arg + strlen ("direct-pinvokes="))); - } else if (str_begins_with (arg, "direct-pinvoke-lists")) { + } else if (str_begins_with (arg, "direct-pinvoke-lists=")) { opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (arg + strlen ("direct-pinvoke-lists="))); } else if (str_begins_with (arg, "direct-icalls")) { opts->direct_icalls = TRUE; @@ -13723,7 +13722,7 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->method_to_cfg = g_hash_table_new (NULL, NULL); acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL); acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free); - acfg->direct_pinvokes = g_hash_table_new_full (NULL, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy); + acfg->direct_pinvokes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy); acfg->method_to_external_icall_symbol_name = g_hash_table_new_full (NULL, NULL, NULL, g_free); acfg->image_hash = g_hash_table_new (NULL, NULL); acfg->image_table = g_ptr_array_new (); @@ -14144,47 +14143,67 @@ init_options (MonoAotOptions *aot_opts) } static gboolean -mono_aot_add_direct_pinvoke (MonoAotCompile *acfg, char *dpi) +process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) { + gboolean processed = TRUE; char *direct_pinvoke = g_strdup (dpi); if (!direct_pinvoke) - return TRUE; + goto early_exit; if (direct_pinvoke[0] == '#') - return TRUE; + goto early_exit; - g_strstrip (direct_pinvoke); - if (!direct_pinvoke) - return TRUE; + if (!g_strstrip (direct_pinvoke)) + goto early_exit; char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", -1); + if (!direct_pinvoke_split) { + processed = FALSE; + aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", dpi); + goto cleanup; + } + char *library_name = g_strdup (direct_pinvoke_split[0]); + if (!library_name) { + processed = FALSE; + aot_printerrf (acfg, "Failed to strdup the module '%s' for the provided 'direct_pinvoke' AOT option '%s'.\n", direct_pinvoke_split[0], dpi); + goto cleanup; + } + if (!direct_pinvoke_split[1]) { g_hash_table_insert (acfg->direct_pinvokes, library_name, NULL); - g_strfreev (direct_pinvoke_split); - return TRUE; + goto cleanup; } + if (direct_pinvoke_split[2]) { aot_printerrf (acfg, "The provided 'direct_pinvoke' AOT option '%s' shouldn't contain multiple '!'\n", dpi); - g_strfreev (direct_pinvoke_split); - return FALSE; + processed = FALSE; + goto cleanup; } char *entrypoint_name = g_strdup (direct_pinvoke_split[1]); - if (g_hash_table_contains (acfg->direct_pinvokes, library_name)) { - GHashTable *val = g_hash_table_lookup (acfg->direct_pinvokes, library_name); - if (!val || g_hash_table_contains (val, entrypoint_name)) { - g_strfreev (direct_pinvoke_split); - return TRUE; - } + if (!entrypoint_name) { + processed = FALSE; + aot_printerrf (acfg, "Failed to strdup the entrypoint '%s' for the provided 'direct_pinvoke' AOT option '%s'.\n", direct_pinvoke_split[1], dpi); + goto cleanup; + } + + GHashTable *val; + if (g_hash_table_lookup_extended (acfg->direct_pinvokes, library_name, NULL, (gpointer *)&val)) { + if (!val || g_hash_table_contains (val, entrypoint_name)) + goto cleanup; g_hash_table_insert (val, entrypoint_name, NULL); } else { - GHashTable *val = g_hash_table_new_full (NULL, g_str_equal, g_free, NULL); + val = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_hash_table_insert (val, entrypoint_name, NULL); g_hash_table_insert (acfg->direct_pinvokes, library_name, val); } + +cleanup: g_strfreev (direct_pinvoke_split); - return TRUE; + +early_exit: + return processed; } static int @@ -14270,21 +14289,16 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) } #endif - if (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) { - if (!acfg->aot_opts.static_link) { - aot_printerrf (acfg, "The 'direct-pinvokes' and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); - return 1; - } - char *any_module = (char *)g_malloc0(2); - any_module[0] = '*'; - g_hash_table_insert (acfg->direct_pinvokes, any_module, NULL); + if ((acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) && !acfg->aot_opts.static_link) { + aot_printerrf (acfg, "The 'direct-pinvokes' and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); + return 1; } gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { GList *l; for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { - added_direct_pinvoke = mono_aot_add_direct_pinvoke (acfg, (char*)l->data); + added_direct_pinvoke = process_direct_pinvokes (acfg, (char*)l->data); if (!added_direct_pinvoke) return 1; } @@ -14303,7 +14317,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) char *line = NULL; size_t line_len = 0; while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { - added_direct_pinvoke = mono_aot_add_direct_pinvoke (acfg, line); + added_direct_pinvoke = process_direct_pinvokes (acfg, line); } fclose (direct_pinvoke_list_file); if (!added_direct_pinvoke) From 5e00533d962c625dee00a6cf2640fb81867d3532 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 16 Dec 2022 17:56:41 -0500 Subject: [PATCH 09/38] Revert "[mono] Deprecate direct_pinvoke boolean flag in favor of direct_pinvokes and direct_pinvoke_lists fields" This reverts commit a8e1c577a53ae2c3772145a3b051a2e2fe4221ca. --- src/mono/mono/mini/aot-compiler.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 6d6562da570021..a9a2f12d2d392a 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -207,6 +207,7 @@ typedef struct MonoAotOptions { gboolean log_instances; gboolean gen_msym_dir; char *gen_msym_dir_path; + gboolean direct_pinvoke; GList *direct_pinvokes; GList *direct_pinvoke_lists; gboolean direct_icalls; @@ -6226,6 +6227,8 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc /* Cross assembly calls */ return method_is_externally_callable (acfg, patch_info->data.method); } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { + if (acfg->aot_opts.direct_pinvoke) + return TRUE; return mono_aot_direct_pinvoke_enabled_for_method (acfg, patch_info->data.method); } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (acfg->aot_opts.direct_icalls) @@ -8525,6 +8528,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (arg + strlen ("direct-pinvokes="))); } else if (str_begins_with (arg, "direct-pinvoke-lists=")) { opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (arg + strlen ("direct-pinvoke-lists="))); + } else if (str_begins_with (arg, "direct-pinvoke")) { + opts->direct_pinvoke = TRUE; } else if (str_begins_with (arg, "direct-icalls")) { opts->direct_icalls = TRUE; } else if (str_begins_with (arg, "direct-extern-calls")) { @@ -8641,6 +8646,7 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) printf (" direct-icalls\n"); printf (" direct-pinvokes=\n"); printf (" direct-pinvoke-lists=\n"); + printf (" direct-pinvoke\n"); printf (" dwarfdebug\n"); printf (" full\n"); printf (" hybrid\n"); @@ -9152,7 +9158,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS); if (acfg->aot_opts.no_direct_calls) flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS); - if (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) + if (acfg->aot_opts.direct_pinvoke || acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) flags = (JitFlags)(flags | JIT_FLAG_DIRECT_PINVOKE); if (acfg->aot_opts.interp) flags = (JitFlags)(flags | JIT_FLAG_INTERP); @@ -10171,7 +10177,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) sym = lookup_icall_symbol_name_aot (method); - else if (mono_aot_direct_pinvoke_enabled_for_method (llvm_acfg, method)) + else if (llvm_acfg->aot_opts.direct_pinvoke || mono_aot_direct_pinvoke_enabled_for_method (llvm_acfg, method)) sym = get_pinvoke_import (llvm_acfg, method); } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID) { MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); From 24eae695ee94ed48a21d4dae3dff7100f0ddca19 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 16 Dec 2022 18:01:35 -0500 Subject: [PATCH 10/38] [task] Add UseDirectPInvoke back into MonoAOTCompiler task --- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 119b0f03e2f2eb..ce2eb8ddb4f58f 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -100,6 +100,12 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task /// public bool UseDirectIcalls { get; set; } + /// + /// When this option is specified, P/Invoke methods are invoked directly instead of going through the operating system symbol lookup operation + /// This requires UseStaticLinking=true. + /// + public bool UseDirectPInvoke { get; set; } + /// /// PInvokes to call directly. /// @@ -368,10 +374,10 @@ private bool ProcessAndValidateArguments() throw new LogAsErrorException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'."); } - if (DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0) + if (UseDirectPInvoke || DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0) { if (!UseStaticLinking) - throw new LogAsErrorException($"'{nameof(DirectPInvokes)}' and '{nameof(DirectPInvokeLists)}' can only be used with '{nameof(UseStaticLinking)}=true'."); + throw new LogAsErrorException($"'{nameof(UseDirectPInvoke)}', '{nameof(DirectPInvokes)}', and '{nameof(DirectPInvokeLists)}' can only be used with '{nameof(UseStaticLinking)}=true'."); foreach (var directPInvokeList in DirectPInvokeLists) { @@ -622,6 +628,11 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st aotArgs.Add($"static"); } + if (UseDirectPInvoke) + { + aotArgs.Add($"direct-pinvoke"); + } + if (DirectPInvokes.Length > 0) { foreach (var directPInvoke in DirectPInvokes) From 8cd5fb4617beab005c5dd77887bf56bc8509244a Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 16 Dec 2022 18:10:28 -0500 Subject: [PATCH 11/38] [mono] Warn if direct-pinvoke argument passed along with direct-pinvokes or direct-pinvoke-list --- src/mono/mono/mini/aot-compiler.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index a9a2f12d2d392a..d92a0a8c811ef3 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14295,10 +14295,12 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) } #endif - if ((acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) && !acfg->aot_opts.static_link) { - aot_printerrf (acfg, "The 'direct-pinvokes' and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); + if ((acfg->aot_opts.direct_pinvoke || acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) && !acfg->aot_opts.static_link) { + aot_printerrf (acfg, "The 'direct-pinvoke' flag, 'direct-pinvokes', and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); return 1; } + if ((acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_list)) + g_warning ("The 'direct-pinvoke' argument trumps specified 'direct-pinvokes' and 'direct-pinvoke-lists' arguments.\n"); gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { GList *l; From 9090c975e83f75cca73ae43fccb40542ba58366a Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Mon, 19 Dec 2022 16:14:41 -0500 Subject: [PATCH 12/38] Address more feedback --- src/mono/mono/mini/aot-compiler.c | 20 +++++++++----------- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index d92a0a8c811ef3..28a10d81897557 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6153,13 +6153,16 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) #endif /* - * mono_aot_direct_pinvoke_enabled_for_method + * is_direct_pinvoke_specified_for_method * * Return whether the method is specified to be directly pinvoked */ static gboolean -mono_aot_direct_pinvoke_enabled_for_method (MonoAotCompile *acfg, MonoMethod *method) +is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) { + if (!acfg->aot_opts.direct_pinvokes && !acfg->aot_opts.direct_pinvoke_lists) + return FALSE; + const char *sym = get_pinvoke_import (acfg, method); const char *module_name = acfg->image->module_name; GHashTable *val; @@ -6229,7 +6232,7 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { if (acfg->aot_opts.direct_pinvoke) return TRUE; - return mono_aot_direct_pinvoke_enabled_for_method (acfg, patch_info->data.method); + return is_direct_pinvoke_specified_for_method (acfg, patch_info->data.method); } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (acfg->aot_opts.direct_icalls) return TRUE; @@ -10177,7 +10180,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) sym = lookup_icall_symbol_name_aot (method); - else if (llvm_acfg->aot_opts.direct_pinvoke || mono_aot_direct_pinvoke_enabled_for_method (llvm_acfg, method)) + else if (llvm_acfg->aot_opts.direct_pinvoke || is_direct_pinvoke_specified_for_method (llvm_acfg, method)) sym = get_pinvoke_import (llvm_acfg, method); } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID) { MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); @@ -14162,7 +14165,7 @@ process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) if (!g_strstrip (direct_pinvoke)) goto early_exit; - char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", -1); + char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); if (!direct_pinvoke_split) { processed = FALSE; aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", dpi); @@ -14181,12 +14184,6 @@ process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) goto cleanup; } - if (direct_pinvoke_split[2]) { - aot_printerrf (acfg, "The provided 'direct_pinvoke' AOT option '%s' shouldn't contain multiple '!'\n", dpi); - processed = FALSE; - goto cleanup; - } - char *entrypoint_name = g_strdup (direct_pinvoke_split[1]); if (!entrypoint_name) { processed = FALSE; @@ -14207,6 +14204,7 @@ process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) cleanup: g_strfreev (direct_pinvoke_split); + g_free (direct_pinvoke); early_exit: return processed; diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index ce2eb8ddb4f58f..258a2d827152eb 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -374,6 +374,11 @@ private bool ProcessAndValidateArguments() throw new LogAsErrorException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'."); } + if (UseDirectPInvoke && (DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0)) + { + Log.LogWarning($"'{nameof(UseDirectPInvoke)}' is enabled and will trump '{nameof(DirectPInvokes)}' and '{nameof(DirectPInvokeLists)}'."); + } + if (UseDirectPInvoke || DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0) { if (!UseStaticLinking) From 8d77b4dd854a01be158114086f5b424ad4d209c1 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Mon, 19 Dec 2022 17:21:35 -0500 Subject: [PATCH 13/38] Fix direct_pinvoke_lists typo --- src/mono/mono/mini/aot-compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 28a10d81897557..700da8aedceed2 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14297,7 +14297,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) aot_printerrf (acfg, "The 'direct-pinvoke' flag, 'direct-pinvokes', and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); return 1; } - if ((acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_list)) + if ((acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists)) g_warning ("The 'direct-pinvoke' argument trumps specified 'direct-pinvokes' and 'direct-pinvoke-lists' arguments.\n"); gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { From 4f217e75754dd0325a6b672292faaca2941cfe32 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Mon, 19 Dec 2022 18:03:29 -0500 Subject: [PATCH 14/38] [mono] Add comments to direct_pinvoke processing --- src/mono/mono/mini/aot-compiler.c | 54 ++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 700da8aedceed2..53e30fdfc5b64f 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6153,9 +6153,10 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) #endif /* - * is_direct_pinvoke_specified_for_method + * is_direct_pinvoke_specified_for_method: * - * Return whether the method is specified to be directly pinvoked + * Returns whether the method is specified to be directly pinvoked based on + * the direct_pinvoke HashTable populated in process_specified_direct_pinvokes. */ static gboolean is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) @@ -14151,8 +14152,46 @@ init_options (MonoAotOptions *aot_opts) aot_opts->clangxx = g_strdup ("clang++"); } +//--------------------------------------------------------------------------------------- +// +// process_specified_direct_pinvokes processes the direct pinvokes and direct pinvoke lists +// the user specifies in the direct-pinvokes and direct-pinvoke-lists options and adds the +// entire module or module and set of entrypoints to the MonoAotCompile instance's +// direct_pinvoke HashTable. +// +// Format of direct_pinvoke HashTable: +// The direct_pinvoke HashTable keys are module names, and its values are HashTables +// corresponding to entrypoint names within the module to be direct pinvoked. +// A NULL value in the direct_pinvoke HashTable is understood to mean that all entrypoints +// from the library are direct. It will overrule previously added HashTable of entrypoints, +// and it will prevent new HashTable of entrypoints from being added. +// +// Processing: +// The specified direct pinvoke, dpi, is ignored if it is empty or considered a comment. +// It is then understood to be in the format of MODULE or MODULE!ENTRYPOINT. +// A direct pinvoke in the form of MODULE is understood as enabling direct pinvoke for all +// entrypoints within the particular module, and will override any previously added set +// of entrypoint names. +// A direct pinvoke in the form of MODULE!ENTRYPOINT is understood as enabling direct pinvoke +// for the specific entrypoint in the module. It will not be added if the entire module +// should be direct pinvoked, but otherwise will be added to a set of entrypoint names for +// the particular module. +// +// Arguments: +// * acfg - the MonoAotCompiler instance +// * dpi (direct pinvoke) - the string passed in specifying a direct pinvoke +// +// Return Value: +// gboolean pertaining to whether or not the direct pinvoke was successfully processed +// processing is considered to have failed if it doesn't add a specified direct pinvoke +// to the MonoAotCompile instance's direct_pinvokes HashTable (excluding comments and +// empty values). +// Note - There are no extensive format checks, and is intended to behave akin to +// ConfigurablePInvokePolicy AddDirectPInvoke in NativeAOT +// + static gboolean -process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) +process_specified_direct_pinvokes (MonoAotCompile *acfg, char *dpi) { gboolean processed = TRUE; char *direct_pinvoke = g_strdup (dpi); @@ -14179,11 +14218,14 @@ process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) goto cleanup; } + // MODULE + // All entrypoints from the library are direct if (!direct_pinvoke_split[1]) { g_hash_table_insert (acfg->direct_pinvokes, library_name, NULL); goto cleanup; } + // MODULE!ENTRYPOINT char *entrypoint_name = g_strdup (direct_pinvoke_split[1]); if (!entrypoint_name) { processed = FALSE; @@ -14193,8 +14235,10 @@ process_direct_pinvokes (MonoAotCompile *acfg, char *dpi) GHashTable *val; if (g_hash_table_lookup_extended (acfg->direct_pinvokes, library_name, NULL, (gpointer *)&val)) { + // All entrypoints from the library are direct if (!val || g_hash_table_contains (val, entrypoint_name)) goto cleanup; + g_hash_table_insert (val, entrypoint_name, NULL); } else { val = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -14304,7 +14348,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) GList *l; for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { - added_direct_pinvoke = process_direct_pinvokes (acfg, (char*)l->data); + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, (char*)l->data); if (!added_direct_pinvoke) return 1; } @@ -14323,7 +14367,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) char *line = NULL; size_t line_len = 0; while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { - added_direct_pinvoke = process_direct_pinvokes (acfg, line); + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, line); } fclose (direct_pinvoke_list_file); if (!added_direct_pinvoke) From 46a9f4587807a322fac0810586058744d6c5ed8f Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Mon, 19 Dec 2022 18:11:40 -0500 Subject: [PATCH 15/38] Fix typo --- src/mono/mono/mini/aot-compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 53e30fdfc5b64f..bf24fa545210ca 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14341,7 +14341,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) aot_printerrf (acfg, "The 'direct-pinvoke' flag, 'direct-pinvokes', and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); return 1; } - if ((acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists)) + if (acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists)) g_warning ("The 'direct-pinvoke' argument trumps specified 'direct-pinvokes' and 'direct-pinvoke-lists' arguments.\n"); gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { From 3e57668ce2b4b3004269f49c4503994f5aef133c Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 11:08:56 -0500 Subject: [PATCH 16/38] [mono] Throw error for incorrect configuration with direct pinvoke flag and specifed arguments --- src/mono/mono/mini/aot-compiler.c | 7 +++++-- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index bf24fa545210ca..880f4cdf27cbf1 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14341,8 +14341,11 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) aot_printerrf (acfg, "The 'direct-pinvoke' flag, 'direct-pinvokes', and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); return 1; } - if (acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists)) - g_warning ("The 'direct-pinvoke' argument trumps specified 'direct-pinvokes' and 'direct-pinvoke-lists' arguments.\n"); + if (acfg->aot_opts.direct_pinvoke && (acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists)) { + aot_printerrf (acfg, "The 'direct-pinvoke' flag trumps specified 'direct-pinvokes' and 'direct-pinvoke-lists' arguments. Unset either the flag or the specific direct pinvoke arguments.\n"); + return 1; + } + gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { GList *l; diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 258a2d827152eb..723a1f17781986 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -376,7 +376,7 @@ private bool ProcessAndValidateArguments() if (UseDirectPInvoke && (DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0)) { - Log.LogWarning($"'{nameof(UseDirectPInvoke)}' is enabled and will trump '{nameof(DirectPInvokes)}' and '{nameof(DirectPInvokeLists)}'."); + throw new LogAsErrorException($"'{nameof(UseDirectPInvoke)}' flag trumps specified '{nameof(DirectPInvokes)}' and '{nameof(DirectPInvokeLists)}' arguments. Unset either the flag or the specific direct pinvoke arguments."); } if (UseDirectPInvoke || DirectPInvokes.Length > 0 || DirectPInvokeLists.Length > 0) From 47923222ed1e5fa49259457f600801f2ecd2d9ef Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 12:16:26 -0500 Subject: [PATCH 17/38] [mono] Bundle direct_pinvoke check into is_direct_pinvoke_specified_for_method --- src/mono/mono/mini/aot-compiler.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 880f4cdf27cbf1..c1e71076ffc8ff 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6161,6 +6161,9 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) static gboolean is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) { + if (acfg->aot_opts.direct_pinvoke) + return TRUE; + if (!acfg->aot_opts.direct_pinvokes && !acfg->aot_opts.direct_pinvoke_lists) return FALSE; @@ -6231,8 +6234,6 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc /* Cross assembly calls */ return method_is_externally_callable (acfg, patch_info->data.method); } else if ((patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL && patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) { - if (acfg->aot_opts.direct_pinvoke) - return TRUE; return is_direct_pinvoke_specified_for_method (acfg, patch_info->data.method); } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (acfg->aot_opts.direct_icalls) @@ -10181,7 +10182,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) sym = lookup_icall_symbol_name_aot (method); - else if (llvm_acfg->aot_opts.direct_pinvoke || is_direct_pinvoke_specified_for_method (llvm_acfg, method)) + else if (is_direct_pinvoke_specified_for_method (llvm_acfg, method)) sym = get_pinvoke_import (llvm_acfg, method); } else if (type == MONO_PATCH_INFO_JIT_ICALL_ID) { MonoJitICallInfo const * const info = mono_find_jit_icall_info ((MonoJitICallId)(gsize)data); From b4f9a44bcd94e7dd0c510018e460e6f81457ec22 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 14:54:50 -0500 Subject: [PATCH 18/38] [mono] Refactor process_specified_direct_pinvokes --- src/mono/mono/mini/aot-compiler.c | 217 ++++++++++++++++++++---------- 1 file changed, 143 insertions(+), 74 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index c1e71076ffc8ff..a59b40c1cab068 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14153,6 +14153,127 @@ init_options (MonoAotOptions *aot_opts) aot_opts->clangxx = g_strdup ("clang++"); } +//--------------------------------------------------------------------------------------- +// +// is_direct_pinvoke_parsable checks whether the direct pinvoke should be parsed into +// the corresponding module and entrypoint names. Empty lines and comments are skipped. +// +// Arguments: +// * direct_pinvoke - the string corresponding to the direct pinvoke to parse +// +// Return Value: +// gboolean pertaining to whether or not the direct pinvoke should be parsed. +// into the respective module_name and entrypoint_name. +// + +static gboolean +is_direct_pinvoke_parsable (char *direct_pinvoke) +{ + if (!direct_pinvoke) + return FALSE; + + if (strlen (direct_pinvoke) == 0) + return FALSE; + + if (direct_pinvoke[0] == '#') + return FALSE; + + return TRUE; +} + +//--------------------------------------------------------------------------------------- +// +// parsed_direct_pinvoke parses the direct pinvoke for the module_name and entrypoint_name +// It presumes that is_direct_pinvoke_parsable (direct_pinvoke) returned true. +// +// Parsing: +// The direct pinvoke is stripped of any leading or trailing whitespace. +// The remaining is assumed to be of the form MODULE or MODULE!ENTRYPOINT. +// The passed in pointers are then reassigned to the corresponding strings. +// +// Arguments: +// * acfg - the MonoAotCompiler instance +// * dpi (direct pinvoke) - the string corresponding to the direct pinvoke to parse +// ** module_name_ptr - the pointer to the module name string +// ** entrypoint_name_ptr - the pointer to the entrypoint name string +// +// Return Value: +// gboolean pertaining to whether or not the direct pinvoke was successfully split +// into the respective module_name and entrypoint_name. +// processing is considered to have failed if there was a problem splitting the direct +// pinvoke with the '!' delimiter. +// + +static gboolean +parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, char **entrypoint_name_ptr) +{ + gboolean parsed = FALSE; + char *direct_pinvoke = g_strdup (dpi); + if (!direct_pinvoke) + goto early_exit; + + if (!g_strstrip (direct_pinvoke)) + goto cleanup; + + char **direct_pinvoke_split = g_strsplit(direct_pinvoke, "!", 2); + if (!direct_pinvoke_split) { + aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", direct_pinvoke); + goto cleanup; + } + + *module_name_ptr = direct_pinvoke_split[0]; + *entrypoint_name_ptr = direct_pinvoke_split[1]; + parsed = TRUE; + g_strfreev(direct_pinvoke_split); + +cleanup: + g_free (direct_pinvoke); + +early_exit: + return parsed; +} + +//--------------------------------------------------------------------------------------- +// +// add_direct_pinvoke adds the module and entrypoint of a specified direct pinvoke to the +// MonoAotCompile instance's HashTable of module/entrypoint entries. +// It is presumed that module_name_ptr and entrypoint_name_ptr point to valid strings. +// It transfers ownership of the module_name and entrypoint_name strings to the HashTable +// +// Arguments: +// * acfg - the MonoAotCompiler instance +// ** module_name_ptr - the pointer to the module name (assumed not NULL) +// ** entrypoint_name_ptr - the pointer to the entrypoint name +// + +static void +add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypoint_name_ptr) +{ + // MODULE + // All entrypoints from the library are direct + if (!*entrypoint_name_ptr) { + g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, NULL); + goto early_exit; + } + + // MODULE!ENTRYPOINT + GHashTable *entrypoints; + if (g_hash_table_lookup_extended (acfg->direct_pinvokes, *module_name_ptr, NULL, (gpointer *)&entrypoints)) { + // All entrypoints from the library are direct + if (!entrypoints) + goto early_exit; + + g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + } else { + entrypoints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); + } + +early_exit: + entrypoints,*module_name_ptr,*entrypoint_name_ptr = NULL; +} + //--------------------------------------------------------------------------------------- // // process_specified_direct_pinvokes processes the direct pinvokes and direct pinvoke lists @@ -14182,77 +14303,19 @@ init_options (MonoAotOptions *aot_opts) // * acfg - the MonoAotCompiler instance // * dpi (direct pinvoke) - the string passed in specifying a direct pinvoke // -// Return Value: -// gboolean pertaining to whether or not the direct pinvoke was successfully processed -// processing is considered to have failed if it doesn't add a specified direct pinvoke -// to the MonoAotCompile instance's direct_pinvokes HashTable (excluding comments and -// empty values). // Note - There are no extensive format checks, and is intended to behave akin to // ConfigurablePInvokePolicy AddDirectPInvoke in NativeAOT // -static gboolean +static void process_specified_direct_pinvokes (MonoAotCompile *acfg, char *dpi) { - gboolean processed = TRUE; - char *direct_pinvoke = g_strdup (dpi); - if (!direct_pinvoke) - goto early_exit; - - if (direct_pinvoke[0] == '#') - goto early_exit; - - if (!g_strstrip (direct_pinvoke)) - goto early_exit; - - char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); - if (!direct_pinvoke_split) { - processed = FALSE; - aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", dpi); - goto cleanup; - } - - char *library_name = g_strdup (direct_pinvoke_split[0]); - if (!library_name) { - processed = FALSE; - aot_printerrf (acfg, "Failed to strdup the module '%s' for the provided 'direct_pinvoke' AOT option '%s'.\n", direct_pinvoke_split[0], dpi); - goto cleanup; - } - - // MODULE - // All entrypoints from the library are direct - if (!direct_pinvoke_split[1]) { - g_hash_table_insert (acfg->direct_pinvokes, library_name, NULL); - goto cleanup; - } - - // MODULE!ENTRYPOINT - char *entrypoint_name = g_strdup (direct_pinvoke_split[1]); - if (!entrypoint_name) { - processed = FALSE; - aot_printerrf (acfg, "Failed to strdup the entrypoint '%s' for the provided 'direct_pinvoke' AOT option '%s'.\n", direct_pinvoke_split[1], dpi); - goto cleanup; - } - - GHashTable *val; - if (g_hash_table_lookup_extended (acfg->direct_pinvokes, library_name, NULL, (gpointer *)&val)) { - // All entrypoints from the library are direct - if (!val || g_hash_table_contains (val, entrypoint_name)) - goto cleanup; - - g_hash_table_insert (val, entrypoint_name, NULL); - } else { - val = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_hash_table_insert (val, entrypoint_name, NULL); - g_hash_table_insert (acfg->direct_pinvokes, library_name, val); + if (is_direct_pinvoke_parsable (dpi)) { + char *module; + char *entrypoint; + if (parsed_direct_pinvoke (acfg, dpi, &module, &entrypoint)) + add_direct_pinvoke (acfg, &module, &entrypoint); } - -cleanup: - g_strfreev (direct_pinvoke_split); - g_free (direct_pinvoke); - -early_exit: - return processed; } static int @@ -14347,15 +14410,11 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) return 1; } - gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { GList *l; - for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { - added_direct_pinvoke = process_specified_direct_pinvokes (acfg, (char*)l->data); - if (!added_direct_pinvoke) - return 1; - } + for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) + process_specified_direct_pinvokes (acfg, (char*)l->data); } if (acfg->aot_opts.direct_pinvoke_lists) { GList *l; @@ -14370,12 +14429,22 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) char *line = NULL; size_t line_len = 0; - while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { - added_direct_pinvoke = process_specified_direct_pinvokes (acfg, line); + while (getline (&line, &line_len, direct_pinvoke_list_file) != -1) { + int len = strlen (line); + + if (len == 0) + continue; + + if (line [len - 1] == '\n') + len--; + + char *direct_pinvoke = g_malloc (sizeof(char) * (len + 1)); + memcpy (direct_pinvoke, line, len); + process_specified_direct_pinvokes (acfg, direct_pinvoke); + g_free (direct_pinvoke); } + fclose (direct_pinvoke_list_file); - if (!added_direct_pinvoke) - return 1; } } From 73b27dfe181a5423e3becd9e164518ade4eedc0a Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 17:00:23 -0500 Subject: [PATCH 19/38] [mono] Readd error propagation in processing specified direct pinvokes [mono] Expand possible results when parsing a direct pinvoke to propagate errors --- src/mono/mono/mini/aot-compiler.c | 70 +++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index a59b40c1cab068..ee66601383f47f 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14181,6 +14181,12 @@ is_direct_pinvoke_parsable (char *direct_pinvoke) return TRUE; } +typedef enum { + DIRECT_PINVOKE_SKIP, + DIRECT_PINVOKE_PARSED, + DIRECT_PINVOKE_ERR, +} DirectPInvokeParsedResult; + //--------------------------------------------------------------------------------------- // // parsed_direct_pinvoke parses the direct pinvoke for the module_name and entrypoint_name @@ -14198,16 +14204,15 @@ is_direct_pinvoke_parsable (char *direct_pinvoke) // ** entrypoint_name_ptr - the pointer to the entrypoint name string // // Return Value: -// gboolean pertaining to whether or not the direct pinvoke was successfully split -// into the respective module_name and entrypoint_name. -// processing is considered to have failed if there was a problem splitting the direct -// pinvoke with the '!' delimiter. +// enum pertaining to whether or not the direct pinvoke entry should be skipped, was +// successfully split into the respective module_name and entrypoint_name, or if +// an error has occurred. // -static gboolean +static DirectPInvokeParsedResult parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, char **entrypoint_name_ptr) { - gboolean parsed = FALSE; + DirectPInvokeParsedResult res = DIRECT_PINVOKE_SKIP; char *direct_pinvoke = g_strdup (dpi); if (!direct_pinvoke) goto early_exit; @@ -14218,19 +14223,20 @@ parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, char **direct_pinvoke_split = g_strsplit(direct_pinvoke, "!", 2); if (!direct_pinvoke_split) { aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", direct_pinvoke); + res = DIRECT_PINVOKE_ERR; goto cleanup; } *module_name_ptr = direct_pinvoke_split[0]; *entrypoint_name_ptr = direct_pinvoke_split[1]; - parsed = TRUE; + res = DIRECT_PINVOKE_PARSED; g_strfreev(direct_pinvoke_split); cleanup: g_free (direct_pinvoke); early_exit: - return parsed; + return res; } //--------------------------------------------------------------------------------------- @@ -14245,15 +14251,20 @@ parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, // ** module_name_ptr - the pointer to the module name (assumed not NULL) // ** entrypoint_name_ptr - the pointer to the entrypoint name // +// Return Value: +// gboolean corresponding to whether or not the direct_pinvoke was successfully added +// or if an error occurred. +// -static void +static gboolean add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypoint_name_ptr) { + gboolean success = TRUE; // MODULE // All entrypoints from the library are direct if (!*entrypoint_name_ptr) { g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, NULL); - goto early_exit; + goto cleanup; } // MODULE!ENTRYPOINT @@ -14261,17 +14272,23 @@ add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypo if (g_hash_table_lookup_extended (acfg->direct_pinvokes, *module_name_ptr, NULL, (gpointer *)&entrypoints)) { // All entrypoints from the library are direct if (!entrypoints) - goto early_exit; + goto cleanup; g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); } else { entrypoints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!entrypoints) { + aot_printerrf (acfg, "Failed to allocate new entrypoints HashTable.\n"); + success = FALSE; + goto cleanup; + } g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); } -early_exit: +cleanup: entrypoints,*module_name_ptr,*entrypoint_name_ptr = NULL; + return success; } //--------------------------------------------------------------------------------------- @@ -14303,19 +14320,30 @@ add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypo // * acfg - the MonoAotCompiler instance // * dpi (direct pinvoke) - the string passed in specifying a direct pinvoke // +// Return Value: +// gboolean corresponding to whether the specified direct pinvoke was successfully +// processed (regardless of it being added or skipped) or if an error occurred. +// // Note - There are no extensive format checks, and is intended to behave akin to // ConfigurablePInvokePolicy AddDirectPInvoke in NativeAOT // -static void +static gboolean process_specified_direct_pinvokes (MonoAotCompile *acfg, char *dpi) { if (is_direct_pinvoke_parsable (dpi)) { char *module; char *entrypoint; - if (parsed_direct_pinvoke (acfg, dpi, &module, &entrypoint)) - add_direct_pinvoke (acfg, &module, &entrypoint); + switch (parsed_direct_pinvoke (acfg, dpi, &module, &entrypoint)) { + case DIRECT_PINVOKE_ERR: + return FALSE; + case DIRECT_PINVOKE_PARSED: + return add_direct_pinvoke (acfg, &module, &entrypoint); + default: + break; + } } + return TRUE; } static int @@ -14410,11 +14438,15 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) return 1; } + gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { GList *l; - for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) + for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { process_specified_direct_pinvokes (acfg, (char*)l->data); + if (!added_direct_pinvoke) + return 1; + } } if (acfg->aot_opts.direct_pinvoke_lists) { GList *l; @@ -14429,7 +14461,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) char *line = NULL; size_t line_len = 0; - while (getline (&line, &line_len, direct_pinvoke_list_file) != -1) { + while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { int len = strlen (line); if (len == 0) @@ -14440,11 +14472,13 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) char *direct_pinvoke = g_malloc (sizeof(char) * (len + 1)); memcpy (direct_pinvoke, line, len); - process_specified_direct_pinvokes (acfg, direct_pinvoke); + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke); g_free (direct_pinvoke); } fclose (direct_pinvoke_list_file); + if (!added_direct_pinvoke) + return 1; } } From 559db698222f56b1eae11c36ce5b0a80dd3c3547 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 17:43:16 -0500 Subject: [PATCH 20/38] Try to properly free and null allocated pointers and memory --- src/mono/mono/mini/aot-compiler.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index ee66601383f47f..6687151f75a2a7 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14220,20 +14220,30 @@ parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, if (!g_strstrip (direct_pinvoke)) goto cleanup; - char **direct_pinvoke_split = g_strsplit(direct_pinvoke, "!", 2); + char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); if (!direct_pinvoke_split) { aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", direct_pinvoke); res = DIRECT_PINVOKE_ERR; goto cleanup; } - *module_name_ptr = direct_pinvoke_split[0]; - *entrypoint_name_ptr = direct_pinvoke_split[1]; res = DIRECT_PINVOKE_PARSED; - g_strfreev(direct_pinvoke_split); + *module_name_ptr = g_strdup (direct_pinvoke_split[0]); + if (!*module_name_ptr) { + aot_printerrf (acfg, "Failed to strdup the module name portion of direct pinvoke '%s'.\n", direct_pinvoke); + res = DIRECT_PINVOKE_ERR; + } + *entrypoint_name_ptr = g_strdup (direct_pinvoke_split[1]); + if (direct_pinvoke_split[1] && !*entrypoint_name_ptr) { + aot_printerrf (acfg, "Failed to strdup the entrypoint name portion of direct pinvoke '%s'.\n", direct_pinvoke); + res = DIRECT_PINVOKE_ERR; + } + g_strfreev (direct_pinvoke_split); + direct_pinvoke_split = NULL; cleanup: g_free (direct_pinvoke); + direct_pinvoke = NULL; early_exit: return res; @@ -14286,8 +14296,12 @@ add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypo g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); } + entrypoints = NULL; cleanup: - entrypoints,*module_name_ptr,*entrypoint_name_ptr = NULL; + g_free (*module_name_ptr); + g_free (*entrypoint_name_ptr); + *module_name_ptr, module_name_ptr = NULL; + *entrypoint_name_ptr, entrypoint_name_ptr = NULL; return success; } From f85a928ed737a0f79ef8cf350050f336762b36f4 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 20 Dec 2022 18:19:48 -0500 Subject: [PATCH 21/38] [mono] Add more error reporting and fix parameter typo --- src/mono/mono/mini/aot-compiler.c | 12 ++++++++---- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 6687151f75a2a7..5469fcb75796f6 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14212,13 +14212,18 @@ typedef enum { static DirectPInvokeParsedResult parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, char **entrypoint_name_ptr) { - DirectPInvokeParsedResult res = DIRECT_PINVOKE_SKIP; + DirectPInvokeParsedResult res = DIRECT_PINVOKE_PARSED; char *direct_pinvoke = g_strdup (dpi); - if (!direct_pinvoke) + if (!direct_pinvoke) { + aot_printerrf (acfg, "Failed to strdup the direct pinvoke '%s'.\n", dpi); + res = DIRECT_PINVOKE_ERR; goto early_exit; + } - if (!g_strstrip (direct_pinvoke)) + if (!g_strstrip (direct_pinvoke)) { + res = DIRECT_PINVOKE_SKIP; goto cleanup; + } char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); if (!direct_pinvoke_split) { @@ -14227,7 +14232,6 @@ parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, goto cleanup; } - res = DIRECT_PINVOKE_PARSED; *module_name_ptr = g_strdup (direct_pinvoke_split[0]); if (!*module_name_ptr) { aot_printerrf (acfg, "Failed to strdup the module name portion of direct pinvoke '%s'.\n", direct_pinvoke); diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 723a1f17781986..88f6516e3858c6 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -650,7 +650,7 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st { foreach (var directPInvokeList in DirectPInvokeLists) { - aotArgs.Add($"direct-pinvoke-list={directPInvokeList}"); + aotArgs.Add($"direct-pinvoke-lists={directPInvokeList}"); } } From bead7445c9ccc1f627cc92e06f6d9639d2c59d87 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Wed, 21 Dec 2022 14:07:03 -0500 Subject: [PATCH 22/38] Address more feedback --- src/mono/mono/mini/aot-compiler.c | 112 ++++++++++++------------------ 1 file changed, 45 insertions(+), 67 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 5469fcb75796f6..3f03f97f7d96c2 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14167,7 +14167,7 @@ init_options (MonoAotOptions *aot_opts) // static gboolean -is_direct_pinvoke_parsable (char *direct_pinvoke) +is_direct_pinvoke_parsable (const char *direct_pinvoke) { if (!direct_pinvoke) return FALSE; @@ -14181,12 +14181,6 @@ is_direct_pinvoke_parsable (char *direct_pinvoke) return TRUE; } -typedef enum { - DIRECT_PINVOKE_SKIP, - DIRECT_PINVOKE_PARSED, - DIRECT_PINVOKE_ERR, -} DirectPInvokeParsedResult; - //--------------------------------------------------------------------------------------- // // parsed_direct_pinvoke parses the direct pinvoke for the module_name and entrypoint_name @@ -14199,7 +14193,7 @@ typedef enum { // // Arguments: // * acfg - the MonoAotCompiler instance -// * dpi (direct pinvoke) - the string corresponding to the direct pinvoke to parse +// * direct pinvoke - the string corresponding to the direct pinvoke to parse // ** module_name_ptr - the pointer to the module name string // ** entrypoint_name_ptr - the pointer to the entrypoint name string // @@ -14209,48 +14203,36 @@ typedef enum { // an error has occurred. // -static DirectPInvokeParsedResult -parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, char **entrypoint_name_ptr) +static gboolean +parsed_direct_pinvoke (MonoAotCompile *acfg, char *direct_pinvoke, char **module_name_ptr, char **entrypoint_name_ptr) { - DirectPInvokeParsedResult res = DIRECT_PINVOKE_PARSED; - char *direct_pinvoke = g_strdup (dpi); - if (!direct_pinvoke) { - aot_printerrf (acfg, "Failed to strdup the direct pinvoke '%s'.\n", dpi); - res = DIRECT_PINVOKE_ERR; - goto early_exit; - } - - if (!g_strstrip (direct_pinvoke)) { - res = DIRECT_PINVOKE_SKIP; - goto cleanup; - } + gboolean parsed = TRUE; char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); if (!direct_pinvoke_split) { aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", direct_pinvoke); - res = DIRECT_PINVOKE_ERR; - goto cleanup; + parsed = FALSE; + goto early_exit; } *module_name_ptr = g_strdup (direct_pinvoke_split[0]); if (!*module_name_ptr) { aot_printerrf (acfg, "Failed to strdup the module name portion of direct pinvoke '%s'.\n", direct_pinvoke); - res = DIRECT_PINVOKE_ERR; + parsed = FALSE; } + + // ENTRYPOINT can be NULL if Direct PInvoke is just MODULE *entrypoint_name_ptr = g_strdup (direct_pinvoke_split[1]); if (direct_pinvoke_split[1] && !*entrypoint_name_ptr) { aot_printerrf (acfg, "Failed to strdup the entrypoint name portion of direct pinvoke '%s'.\n", direct_pinvoke); - res = DIRECT_PINVOKE_ERR; + parsed = FALSE; } + g_strfreev (direct_pinvoke_split); direct_pinvoke_split = NULL; -cleanup: - g_free (direct_pinvoke); - direct_pinvoke = NULL; - early_exit: - return res; + return parsed; } //--------------------------------------------------------------------------------------- @@ -14258,7 +14240,9 @@ parsed_direct_pinvoke (MonoAotCompile *acfg, char *dpi, char **module_name_ptr, // add_direct_pinvoke adds the module and entrypoint of a specified direct pinvoke to the // MonoAotCompile instance's HashTable of module/entrypoint entries. // It is presumed that module_name_ptr and entrypoint_name_ptr point to valid strings. -// It transfers ownership of the module_name and entrypoint_name strings to the HashTable +// It transfers ownership of the module_name and entrypoint_name strings data to the HashTable +// This function takes ownership of the module and entrypoint strings pointers regardless of +// success or failure (in which it frees the memory) and sets them to NULL. // // Arguments: // * acfg - the MonoAotCompiler instance @@ -14274,38 +14258,31 @@ static gboolean add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypoint_name_ptr) { gboolean success = TRUE; - // MODULE - // All entrypoints from the library are direct - if (!*entrypoint_name_ptr) { - g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, NULL); - goto cleanup; - } - - // MODULE!ENTRYPOINT GHashTable *entrypoints; + // If there is an entry for the module if (g_hash_table_lookup_extended (acfg->direct_pinvokes, *module_name_ptr, NULL, (gpointer *)&entrypoints)) { - // All entrypoints from the library are direct - if (!entrypoints) - goto cleanup; - - g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + // Not all entrypoints are direct, if specifying a new entrypoint + if (entrypoints && *entrypoint_name_ptr && !g_hash_table_contains (entrypoints, *entrypoint_name_ptr)) + g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + // New entry for module, All entrypoints are direct + } else if (!*entrypoint_name_ptr) { + g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, NULL); + // New entry for module, specifying an entrypoint } else { entrypoints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (!entrypoints) { aot_printerrf (acfg, "Failed to allocate new entrypoints HashTable.\n"); + g_free (*module_name_ptr); + g_free (*entrypoint_name_ptr); success = FALSE; - goto cleanup; + } else { + g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); } - g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); - g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); } - entrypoints = NULL; -cleanup: - g_free (*module_name_ptr); - g_free (*entrypoint_name_ptr); - *module_name_ptr, module_name_ptr = NULL; - *entrypoint_name_ptr, entrypoint_name_ptr = NULL; + *module_name_ptr = NULL; + *entrypoint_name_ptr = NULL; return success; } @@ -14347,21 +14324,22 @@ add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypo // static gboolean -process_specified_direct_pinvokes (MonoAotCompile *acfg, char *dpi) +process_specified_direct_pinvokes (MonoAotCompile *acfg, const char *dpi) { - if (is_direct_pinvoke_parsable (dpi)) { - char *module; - char *entrypoint; - switch (parsed_direct_pinvoke (acfg, dpi, &module, &entrypoint)) { - case DIRECT_PINVOKE_ERR: - return FALSE; - case DIRECT_PINVOKE_PARSED: - return add_direct_pinvoke (acfg, &module, &entrypoint); - default: - break; + gboolean result = FALSE; + char *direct_pinvoke = g_strdup (dpi); + if (direct_pinvoke && g_strstrip (direct_pinvoke)) { + if (is_direct_pinvoke_parsable (direct_pinvoke)) { + char *module; + char *entrypoint; + if (parsed_direct_pinvoke (acfg, direct_pinvoke, &module, &entrypoint)) + result = add_direct_pinvoke (acfg, &module, &entrypoint); + } else { + result = TRUE; } } - return TRUE; + g_free (direct_pinvoke); + return result; } static int @@ -14488,7 +14466,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) if (line [len - 1] == '\n') len--; - char *direct_pinvoke = g_malloc (sizeof(char) * (len + 1)); + char *direct_pinvoke = g_malloc0 (sizeof(char) * (len + 1)); memcpy (direct_pinvoke, line, len); added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke); g_free (direct_pinvoke); From 18d8d0aedd0ecfea4277815c27d8daad317f6ee4 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 22 Dec 2022 16:53:48 -0500 Subject: [PATCH 23/38] Address more feedback --- src/mono/mono/mini/aot-compiler.c | 75 +++++++++++++++++-------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 3f03f97f7d96c2..5491b02e9cebd7 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -9061,6 +9061,12 @@ add_referenced_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, int depth) } } +static inline gboolean +is_direct_pinvoke_enabled (const MonoAotCompile *acfg) +{ + return acfg->aot_opts.direct_pinvoke || acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists; +} + /* * compile_method: * @@ -9163,7 +9169,7 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) flags = (JitFlags)(flags | JIT_FLAG_LLVM_ONLY | JIT_FLAG_EXPLICIT_NULL_CHECKS); if (acfg->aot_opts.no_direct_calls) flags = (JitFlags)(flags | JIT_FLAG_NO_DIRECT_ICALLS); - if (acfg->aot_opts.direct_pinvoke || acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) + if (is_direct_pinvoke_enabled (acfg)) flags = (JitFlags)(flags | JIT_FLAG_DIRECT_PINVOKE); if (acfg->aot_opts.interp) flags = (JitFlags)(flags | JIT_FLAG_INTERP); @@ -14204,34 +14210,34 @@ is_direct_pinvoke_parsable (const char *direct_pinvoke) // static gboolean -parsed_direct_pinvoke (MonoAotCompile *acfg, char *direct_pinvoke, char **module_name_ptr, char **entrypoint_name_ptr) +parsed_direct_pinvoke (MonoAotCompile *acfg, const char *direct_pinvoke, char **module_name_ptr, char **entrypoint_name_ptr) { - gboolean parsed = TRUE; + gboolean parsed = FALSE; + + *module_name_ptr = NULL; + *entrypoint_name_ptr = NULL; char **direct_pinvoke_split = g_strsplit (direct_pinvoke, "!", 2); - if (!direct_pinvoke_split) { - aot_printerrf (acfg, "Failed to split the provided 'direct_pinvoke' AOT option '%s' with delimiter '!'\n", direct_pinvoke); - parsed = FALSE; - goto early_exit; - } + if (direct_pinvoke_split) { + *module_name_ptr = g_strdup (direct_pinvoke_split [0]); + *entrypoint_name_ptr = g_strdup (direct_pinvoke_split [1]); - *module_name_ptr = g_strdup (direct_pinvoke_split[0]); - if (!*module_name_ptr) { - aot_printerrf (acfg, "Failed to strdup the module name portion of direct pinvoke '%s'.\n", direct_pinvoke); - parsed = FALSE; - } + // ENTRYPOINT can be NULL if Direct PInvoke is just MODULE + if (*module_name_ptr && (!direct_pinvoke_split [1] || *entrypoint_name_ptr)) + parsed = TRUE; - // ENTRYPOINT can be NULL if Direct PInvoke is just MODULE - *entrypoint_name_ptr = g_strdup (direct_pinvoke_split[1]); - if (direct_pinvoke_split[1] && !*entrypoint_name_ptr) { - aot_printerrf (acfg, "Failed to strdup the entrypoint name portion of direct pinvoke '%s'.\n", direct_pinvoke); - parsed = FALSE; + g_strfreev (direct_pinvoke_split); } - g_strfreev (direct_pinvoke_split); - direct_pinvoke_split = NULL; + if (!parsed) { + aot_printerrf (acfg, "Failed to parse the specified direct pinvoke '%s'. 'g_strsplit' or 'g_strdup' failed, possible due to insufficient memory.\n", direct_pinvoke); + g_free (*module_name_ptr); + *module_name_ptr = NULL; + + g_free (*entrypoint_name_ptr); + *entrypoint_name_ptr = NULL; + } -early_exit: return parsed; } @@ -14262,25 +14268,31 @@ add_direct_pinvoke (MonoAotCompile *acfg, char **module_name_ptr, char **entrypo // If there is an entry for the module if (g_hash_table_lookup_extended (acfg->direct_pinvokes, *module_name_ptr, NULL, (gpointer *)&entrypoints)) { // Not all entrypoints are direct, if specifying a new entrypoint - if (entrypoints && *entrypoint_name_ptr && !g_hash_table_contains (entrypoints, *entrypoint_name_ptr)) + if (entrypoints && *entrypoint_name_ptr && !g_hash_table_contains (entrypoints, *entrypoint_name_ptr)) { g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); + *entrypoint_name_ptr = NULL; + } // New entry for module, All entrypoints are direct } else if (!*entrypoint_name_ptr) { g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, NULL); + *module_name_ptr = NULL; // New entry for module, specifying an entrypoint } else { entrypoints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (!entrypoints) { aot_printerrf (acfg, "Failed to allocate new entrypoints HashTable.\n"); - g_free (*module_name_ptr); - g_free (*entrypoint_name_ptr); success = FALSE; } else { g_hash_table_insert (entrypoints, *entrypoint_name_ptr, NULL); g_hash_table_insert (acfg->direct_pinvokes, *module_name_ptr, entrypoints); + *entrypoint_name_ptr = NULL; + *module_name_ptr = NULL; } } + g_free (*module_name_ptr); + g_free (*entrypoint_name_ptr); + *module_name_ptr = NULL; *entrypoint_name_ptr = NULL; return success; @@ -14330,8 +14342,7 @@ process_specified_direct_pinvokes (MonoAotCompile *acfg, const char *dpi) char *direct_pinvoke = g_strdup (dpi); if (direct_pinvoke && g_strstrip (direct_pinvoke)) { if (is_direct_pinvoke_parsable (direct_pinvoke)) { - char *module; - char *entrypoint; + char *module, *entrypoint; if (parsed_direct_pinvoke (acfg, direct_pinvoke, &module, &entrypoint)) result = add_direct_pinvoke (acfg, &module, &entrypoint); } else { @@ -14425,7 +14436,7 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) } #endif - if ((acfg->aot_opts.direct_pinvoke || acfg->aot_opts.direct_pinvokes || acfg->aot_opts.direct_pinvoke_lists) && !acfg->aot_opts.static_link) { + if ((is_direct_pinvoke_enabled (acfg)) && !acfg->aot_opts.static_link) { aot_printerrf (acfg, "The 'direct-pinvoke' flag, 'direct-pinvokes', and 'direct-pinvoke-lists' AOT options also require the 'static' AOT option.\n"); return 1; } @@ -14436,18 +14447,14 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { - GList *l; - - for (l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { - process_specified_direct_pinvokes (acfg, (char*)l->data); + for (GList *l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, (char*)l->data); if (!added_direct_pinvoke) return 1; } } if (acfg->aot_opts.direct_pinvoke_lists) { - GList *l; - - for (l = acfg->aot_opts.direct_pinvoke_lists; l; l = l->next) { + for (GList *l = acfg->aot_opts.direct_pinvoke_lists; l; l = l->next) { char *direct_pinvoke_list = (char*)l->data; FILE *direct_pinvoke_list_file = fopen (direct_pinvoke_list, "r"); if (!direct_pinvoke_list_file) { From e51e4609b166d60731261d140a588d211341df8f Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 3 Jan 2023 22:38:38 -0500 Subject: [PATCH 24/38] [mono] Read direct pinvoke input file using fgets --- src/mono/mono/mini/aot-compiler.c | 51 +++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 5491b02e9cebd7..4d60d10d59d8e8 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14462,23 +14462,54 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) return 1; } - char *line = NULL; - size_t line_len = 0; - while (getline (&line, &line_len, direct_pinvoke_list_file) != -1 && added_direct_pinvoke) { - int len = strlen (line); + if (fseek (direct_pinvoke_list_file, 0L, SEEK_END)) { + aot_printerrf (acfg, "Failed to seek end of provided 'direct-pinvoke-list' '%s', fseek SEEK_END failed.\n", direct_pinvoke_list); + fclose (direct_pinvoke_list_file); + return 1; + } + + size_t file_len = ftell (direct_pinvoke_list_file); + + if (fseek (direct_pinvoke_list_file, 0L, SEEK_SET)) { + aot_printerrf (acfg, "Failed to seek start of provided 'direct-pinvoke-list' '%s', fseek SEEK_SET failed.\n", direct_pinvoke_list); + fclose (direct_pinvoke_list_file); + return 1; + } + + // Allocate enough memory to read the entire file + // Other than that, the contents doesn't really matter, + // and it won't match the contents of direct_pinvoke_list_file + // when each direct_pinvoke read are cleaned of \n and whitespaces + char *direct_pinvokes = g_malloc0 (file_len * sizeof (char)); + // Ensures that + size_t offset = 0; + + while (added_direct_pinvoke && fgets (&direct_pinvokes [offset], (int)(file_len - offset + 1), direct_pinvoke_list_file)) { + char *direct_pinvoke = &direct_pinvokes [offset]; + size_t len = strlen (direct_pinvoke); + // No characters have been read from fgets if (len == 0) - continue; + break; + + offset += len; + + // Remove newline read by fgets by null terminating instead + if (len >= 0 && direct_pinvoke [len - 1] == '\n') + direct_pinvoke [len - 1] = '\0'; - if (line [len - 1] == '\n') - len--; + // Strip whitespace from line read + g_strstrip (direct_pinvoke); + + // Skip empty direct_pinvokes + if (direct_pinvoke [0] == '\0') + continue; - char *direct_pinvoke = g_malloc0 (sizeof(char) * (len + 1)); - memcpy (direct_pinvoke, line, len); added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke); - g_free (direct_pinvoke); } + g_free (direct_pinvokes); + fclose (direct_pinvoke_list_file); if (!added_direct_pinvoke) return 1; From ef0330f44a27212f71a30f487000361ff0abdc49 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 10 Jan 2023 10:54:39 -0500 Subject: [PATCH 25/38] [mono] Read direct pinvoke lists file via g_file_get_contents --- src/mono/mono/mini/aot-compiler.c | 61 +++++++------------------------ 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 4d60d10d59d8e8..35dfc1566337cc 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -14448,69 +14448,36 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) gboolean added_direct_pinvoke = TRUE; if (acfg->aot_opts.direct_pinvokes) { for (GList *l = acfg->aot_opts.direct_pinvokes; l; l = l->next) { - added_direct_pinvoke = process_specified_direct_pinvokes (acfg, (char*)l->data); + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, (const char*)l->data); if (!added_direct_pinvoke) return 1; } } if (acfg->aot_opts.direct_pinvoke_lists) { for (GList *l = acfg->aot_opts.direct_pinvoke_lists; l; l = l->next) { - char *direct_pinvoke_list = (char*)l->data; - FILE *direct_pinvoke_list_file = fopen (direct_pinvoke_list, "r"); - if (!direct_pinvoke_list_file) { - aot_printerrf (acfg, "Failed to open the provided 'direct-pinvoke-list' '%s', fopen failed.\n", direct_pinvoke_list); - return 1; - } + const char *direct_pinvoke_list = (const char*)l->data; + gchar *direct_pinvoke_list_content = NULL; + gchar *direct_pinvoke_list_content_ctx = NULL; + gchar *direct_pinvoke_list_content_line = NULL; - if (fseek (direct_pinvoke_list_file, 0L, SEEK_END)) { - aot_printerrf (acfg, "Failed to seek end of provided 'direct-pinvoke-list' '%s', fseek SEEK_END failed.\n", direct_pinvoke_list); - fclose (direct_pinvoke_list_file); + if (!g_file_get_contents (direct_pinvoke_list, &direct_pinvoke_list_content, NULL, NULL)) { + aot_printerrf (acfg, "Failed to open and read the provided 'direct-pinvoke-list' '%s'.\n", direct_pinvoke_list); return 1; } - size_t file_len = ftell (direct_pinvoke_list_file); - - if (fseek (direct_pinvoke_list_file, 0L, SEEK_SET)) { - aot_printerrf (acfg, "Failed to seek start of provided 'direct-pinvoke-list' '%s', fseek SEEK_SET failed.\n", direct_pinvoke_list); - fclose (direct_pinvoke_list_file); - return 1; - } - - // Allocate enough memory to read the entire file - // Other than that, the contents doesn't really matter, - // and it won't match the contents of direct_pinvoke_list_file - // when each direct_pinvoke read are cleaned of \n and whitespaces - char *direct_pinvokes = g_malloc0 (file_len * sizeof (char)); - // Ensures that - size_t offset = 0; - - while (added_direct_pinvoke && fgets (&direct_pinvokes [offset], (int)(file_len - offset + 1), direct_pinvoke_list_file)) { - char *direct_pinvoke = &direct_pinvokes [offset]; - size_t len = strlen (direct_pinvoke); - - // No characters have been read from fgets - if (len == 0) - break; - - offset += len; - - // Remove newline read by fgets by null terminating instead - if (len >= 0 && direct_pinvoke [len - 1] == '\n') - direct_pinvoke [len - 1] = '\0'; - + direct_pinvoke_list_content_line = strtok_r (direct_pinvoke_list_content, "\n", &direct_pinvoke_list_content_ctx); + while (direct_pinvoke_list_content_line && added_direct_pinvoke) { // Strip whitespace from line read - g_strstrip (direct_pinvoke); + g_strstrip (direct_pinvoke_list_content_line); // Skip empty direct_pinvokes - if (direct_pinvoke [0] == '\0') - continue; + if (direct_pinvoke_list_content_line [0] != '\0') + added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke_list_content_line); - added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke); + direct_pinvoke_list_content_line = strtok_r (NULL, "\n", &direct_pinvoke_list_content_ctx); } - g_free (direct_pinvokes); - - fclose (direct_pinvoke_list_file); + g_free (direct_pinvoke_list_content); if (!added_direct_pinvoke) return 1; } From 85799e44d7066e8e7028f0574e05a7622d585162 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Wed, 11 Jan 2023 15:27:49 -0500 Subject: [PATCH 26/38] [mono] ALlow multiple values for direct-pinvokes and direct-pinvoke-lists --- src/mono/mono/mini/aot-compiler.c | 24 ++++++++++++++++---- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 10 ++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 35dfc1566337cc..c98ae4ad187c87 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -8530,9 +8530,23 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->gen_msym_dir = TRUE; opts->gen_msym_dir_path = g_strdup (arg + strlen ("msym_dir=")); } else if (str_begins_with (arg, "direct-pinvokes=")) { - opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (arg + strlen ("direct-pinvokes="))); + char *direct_pinvokes = g_strdup (arg + strlen ("direct-pinvokes=")); + gchar *direct_pinvoke_ctx = NULL; + gchar *direct_pinvoke = strtok_r (direct_pinvokes, ",", direct_pinvoke_ctx); + while (direct_pinvoke) { + opts->direct_pinvokes = g_list_append (opts->direct_pinvoke, g_strdup (direct_pinvoke)); + direct_pinvoke = strtok_r (NULL, ",", direct_pinvoke_ctx); + } + g_free (direct_pinvokes); } else if (str_begins_with (arg, "direct-pinvoke-lists=")) { - opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (arg + strlen ("direct-pinvoke-lists="))); + char *direct_pinvoke_lists = g_strdup (arg + strlen ("direct-pinvoke-lists=")); + gchar *direct_pinvoke_list_ctx = NULL; + gchar *direct_pinvoke_list = strtok_r (direct_pinvoke_lists, ",", direct_pinvoke_list_ctx); + while (direct_pinvoke_list) { + opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (direct_pinvoke_list)); + direct_pinvoke_list = strtok_r (NULL, ",", direct_pinvoke_list_ctx); + } + g_free (direct_pinvoke_lists); } else if (str_begins_with (arg, "direct-pinvoke")) { opts->direct_pinvoke = TRUE; } else if (str_begins_with (arg, "direct-icalls")) { @@ -14178,7 +14192,7 @@ is_direct_pinvoke_parsable (const char *direct_pinvoke) if (!direct_pinvoke) return FALSE; - if (strlen (direct_pinvoke) == 0) + if (direct_pinvoke[0] == '\0') return FALSE; if (direct_pinvoke[0] == '#') @@ -14470,8 +14484,8 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) // Strip whitespace from line read g_strstrip (direct_pinvoke_list_content_line); - // Skip empty direct_pinvokes - if (direct_pinvoke_list_content_line [0] != '\0') + // Skip empty direct_pinvokes and comments + if (direct_pinvoke_list_content_line [0] != '\0' && direct_pinvoke_list_content_line [0] != '#') added_direct_pinvoke = process_specified_direct_pinvokes (acfg, direct_pinvoke_list_content_line); direct_pinvoke_list_content_line = strtok_r (NULL, "\n", &direct_pinvoke_list_content_ctx); diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 88f6516e3858c6..c1b92f52ac7f32 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -640,18 +640,12 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st if (DirectPInvokes.Length > 0) { - foreach (var directPInvoke in DirectPInvokes) - { - aotArgs.Add($"direct-pinvokes={directPInvoke}"); - } + aotArgs.Add($"direct-pinvokes={string.Join(",", DirectPInvokes)}"); } if (DirectPInvokeLists.Length > 0) { - foreach (var directPInvokeList in DirectPInvokeLists) - { - aotArgs.Add($"direct-pinvoke-lists={directPInvokeList}"); - } + aotArgs.Add($"direct-pinvoke-lists={string.Join(",", DirectPInvokeLists)}"); } if (UseDwarfDebug) From 2f8bba0b92a259134c0a2caa1f4cfcc150bc36f3 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 12 Jan 2023 16:00:31 -0500 Subject: [PATCH 27/38] [mono] Use ITaskItem for DirectPInvoke parameters and separate multivalue aot args by semicolon --- src/mono/mono/mini/aot-compiler.c | 10 +++++----- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 14 +++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index c98ae4ad187c87..11f0f405f9c0f9 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -8532,19 +8532,19 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) } else if (str_begins_with (arg, "direct-pinvokes=")) { char *direct_pinvokes = g_strdup (arg + strlen ("direct-pinvokes=")); gchar *direct_pinvoke_ctx = NULL; - gchar *direct_pinvoke = strtok_r (direct_pinvokes, ",", direct_pinvoke_ctx); + gchar *direct_pinvoke = strtok_r (direct_pinvokes, ";", &direct_pinvoke_ctx); while (direct_pinvoke) { - opts->direct_pinvokes = g_list_append (opts->direct_pinvoke, g_strdup (direct_pinvoke)); - direct_pinvoke = strtok_r (NULL, ",", direct_pinvoke_ctx); + opts->direct_pinvokes = g_list_append (opts->direct_pinvokes, g_strdup (direct_pinvoke)); + direct_pinvoke = strtok_r (NULL, ";", &direct_pinvoke_ctx); } g_free (direct_pinvokes); } else if (str_begins_with (arg, "direct-pinvoke-lists=")) { char *direct_pinvoke_lists = g_strdup (arg + strlen ("direct-pinvoke-lists=")); gchar *direct_pinvoke_list_ctx = NULL; - gchar *direct_pinvoke_list = strtok_r (direct_pinvoke_lists, ",", direct_pinvoke_list_ctx); + gchar *direct_pinvoke_list = strtok_r (direct_pinvoke_lists, ";", &direct_pinvoke_list_ctx); while (direct_pinvoke_list) { opts->direct_pinvoke_lists = g_list_append (opts->direct_pinvoke_lists, g_strdup (direct_pinvoke_list)); - direct_pinvoke_list = strtok_r (NULL, ",", direct_pinvoke_list_ctx); + direct_pinvoke_list = strtok_r (NULL, ";", &direct_pinvoke_list_ctx); } g_free (direct_pinvoke_lists); } else if (str_begins_with (arg, "direct-pinvoke")) { diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index c1b92f52ac7f32..46753a2c3cb90a 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -109,12 +109,12 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task /// /// PInvokes to call directly. /// - public string[] DirectPInvokes { get; set; } = Array.Empty(); + public ITaskItem[] DirectPInvokes { get; set; } = Array.Empty(); /// /// File with list of PInvokes to call directly. /// - public string[] DirectPInvokeLists { get; set; } = Array.Empty(); + public ITaskItem[] DirectPInvokeLists { get; set; } = Array.Empty(); /// /// Instructs the AOT compiler to emit DWARF debugging information. @@ -386,7 +386,7 @@ private bool ProcessAndValidateArguments() foreach (var directPInvokeList in DirectPInvokeLists) { - if (!File.Exists(directPInvokeList)) + if (!File.Exists(directPInvokeList.GetMetadata("FullPath"))) throw new LogAsErrorException($"Could not find file '{directPInvokeList}'."); } } @@ -640,12 +640,16 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st if (DirectPInvokes.Length > 0) { - aotArgs.Add($"direct-pinvokes={string.Join(",", DirectPInvokes)}"); + var directPInvokesSB = new StringBuilder("direct-pinvokes="); + Array.ForEach(DirectPInvokes, directPInvokeItem => directPInvokesSB.Append($"{directPInvokeItem.GetMetadata("Identity")};")); + aotArgs.Add(directPInvokesSB.ToString()); } if (DirectPInvokeLists.Length > 0) { - aotArgs.Add($"direct-pinvoke-lists={string.Join(",", DirectPInvokeLists)}"); + var directPInvokeListsSB = new StringBuilder("direct-pinvoke-lists="); + Array.ForEach(DirectPInvokeLists, directPInvokeListItem => directPInvokeListsSB.Append($"{directPInvokeListItem.GetMetadata("FullPath")};")); + aotArgs.Add(directPInvokeListsSB.ToString()); } if (UseDwarfDebug) From 31726dd66000b3da1200f7680c39841bdae9f90f Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 12 Jan 2023 16:38:02 -0500 Subject: [PATCH 28/38] [mono] Free MonoAotOptions --- src/mono/mono/mini/aot-compiler.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 11f0f405f9c0f9..88ecfa1c8f7b88 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -13797,6 +13797,33 @@ got_info_free (GotInfo *info) g_ptr_array_free (info->got_patches, TRUE); } +static void +aot_opts_free (MonoAotOptions *aot_opts) +{ + g_free (aot_opts->outfile); + g_free (aot_opts->llvm_outfile); + g_free (aot_opts->data_outfile); + g_list_free (aot_opts->profile_files); + g_list_free (aot_opts->mibc_profile_files); + g_free (aot_opts->gen_msym_dir_path); + g_list_free (aot_opts->direct_pinvokes); + g_list_free (aot_opts->direct_pinvoke_lists); + g_free (aot_opts->dedup_include); + g_free (aot_opts->tool_prefix); + g_free (aot_opts->ld_flags); + g_free (aot_opts->ld_name); + g_free (aot_opts->mtriple); + g_free (aot_opts->llvm_path); + g_free (aot_opts->temp_path); + g_free (aot_opts->instances_logfile_path); + g_free (aot_opts->logfile); + g_free (aot_opts->llvm_opts); + g_free (aot_opts->llvm_llc); + g_free (aot_opts->llvm_cpu_attr); + g_free (aot_opts->clangxx); + g_free (aot_opts->depfile); +} + static void acfg_free (MonoAotCompile *acfg) { @@ -13839,6 +13866,7 @@ acfg_free (MonoAotCompile *acfg) got_info_free (&acfg->llvm_got_info); arch_free_unwind_info_section_cache (acfg); mono_mempool_destroy (acfg->mempool); + aot_opts_free (&acfg->aot_opts); method_to_external_icall_symbol_name = NULL; g_free (acfg); From 63304841c5a1c1d6e0aa2204875186f5c8b3853c Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 13 Jan 2023 11:21:27 -0500 Subject: [PATCH 29/38] [mono] Manually free each GList in aot_opts_free and cleanup MonoAOTCompiler --- src/mono/mono/mini/aot-compiler.c | 8 ++++++++ src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 88ecfa1c8f7b88..d3dc3fb3787da5 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -13803,10 +13803,18 @@ aot_opts_free (MonoAotOptions *aot_opts) g_free (aot_opts->outfile); g_free (aot_opts->llvm_outfile); g_free (aot_opts->data_outfile); + for (GList *elem = aot_opts->profile_files; elem; elem = elem->next) + g_free (elem->data); g_list_free (aot_opts->profile_files); + for (GList *elem = aot_opts->mibc_profile_files; elem; elem = elem->next) + g_free (elem->data); g_list_free (aot_opts->mibc_profile_files); g_free (aot_opts->gen_msym_dir_path); + for (GList *elem = aot_opts->direct_pinvokes; elem; elem = elem->next) + g_free (elem->data); g_list_free (aot_opts->direct_pinvokes); + for (GList *elem = aot_opts->direct_pinvoke_lists; elem; elem = elem->next) + g_free (elem->data); g_list_free (aot_opts->direct_pinvoke_lists); g_free (aot_opts->dedup_include); g_free (aot_opts->tool_prefix); diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 46753a2c3cb90a..1a8cccc7c5826d 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -112,7 +112,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task public ITaskItem[] DirectPInvokes { get; set; } = Array.Empty(); /// - /// File with list of PInvokes to call directly. + /// List of files with list of PInvokes to call directly. /// public ITaskItem[] DirectPInvokeLists { get; set; } = Array.Empty(); @@ -641,7 +641,7 @@ private PrecompileArguments GetPrecompileArgumentsFor(ITaskItem assemblyItem, st if (DirectPInvokes.Length > 0) { var directPInvokesSB = new StringBuilder("direct-pinvokes="); - Array.ForEach(DirectPInvokes, directPInvokeItem => directPInvokesSB.Append($"{directPInvokeItem.GetMetadata("Identity")};")); + Array.ForEach(DirectPInvokes, directPInvokeItem => directPInvokesSB.Append($"{directPInvokeItem.ItemSpec};")); aotArgs.Add(directPInvokesSB.ToString()); } From 18e53b683abe24873648cf29098877df973a70de Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 19 Jan 2023 01:23:51 -0500 Subject: [PATCH 30/38] [mono] Extend get_pinvoke_import to grab scope as well --- src/mono/mono/mini/aot-compiler.c | 76 +++++++++++++++++++------------ 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index d3dc3fb3787da5..4aac22c6ea7743 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -308,7 +308,7 @@ typedef struct MonoAotCompile { GHashTable *image_hash; GHashTable *method_to_cfg; GHashTable *token_info_hash; - GHashTable *method_to_pinvoke_import; + GHashTable *method_to_pinvoke_scope_import; GHashTable *direct_pinvokes; GHashTable *method_to_external_icall_symbol_name; GPtrArray *extra_methods; @@ -6115,40 +6115,55 @@ method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method) } #ifdef MONO_ARCH_AOT_SUPPORTED -static const char * -get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) +static gboolean +method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) { MonoImage *image = m_class_get_image (method->klass); MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; MonoTableInfo *tables = image->tables; MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP]; + MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF]; guint32 im_cols [MONO_IMPLMAP_SIZE]; - char *import; - - import = (char *)g_hash_table_lookup (acfg->method_to_pinvoke_import, method); - if (import != NULL) - return import; + int module_idx; + const char **scope_import; + guint32 scope_token; + + if (g_hash_table_lookup_extended (acfg->method_to_pinvoke_scope_import, method, NULL, (gpointer *)&scope_import) && scope_import) { + if (module) + *module = g_strdup (scope_import[0]); + if (entrypoint) + *entrypoint = g_strdup (scope_import[1]); + return TRUE; + } if (piinfo->implmap_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_IMPLMAP, piinfo->implmap_idx)) - return NULL; + return FALSE; mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE); - int module_idx = im_cols [MONO_IMPLMAP_SCOPE]; + module_idx = im_cols [MONO_IMPLMAP_SCOPE]; if (module_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_MODULEREF, module_idx)) - return NULL; + return FALSE; - import = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); + scope_import = (const char **) g_malloc0 (3 * sizeof (scope_import)); + scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME); + scope_import[0] = g_strdup_printf ("%s", mono_metadata_string_heap (image, scope_token)); + scope_import[1] = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); - g_hash_table_insert (acfg->method_to_pinvoke_import, method, import); + g_hash_table_insert (acfg->method_to_pinvoke_scope_import, method, scope_import); - return import; + if (module) + *module = g_strdup (scope_import[0]); + if (entrypoint) + *entrypoint = g_strdup (scope_import[1]); + + return TRUE; } #else -static const char * -get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) +static gboolean +method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) { - return NULL; + return FALSE; } #endif @@ -6161,21 +6176,26 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method) static gboolean is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) { + gboolean direct_pinvoke_specified = FALSE; + const char *module_name, *sym; + GHashTable *val; + if (acfg->aot_opts.direct_pinvoke) return TRUE; if (!acfg->aot_opts.direct_pinvokes && !acfg->aot_opts.direct_pinvoke_lists) return FALSE; - const char *sym = get_pinvoke_import (acfg, method); - const char *module_name = acfg->image->module_name; - GHashTable *val; - if (g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { + if (method_to_pinvoke_has_scope_import (acfg, method, &module_name, &sym) && g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { if (!val) - return TRUE; - return g_hash_table_contains (val, sym); + direct_pinvoke_specified = TRUE; + else + direct_pinvoke_specified = g_hash_table_contains (val, sym); } - return FALSE; + g_free ((char *)module_name); + g_free ((char *)sym); + + return direct_pinvoke_specified; } /* @@ -6523,7 +6543,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) direct_pinvoke = lookup_icall_symbol_name_aot (patch_info->data.method); else - direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method); + method_to_pinvoke_has_scope_import (acfg, patch_info->data.method, NULL, &direct_pinvoke); if (direct_pinvoke && !never_direct_pinvoke (direct_pinvoke)) { direct_call = TRUE; g_assert (strlen (direct_pinvoke) < 1000); @@ -10203,7 +10223,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer 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)) - sym = get_pinvoke_import (llvm_acfg, method); + method_to_pinvoke_has_scope_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; @@ -13752,7 +13772,7 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->patch_to_plt_entry = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM); acfg->method_to_cfg = g_hash_table_new (NULL, NULL); acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL); - acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free); + acfg->method_to_pinvoke_scope_import = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_strfreev); acfg->direct_pinvokes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy); acfg->method_to_external_icall_symbol_name = g_hash_table_new_full (NULL, NULL, NULL, g_free); acfg->image_hash = g_hash_table_new (NULL, NULL); @@ -13857,7 +13877,7 @@ acfg_free (MonoAotCompile *acfg) g_free (acfg->patch_to_plt_entry); g_hash_table_destroy (acfg->method_to_cfg); g_hash_table_destroy (acfg->token_info_hash); - g_hash_table_destroy (acfg->method_to_pinvoke_import); + g_hash_table_destroy (acfg->method_to_pinvoke_scope_import); g_hash_table_destroy (acfg->direct_pinvokes); g_hash_table_destroy (acfg->method_to_external_icall_symbol_name); g_hash_table_destroy (acfg->image_hash); From b7cb5f0a0740cd39ec612bc91079f9dd64449eab Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 19 Jan 2023 10:26:47 -0500 Subject: [PATCH 31/38] Address feedback --- src/mono/mono/mini/aot-compiler.c | 47 ++++++++++++++++++------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 4aac22c6ea7743..1ff99f694cb7d6 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -308,7 +308,7 @@ typedef struct MonoAotCompile { GHashTable *image_hash; GHashTable *method_to_cfg; GHashTable *token_info_hash; - GHashTable *method_to_pinvoke_scope_import; + GHashTable *method_to_pinvoke_import; GHashTable *direct_pinvokes; GHashTable *method_to_external_icall_symbol_name; GPtrArray *extra_methods; @@ -6116,7 +6116,7 @@ method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method) #ifdef MONO_ARCH_AOT_SUPPORTED static gboolean -method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) +get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) { MonoImage *image = m_class_get_image (method->klass); MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; @@ -6125,14 +6125,14 @@ method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, co MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF]; guint32 im_cols [MONO_IMPLMAP_SIZE]; int module_idx; - const char **scope_import; + char **scope_import; guint32 scope_token; - if (g_hash_table_lookup_extended (acfg->method_to_pinvoke_scope_import, method, NULL, (gpointer *)&scope_import) && scope_import) { + if (g_hash_table_lookup_extended (acfg->method_to_pinvoke_import, method, NULL, (gpointer *)&scope_import) && scope_import) { if (module) - *module = g_strdup (scope_import[0]); + *module = scope_import[0]; if (entrypoint) - *entrypoint = g_strdup (scope_import[1]); + *entrypoint = scope_import[1]; return TRUE; } @@ -6145,23 +6145,23 @@ method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, co if (module_idx == 0 || mono_metadata_table_bounds_check (image, MONO_TABLE_MODULEREF, module_idx)) return FALSE; - scope_import = (const char **) g_malloc0 (3 * sizeof (scope_import)); + scope_import = (char **) g_malloc0 (2 * sizeof (char *)); scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME); scope_import[0] = g_strdup_printf ("%s", mono_metadata_string_heap (image, scope_token)); scope_import[1] = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); - g_hash_table_insert (acfg->method_to_pinvoke_scope_import, method, scope_import); + g_hash_table_insert (acfg->method_to_pinvoke_import, method, scope_import); if (module) - *module = g_strdup (scope_import[0]); + *module = scope_import[0]; if (entrypoint) - *entrypoint = g_strdup (scope_import[1]); + *entrypoint = scope_import[1]; return TRUE; } #else static gboolean -method_to_pinvoke_has_scope_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) +get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) { return FALSE; } @@ -6177,7 +6177,7 @@ static gboolean is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) { gboolean direct_pinvoke_specified = FALSE; - const char *module_name, *sym; + const char *module_name, *sym = NULL; GHashTable *val; if (acfg->aot_opts.direct_pinvoke) @@ -6186,14 +6186,12 @@ is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method if (!acfg->aot_opts.direct_pinvokes && !acfg->aot_opts.direct_pinvoke_lists) return FALSE; - if (method_to_pinvoke_has_scope_import (acfg, method, &module_name, &sym) && g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { + if (get_pinvoke_import (acfg, method, &module_name, &sym) && g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { if (!val) direct_pinvoke_specified = TRUE; else direct_pinvoke_specified = g_hash_table_contains (val, sym); } - g_free ((char *)module_name); - g_free ((char *)sym); return direct_pinvoke_specified; } @@ -6543,7 +6541,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) direct_pinvoke = lookup_icall_symbol_name_aot (patch_info->data.method); else - method_to_pinvoke_has_scope_import (acfg, patch_info->data.method, NULL, &direct_pinvoke); + get_pinvoke_import (acfg, patch_info->data.method, NULL, &direct_pinvoke); if (direct_pinvoke && !never_direct_pinvoke (direct_pinvoke)) { direct_call = TRUE; g_assert (strlen (direct_pinvoke) < 1000); @@ -10223,7 +10221,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer 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)) - method_to_pinvoke_has_scope_import (llvm_acfg, method, NULL, &sym); + 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; @@ -13746,6 +13744,17 @@ add_mibc_profile_methods (MonoAotCompile *acfg, char *filename) printf ("Added %d methods from mibc profile.\n", count); } +static void +free_method_pinvoke_import_value (gpointer data) +{ + gchar **value = (gchar **)data; + if (!value) + return; + g_free (value[0]); + g_free (value[1]); + g_free (value); +} + static void init_got_info (GotInfo *info) { @@ -13772,7 +13781,7 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->patch_to_plt_entry = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM); acfg->method_to_cfg = g_hash_table_new (NULL, NULL); acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL); - acfg->method_to_pinvoke_scope_import = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_strfreev); + acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)free_method_pinvoke_import_value); acfg->direct_pinvokes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy); acfg->method_to_external_icall_symbol_name = g_hash_table_new_full (NULL, NULL, NULL, g_free); acfg->image_hash = g_hash_table_new (NULL, NULL); @@ -13877,7 +13886,7 @@ acfg_free (MonoAotCompile *acfg) g_free (acfg->patch_to_plt_entry); g_hash_table_destroy (acfg->method_to_cfg); g_hash_table_destroy (acfg->token_info_hash); - g_hash_table_destroy (acfg->method_to_pinvoke_scope_import); + g_hash_table_destroy (acfg->method_to_pinvoke_import); g_hash_table_destroy (acfg->direct_pinvokes); g_hash_table_destroy (acfg->method_to_external_icall_symbol_name); g_hash_table_destroy (acfg->image_hash); From c7c8a4b6583e35f585f8f2e7dedf73128e442a75 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 19 Jan 2023 18:11:02 -0500 Subject: [PATCH 32/38] [mono] Strip method pinvoke method ref to file name without extension --- src/mono/mono/mini/aot-compiler.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 1ff99f694cb7d6..6309308a9f7000 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6127,6 +6127,8 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul int module_idx; char **scope_import; guint32 scope_token; + char *module_ref_basename; + char **module_ref_basename_without_extension; if (g_hash_table_lookup_extended (acfg->method_to_pinvoke_import, method, NULL, (gpointer *)&scope_import) && scope_import) { if (module) @@ -6147,7 +6149,10 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul scope_import = (char **) g_malloc0 (2 * sizeof (char *)); scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME); - scope_import[0] = g_strdup_printf ("%s", mono_metadata_string_heap (image, scope_token)); + module_ref_basename = g_path_get_basename (mono_metadata_string_heap (image, scope_token)); + module_ref_basename_without_extension = g_strsplit (module_ref_basename, ".", -1); + g_assert (!module_ref_basename_without_extension [1] || !module_ref_basename_without_extension [2]); + scope_import[0] = g_strdup_printf ("%s", module_ref_basename_without_extension [0]); scope_import[1] = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); g_hash_table_insert (acfg->method_to_pinvoke_import, method, scope_import); @@ -6157,6 +6162,8 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul if (entrypoint) *entrypoint = scope_import[1]; + g_strfreev (module_ref_basename_without_extension); + g_free (module_ref_basename); return TRUE; } #else From ea0d8301ed51a0663a06487caa797d0e1bac54ae Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 19 Jan 2023 19:51:20 -0500 Subject: [PATCH 33/38] [mono] Remove unnecessary boolean variable from is_direct_pinvoke_specified_for_method --- src/mono/mono/mini/aot-compiler.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 6309308a9f7000..73e5049119b0e5 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6183,7 +6183,6 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul static gboolean is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method) { - gboolean direct_pinvoke_specified = FALSE; const char *module_name, *sym = NULL; GHashTable *val; @@ -6195,12 +6194,12 @@ is_direct_pinvoke_specified_for_method (MonoAotCompile *acfg, MonoMethod *method if (get_pinvoke_import (acfg, method, &module_name, &sym) && g_hash_table_lookup_extended (acfg->direct_pinvokes, module_name, NULL, (gpointer *)&val)) { if (!val) - direct_pinvoke_specified = TRUE; - else - direct_pinvoke_specified = g_hash_table_contains (val, sym); + return TRUE; + + return g_hash_table_contains (val, sym); } - return direct_pinvoke_specified; + return FALSE; } /* From 4016be0c05a129b2335b79a9f26dbf8e23fc1ca1 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 19 Jan 2023 19:52:40 -0500 Subject: [PATCH 34/38] [mono] Add documentation to get_direct_pinvoke, direct_pinvokes, and direct_pinvoke_lists --- src/mono/mono/mini/aot-compiler.c | 127 +++++++++++-------- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 34 ++++- 2 files changed, 106 insertions(+), 55 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 73e5049119b0e5..7039c11f50dcbf 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6115,6 +6115,27 @@ method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method) } #ifdef MONO_ARCH_AOT_SUPPORTED +//--------------------------------------------------------------------------------------- +// +// get_pinvoke_import: +// +// Returns whether or not module and entrypoint pinvoke information could be grabbed +// from the MonoMethod. It populates module and entrypoint if they are not NULL. A +// hash table is populated with key value pairs corresponding to the MonoMethod and +// module entrypoint string array to serve as a fast path cache. The module and +// entrypoint string data are owned by the hash table. +// +// Arguments: +// * acfg - the MonoAotCompiler instance +// * method - the MonoMethod to grab pinvoke scope and import information from +// ** module - the pointer to the module name string (owned by the hashtable) +// ** entrypoint - the pointer to the entrypoint name string (owned by the hashtable) +// +// Return Value: +// gboolean corresponding to whether or not module and entrypoint pinvoke information +// could be grabbed from the provided MonoMethod. +// + static gboolean get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **module, const char **entrypoint) { @@ -8682,59 +8703,59 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) opts->depfile = g_strdup (arg + strlen ("depfile=")); } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) { printf ("Supported options for --aot:\n"); - printf (" asmonly\n"); - printf (" bind-to-runtime-version\n"); - printf (" bitcode\n"); - printf (" data-outfile=\n"); - printf (" direct-icalls\n"); - printf (" direct-pinvokes=\n"); - printf (" direct-pinvoke-lists=\n"); - printf (" direct-pinvoke\n"); - printf (" dwarfdebug\n"); - printf (" full\n"); - printf (" hybrid\n"); - printf (" info\n"); - printf (" keep-temps\n"); - printf (" llvm\n"); - printf (" llvmonly\n"); - printf (" llvm-outfile=\n"); - printf (" llvm-path=\n"); - printf (" msym-dir=\n"); - printf (" mtriple\n"); - printf (" nimt-trampolines=\n"); - printf (" nodebug\n"); - printf (" no-direct-calls\n"); - printf (" no-write-symbols\n"); - printf (" nrgctx-trampolines=\n"); - printf (" nrgctx-fetch-trampolines=\n"); - printf (" ngsharedvt-trampolines=\n"); - printf (" nftnptr-arg-trampolines=\n"); - printf (" nunbox-arbitrary-trampolines=\n"); - printf (" ntrampolines=\n"); - printf (" outfile=\n"); - printf (" profile=\n"); - printf (" profile-only\n"); - printf (" mibc-profile=\n"); - printf (" print-skipped-methods\n"); - printf (" readonly-value=\n"); - printf (" save-temps\n"); - printf (" soft-debug\n"); - printf (" static\n"); - printf (" stats\n"); - printf (" temp-path=\n"); - printf (" tool-prefix=\n"); - printf (" threads=\n"); - printf (" write-symbols\n"); - printf (" verbose\n"); - printf (" allow-errors\n"); - printf (" no-opt\n"); - printf (" llvmopts=\n"); - printf (" llvmllc=\n"); - printf (" clangxx=\n"); - printf (" depfile=\n"); - printf (" mcpu=\n"); - printf (" mattr=\n"); - printf (" help/?\n"); + printf (" asmonly - \n"); + printf (" bind-to-runtime-version - \n"); + printf (" bitcode - \n"); + printf (" data-outfile= - \n"); + printf (" direct-icalls - \n"); + printf (" direct-pinvokes= - Specific direct pinvokes to generate direct calls for an entire 'module' or specific 'module!entrypoint' separated by semi-colons. Incompatible with 'direct-pinvoke' option.\n"); + printf (" direct-pinvoke-lists= - Files containing specific direct pinvokes to generate direct calls for an entire 'module' or specific 'module!entrypoint' on separate lines. Incompatible with 'direct-pinvoke' option.\n"); + printf (" direct-pinvoke - Generate direct calls for all direct pinvokes encountered in the managed assembly.\n"); + printf (" dwarfdebug - \n"); + printf (" full - \n"); + printf (" hybrid - \n"); + printf (" info - \n"); + printf (" keep-temps - \n"); + printf (" llvm - \n"); + printf (" llvmonly - \n"); + printf (" llvm-outfile= - \n"); + printf (" llvm-path= - \n"); + printf (" msym-dir= - \n"); + printf (" mtriple - \n"); + printf (" nimt-trampolines= - \n"); + printf (" nodebug - \n"); + printf (" no-direct-calls - \n"); + printf (" no-write-symbols - \n"); + printf (" nrgctx-trampolines= - \n"); + printf (" nrgctx-fetch-trampolines= - \n"); + printf (" ngsharedvt-trampolines= - \n"); + printf (" nftnptr-arg-trampolines= - \n"); + printf (" nunbox-arbitrary-trampolines= - \n"); + printf (" ntrampolines= - \n"); + printf (" outfile= - \n"); + printf (" profile= - \n"); + printf (" profile-only - \n"); + printf (" mibc-profile= - \n"); + printf (" print-skipped-methods - \n"); + printf (" readonly-value= - \n"); + printf (" save-temps - \n"); + printf (" soft-debug - \n"); + printf (" static - \n"); + printf (" stats - \n"); + printf (" temp-path= - \n"); + printf (" tool-prefix= - \n"); + printf (" threads= - \n"); + printf (" write-symbols - \n"); + printf (" verbose - \n"); + printf (" allow-errors - \n"); + printf (" no-opt - \n"); + printf (" llvmopts= - \n"); + printf (" llvmllc= - \n"); + printf (" clangxx= - \n"); + printf (" depfile= - \n"); + printf (" mcpu= - \n"); + printf (" mattr= - \n"); + printf (" help/? \n"); exit (0); } else { fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg); diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 1a8cccc7c5826d..41fe756b7df402 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -107,12 +107,42 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task public bool UseDirectPInvoke { get; set; } /// - /// PInvokes to call directly. + /// When this option is specified, the mono aot compiler will generate direct calls for only specified direct pinvokes. + /// Specified direct pinvokes can be in the format of 'module' to generate direct calls for all entrypoints in the module, + /// or 'module!entrypoint' to generate direct calls for individual entrypoints in a module. 'module' will trump 'module!entrypoint'. + /// For a direct call to be generated, the managed code must call the native function through a direct pinvoke, e.g. + /// + /// [DllImport("module", EntryPoint="entrypoint")] + /// public static extern ManagedName (arg) + /// + /// or + /// + /// [DllImport("module")] + /// public static extern entrypoint (arg) + /// + /// The native sources must be supplied in the direct pinvoke sources parammeter in the LibraryBuilder to generate a shared library. + /// If not using the LibraryBuilder, the native sources must be linked manually in the final executable or library. + /// This requires UseStaticLinking=true, can be used in conjunction with DirectPInvokeLists, but is incompatible with UseDirectPInvoke. /// public ITaskItem[] DirectPInvokes { get; set; } = Array.Empty(); /// - /// List of files with list of PInvokes to call directly. + /// When this option is specified, the mono aot compiler will generate direct calls for only specified direct pinvokes in the provided files. + /// Specified direct pinvokes can be in the format of 'module' to generate direct calls for all entrypoints in the module, + /// or 'module!entrypoint' to generate direct calls for individual entrypoints in a module. 'module' will trump 'module!entrypoint'. + /// For a direct call to be generated, the managed code must call the native function through a direct pinvoke, e.g. + /// + /// [DllImport("module", EntryPoint="entrypoint")] + /// public static extern ManagedName (arg) + /// + /// or + /// + /// [DllImport("module")] + /// public static extern entrypoint (arg) + /// + /// The native sources must be supplied in the direct pinvoke sources parammeter in the LibraryBuilder to generate a shared library. + /// If not using the LibraryBuilder, the native sources must be linked manually in the final executable or library. + /// This requires UseStaticLinking=true, can be used in conjunction with DirectPInvokes, but is incompatible with UseDirectPInvoke. /// public ITaskItem[] DirectPInvokeLists { get; set; } = Array.Empty(); From 74a518a9e3e683782c5d5c1abd1064bc334a4c91 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 20 Jan 2023 12:55:44 -0500 Subject: [PATCH 35/38] [mono] Handle known file extensions when parsing method pinvoke import --- src/mono/mono/mini/aot-compiler.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 7039c11f50dcbf..b2b4832b61d4c6 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6149,7 +6149,7 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul char **scope_import; guint32 scope_token; char *module_ref_basename; - char **module_ref_basename_without_extension; + char *module_ref_basename_extension; if (g_hash_table_lookup_extended (acfg->method_to_pinvoke_import, method, NULL, (gpointer *)&scope_import) && scope_import) { if (module) @@ -6171,20 +6171,27 @@ get_pinvoke_import (MonoAotCompile *acfg, MonoMethod *method, const char **modul scope_import = (char **) g_malloc0 (2 * sizeof (char *)); scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME); module_ref_basename = g_path_get_basename (mono_metadata_string_heap (image, scope_token)); - module_ref_basename_without_extension = g_strsplit (module_ref_basename, ".", -1); - g_assert (!module_ref_basename_without_extension [1] || !module_ref_basename_without_extension [2]); - scope_import[0] = g_strdup_printf ("%s", module_ref_basename_without_extension [0]); - scope_import[1] = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); + module_ref_basename_extension = strrchr (module_ref_basename, '.'); + if (module_ref_basename_extension) { + const char **suffixes = mono_dl_get_so_suffixes (); + for (int i = 0; suffixes [i] && suffixes [i][0] != '\0'; i++) { + if (!strcmp (module_ref_basename_extension, suffixes [i])) { + *module_ref_basename_extension= '\0'; + break; + } + } + } + + scope_import [0] = module_ref_basename; + scope_import [1] = g_strdup_printf ("%s", mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME])); g_hash_table_insert (acfg->method_to_pinvoke_import, method, scope_import); if (module) - *module = scope_import[0]; + *module = scope_import [0]; if (entrypoint) - *entrypoint = scope_import[1]; + *entrypoint = scope_import [1]; - g_strfreev (module_ref_basename_without_extension); - g_free (module_ref_basename); return TRUE; } #else From e2ac545270ae4c819106d9c62e88d66f73b2f2dc Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 24 Jan 2023 13:07:13 -0500 Subject: [PATCH 36/38] [mono] Initialize direct_pinvoke --- src/mono/mono/mini/aot-compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index b2b4832b61d4c6..bbe5d0d24f4d1d 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -6445,7 +6445,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui gboolean direct_call, external_call; guint32 got_slot; const char *direct_call_target = 0; - const char *direct_pinvoke; + const char *direct_pinvoke = NULL; #endif if (acfg->gas_line_numbers && method && debug_info) { From 80c72a7e5081271a77416ee604a87ac48e71bb2e Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Thu, 26 Jan 2023 16:25:07 -0500 Subject: [PATCH 37/38] [mono] Fix aot_opts_free location to appropriate scope where allocated --- src/mono/mono/mini/aot-compiler.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index bbe5d0d24f4d1d..eaab4b3c747a15 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -13937,7 +13937,6 @@ acfg_free (MonoAotCompile *acfg) got_info_free (&acfg->llvm_got_info); arch_free_unwind_info_section_cache (acfg); mono_mempool_destroy (acfg->mempool); - aot_opts_free (&acfg->aot_opts); method_to_external_icall_symbol_name = NULL; g_free (acfg); @@ -15175,7 +15174,8 @@ mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opt mono_aot_parse_options (aot_options, &aot_opts); if (aot_opts.direct_extern_calls && !(aot_opts.llvm && aot_opts.static_link)) { fprintf (stderr, "The 'direct-extern-calls' option requires the 'llvm' and 'static' options.\n"); - return 1; + res = 1; + goto early_exit; } if (aot_opts.dedup_include) { @@ -15189,7 +15189,8 @@ mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opt } if (dedup_aindex == -1) { fprintf (stderr, "Can't find --dedup-include assembly '%s' among the assemblies to be compiled.\n", aot_opts.dedup_include); - return 1; + res = 1; + goto early_exit; } dedup_assembly = assemblies [dedup_aindex]; @@ -15206,10 +15207,13 @@ mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opt res = aot_assembly (assemblies [i], jit_opts, &aot_opts); if (res != 0) { fprintf (stderr, "AOT of image %s failed.\n", assemblies [i]->image->name); - return 1; + goto early_exit; } } - return 0; + +early_exit: + aot_opts_free (&aot_opts); + return res; } #else From 4f31461cc69ef48162da647447e5ca52a9752565 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Fri, 27 Jan 2023 08:59:15 -0500 Subject: [PATCH 38/38] [mono] Initialize mono_aot_assemblies result for return --- src/mono/mono/mini/aot-compiler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index eaab4b3c747a15..bba7c9184ae46c 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -15167,7 +15167,7 @@ emit_aot_image (MonoAotCompile *acfg) int mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opts, const char *aot_options) { - int res; + int res = 0; MonoAotOptions aot_opts; init_options (&aot_opts); @@ -15207,6 +15207,7 @@ mono_aot_assemblies (MonoAssembly **assemblies, int nassemblies, guint32 jit_opt res = aot_assembly (assemblies [i], jit_opts, &aot_opts); if (res != 0) { fprintf (stderr, "AOT of image %s failed.\n", assemblies [i]->image->name); + res = 1; goto early_exit; } }