From 33e5a940905f3fae6740407142b2cc297d02f055 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Mon, 8 Apr 2019 17:33:34 +0200 Subject: [PATCH] Add support for direct icalls not defined in icall-def.h. An icall declaration can now use the following attribute: MonoDirectICallSymbolNameAttribute("MyNativeCFunction") and if not already defined in icall-def.h and direct-icalls are used when AOT compile the assembly, a direct call will use symbol defined in attribute as the symbol for direct call. Using this attribute will also enable inlining for the specific icall wrapper generating inlined direct icalls to external defined native methods. This feature is valuable when embedding the runtime and extend with icalls added using mono_add_internal_call. By applying the above attribute, it is possible to do AOT with direct-icalls and get static linked icalls without the need to extend and rebuild cross compiler in the process. Commit migrated from https://github.com/mono/mono/commit/491a4d5da8e523d6191e6027ea7f3cee226d6ba8 --- src/mono/mono/mini/aot-compiler.c | 91 +++++++++++++++++++++++++++++++++++++-- src/mono/mono/mini/aot-compiler.h | 1 + src/mono/mono/mini/method-to-ir.c | 17 +++++--- 3 files changed, 99 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index e5f9349..7be1470 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -289,6 +289,7 @@ typedef struct MonoAotCompile { GHashTable *method_to_cfg; GHashTable *token_info_hash; GHashTable *method_to_pinvoke_import; + GHashTable *method_to_external_icall_symbol_name; GPtrArray *extra_methods; GPtrArray *image_table; GPtrArray *globals; @@ -401,6 +402,11 @@ typedef struct { /* This points to the current acfg in LLVM mode */ static MonoAotCompile *llvm_acfg; +/* Cache of decoded method external icall symbol names. */ +/* Owned by acfg, but kept in this static as well since it is */ +/* accessed by code paths not having access to acfg. */ +static GHashTable *method_to_external_icall_symbol_name; + // This, instead of an array of pointers, to optimize away a pointer and a relocation per string. #define MSGSTRFIELD(line) MSGSTRFIELD1(line) #define MSGSTRFIELD1(line) str##line @@ -5627,6 +5633,80 @@ add_generic_instances (MonoAotCompile *acfg) } } +static char * +decode_direct_icall_symbol_name_attribute (MonoMethod *method) +{ + ERROR_DECL (error); + + int j = 0; + char *symbol_name = NULL; + + MonoCustomAttrInfo *cattr = mono_custom_attrs_from_method_checked (method, error); + if (mono_error_ok(error) && cattr) { + for (j = 0; j < cattr->num_attrs; j++) + if (cattr->attrs [j].ctor && !strcmp (m_class_get_name (cattr->attrs [j].ctor->klass), "MonoDirectICallSymbolNameAttribute")) + break; + + if (j < cattr->num_attrs) { + MonoCustomAttrEntry *e = &cattr->attrs [j]; + MonoMethodSignature *sig = mono_method_signature_internal (e->ctor); + if (e->data && sig && sig->param_count == 1 && sig->params [0]->type == MONO_TYPE_STRING) { + /* + * Decode the cattr manually since we can't create objects + * during aot compilation. + */ + + /* Skip prolog */ + const char *p = ((const char*)e->data) + 2; + int slen = mono_metadata_decode_value (p, &p); + + symbol_name = (char *)g_memdup (p, slen + 1); + if (symbol_name) + symbol_name [slen] = 0; + } + } + } + + return symbol_name; +} +static const char* +lookup_external_icall_symbol_name_aot (MonoMethod *method) +{ + g_assert (method_to_external_icall_symbol_name); + + gpointer key, value; + if (g_hash_table_lookup_extended (method_to_external_icall_symbol_name, method, &key, &value)) + return (const char*)value; + + char *symbol_name = decode_direct_icall_symbol_name_attribute (method); + g_hash_table_insert (method_to_external_icall_symbol_name, method, symbol_name); + + return symbol_name; +} + +static const char* +lookup_icall_symbol_name_aot (MonoMethod *method) +{ + const char * symbol_name = mono_lookup_icall_symbol (method); + if (!symbol_name) + symbol_name = lookup_external_icall_symbol_name_aot (method); + + return symbol_name; +} + +gboolean +mono_aot_direct_icalls_enabled_for_method (MonoCompile *cfg, MonoMethod *method) +{ + gboolean enable_icall = FALSE; + if (cfg->compile_aot) { + enable_icall = lookup_external_icall_symbol_name_aot (method) ? TRUE : FALSE; + } else { + enable_icall = FALSE; + } + + return enable_icall; +} + /* * is_direct_callable: * @@ -5981,7 +6061,7 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui } else if (patch_info->type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { if (!got_only && is_direct_callable (acfg, method, patch_info)) { if (!(patch_info->data.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) - direct_pinvoke = mono_lookup_icall_symbol (patch_info->data.method); + direct_pinvoke = lookup_icall_symbol_name_aot (patch_info->data.method); else direct_pinvoke = get_pinvoke_import (acfg, patch_info->data.method); if (direct_pinvoke) { @@ -9349,7 +9429,7 @@ mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data) } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) - sym = mono_lookup_icall_symbol (method); + sym = lookup_icall_symbol_name_aot (method); else if (llvm_acfg->aot_opts.direct_pinvoke) sym = get_pinvoke_import (llvm_acfg, method); } else if (type == MONO_PATCH_INFO_JIT_ICALL) { @@ -9384,7 +9464,7 @@ mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data) } else if (type == MONO_PATCH_INFO_ICALL_ADDR_CALL) { MonoMethod *method = (MonoMethod *)data; if (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) - sym = mono_lookup_icall_symbol (method); + sym = lookup_icall_symbol_name_aot (method); } if (sym) return g_strdup (sym); @@ -12423,6 +12503,7 @@ acfg_create (MonoAssembly *ass, guint32 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->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 (); acfg->globals = g_ptr_array_new (); @@ -12451,6 +12532,7 @@ acfg_create (MonoAssembly *ass, guint32 opts) init_got_info (&acfg->got_info); init_got_info (&acfg->llvm_got_info); + method_to_external_icall_symbol_name = acfg->method_to_external_icall_symbol_name; return acfg; } @@ -12494,6 +12576,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->method_to_external_icall_symbol_name); g_hash_table_destroy (acfg->image_hash); g_hash_table_destroy (acfg->unwind_info_offsets); g_hash_table_destroy (acfg->method_label_hash); @@ -12506,6 +12589,8 @@ acfg_free (MonoAotCompile *acfg) got_info_free (&acfg->llvm_got_info); arch_free_unwind_info_section_cache (acfg); mono_mempool_destroy (acfg->mempool); + + method_to_external_icall_symbol_name = NULL; g_free (acfg); } diff --git a/src/mono/mono/mini/aot-compiler.h b/src/mono/mono/mini/aot-compiler.h index 6433222..e5fd43f 100644 --- a/src/mono/mono/mini/aot-compiler.h +++ b/src/mono/mono/mini/aot-compiler.h @@ -10,6 +10,7 @@ int mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, gpointer **aot_state); int mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state); void* mono_aot_readonly_field_override (MonoClassField *field); +gboolean mono_aot_direct_icalls_enabled_for_method (MonoCompile *cfg, MonoMethod *method); gboolean mono_aot_is_shared_got_offset (int offset) MONO_LLVM_INTERNAL; guint32 mono_aot_get_got_offset (MonoJumpInfo *ji) MONO_LLVM_INTERNAL; diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 221edcf..461242e 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -2148,18 +2148,21 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_ } static gboolean -direct_icalls_enabled (MonoCompile *cfg) +direct_icalls_enabled (MonoCompile *cfg, MonoMethod *method) { - return FALSE; + if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls) + return FALSE; + + if (method && mono_aot_direct_icalls_enabled_for_method (cfg, method)) + return TRUE; /* LLVM on amd64 can't handle calls to non-32 bit addresses */ #ifdef TARGET_AMD64 if (cfg->compile_llvm && !cfg->llvm_only) return FALSE; #endif - if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls) - return FALSE; - return TRUE; + + return FALSE; } MonoInst* @@ -2170,7 +2173,7 @@ mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitICallInfo * * The wrapper is needed to be able to do stack walks for asynchronously suspended * threads when debugging. */ - if (direct_icalls_enabled (cfg)) { + if (direct_icalls_enabled (cfg, NULL)) { int costs; if (!info->wrapper_method) { @@ -7047,7 +7050,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL && mini_class_is_system_array (cmethod->klass)) { array_rank = m_class_get_rank (cmethod->klass); - } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && direct_icalls_enabled (cfg)) { + } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && direct_icalls_enabled (cfg, cmethod)) { direct_icall = TRUE; } else if (fsig->pinvoke) { MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot); -- 2.7.4