diff options
author | Zoltan Varga <vargaz@gmail.com> | 2020-01-31 19:41:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-31 19:41:49 +0300 |
commit | a475b84a3eec7c6e1824ab2ad32de34ecb34f7aa (patch) | |
tree | b0d4b909d042f61c568c38a7bad3526889a0d13c | |
parent | 4ef40a91ed602a0a13730ee4103cfb5d1d300b9a (diff) |
[aot] Add support for making direct cross-assembly calls in llvm mode. (#18505)
* [aot] Handle '|' during symbol mangling.
* [aot] Clean up the construction of the linker command line.
* [aot] Pass -Wl,-install_name to the linker on osx, otherwise the shared object will be named based on the output file name i.e. <assembly>.dylib.tmp.
* [llvm] Pass the MonoAotFileInfo pointer to the init functions, not used yet.
* [jit] Add support for direct calls between methods in different AOT images in LLVM mode.
* Add a 'direct-extern-calls' AOT option.
* Initialize the PLT/GOT during method initialization,
this normally happens in load_method () but that is
not called when a method is directly called.
* Add self initialization support for JITted methods, they can be
called directly since they are fallbacks if LLVM fails.
* Fix the build.
* Avoid calling BeginInvoke etc. directly, its implemented by the runtime.
* Unify some cases.
* Init PLT at image load time since directly called methods without initializers might make calls through it.
* Fix a startup problem.
* Make the mono_is_corlib_image () check for during startup.
* Check for is_inited in the init icall wrappers, since they might be called from JITted code which doesn't check it.
* Address review comments.
-rw-r--r-- | mono/metadata/icall-signatures.h | 2 | ||||
-rw-r--r-- | mono/mini/aot-compiler.c | 162 | ||||
-rw-r--r-- | mono/mini/aot-compiler.h | 1 | ||||
-rw-r--r-- | mono/mini/aot-runtime.c | 47 | ||||
-rw-r--r-- | mono/mini/aot-runtime.h | 2 | ||||
-rw-r--r-- | mono/mini/llvmonly-runtime.c | 8 | ||||
-rw-r--r-- | mono/mini/llvmonly-runtime.h | 9 | ||||
-rw-r--r-- | mono/mini/method-to-ir.c | 22 | ||||
-rw-r--r-- | mono/mini/mini-llvm.c | 170 | ||||
-rw-r--r-- | mono/mini/mini-runtime.c | 8 | ||||
-rw-r--r-- | mono/mini/mini.c | 2 | ||||
-rw-r--r-- | mono/mini/mini.h | 3 |
12 files changed, 337 insertions, 99 deletions
diff --git a/mono/metadata/icall-signatures.h b/mono/metadata/icall-signatures.h index aa15e211bc1..876c427c314 100644 --- a/mono/metadata/icall-signatures.h +++ b/mono/metadata/icall-signatures.h @@ -257,6 +257,8 @@ ICALL_SIG (5, (void, object, ptr, int32, int32)) \ ICALL_SIG (5, (void, object, ptr, ptr, ptr)) \ ICALL_SIG (5, (void, ptr, int, int, object)) \ ICALL_SIG (5, (void, ptr, ptr, ptr, ptr)) \ +ICALL_SIG (5, (void, ptr, ptr, int, object)) \ +ICALL_SIG (5, (void, ptr, ptr, int, ptr)) \ ICALL_SIG (5, (ptr, ptr, ptr, ptr, ptr)) \ ICALL_SIG (6, (int, int, int, ptr, ptr, ptr)) \ ICALL_SIG (6, (int, ptr, int, int, ptr, object)) \ diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 6c43e33611f..d194a35afec 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -203,6 +203,7 @@ typedef struct MonoAotOptions { char *gen_msym_dir_path; gboolean direct_pinvoke; gboolean direct_icalls; + gboolean direct_extern_calls; gboolean no_direct_calls; gboolean use_trampolines_page; gboolean no_instances; @@ -5800,6 +5801,63 @@ mono_aot_direct_icalls_enabled_for_method (MonoCompile *cfg, MonoMethod *method) } /* + * method_is_externally_callable: + * + * Return whenever METHOD can be directly called from other AOT images + * without going through a PLT. + */ +static gboolean +method_is_externally_callable (MonoAotCompile *acfg, MonoMethod *method) +{ + // FIXME: Unify + if (acfg->aot_opts.llvm_only) { + if (!acfg->aot_opts.static_link) + return FALSE; + if (method->wrapper_type == MONO_WRAPPER_ALLOC) + return TRUE; + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + return TRUE; + if (method->string_ctor) + return FALSE; + if (method->wrapper_type) + return FALSE; + if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) + return FALSE; + if (method->is_inflated) + return FALSE; + if (!((mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC))) + return FALSE; + /* Can't enable this as the callee might fail llvm compilation */ + //return TRUE; + return FALSE; + } else { + if (!acfg->aot_opts.direct_extern_calls) + return FALSE; + if (!acfg->llvm || acfg->aot_opts.llvm_disable_self_init) + return FALSE; + if (acfg->aot_opts.soft_debug || acfg->aot_opts.no_direct_calls) + return FALSE; + if (method->wrapper_type == MONO_WRAPPER_ALLOC) + return FALSE; + if (method->string_ctor) + return FALSE; + if (method->wrapper_type) + return FALSE; + if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) + return FALSE; + if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + return FALSE; + if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) + return FALSE; + if (method->is_inflated) + return FALSE; + if (!((mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC))) + return FALSE; + return TRUE; + } +} + +/* * is_direct_callable: * * Return whenever the method identified by JI is directly callable without @@ -5851,6 +5909,9 @@ is_direct_callable (MonoAotCompile *acfg, MonoMethod *method, MonoJumpInfo *patc if (direct_callable) return TRUE; } + } else if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (m_class_get_image (patch_info->data.method->klass) != acfg->image)) { + /* 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; @@ -6132,13 +6193,28 @@ emit_and_reloc_code (MonoAotCompile *acfg, MonoMethod *method, guint8 *code, gui */ direct_call = FALSE; external_call = FALSE; - if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (m_class_get_image (patch_info->data.method->klass) == acfg->image)) { - if (!got_only && is_direct_callable (acfg, method, patch_info)) { - MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method); + if (patch_info->type == MONO_PATCH_INFO_METHOD) { + MonoMethod *cmethod = patch_info->data.method; + if (cmethod->wrapper_type == MONO_WRAPPER_OTHER && mono_marshal_get_wrapper_info (cmethod)->subtype == WRAPPER_SUBTYPE_AOT_INIT) { + WrapperInfo *info = mono_marshal_get_wrapper_info (cmethod); + + /* + * This is a call from a JITted method to the init wrapper emitted by LLVM. + */ + g_assert (acfg->aot_opts.llvm && acfg->aot_opts.direct_extern_calls); + + const char *init_name = mono_marshal_get_aot_init_wrapper_name (info->d.aot_init.subtype); + char *symbol = g_strdup_printf ("%s%s_%s", acfg->user_symbol_prefix, acfg->global_prefix, init_name); + + direct_call = TRUE; + direct_call_target = symbol; + patch_info->type = MONO_PATCH_INFO_NONE; + } else if ((m_class_get_image (patch_info->data.method->klass) == acfg->image) && !got_only && is_direct_callable (acfg, method, patch_info)) { + MonoCompile *callee_cfg = (MonoCompile *)g_hash_table_lookup (acfg->method_to_cfg, cmethod); // Don't compile inflated methods if we're doing dedup - if (acfg->aot_opts.dedup && !mono_aot_can_dedup (patch_info->data.method)) { - char *name = mono_aot_get_mangled_method_name (patch_info->data.method); + if (acfg->aot_opts.dedup && !mono_aot_can_dedup (cmethod)) { + char *name = mono_aot_get_mangled_method_name (cmethod); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "DIRECT CALL: %s by %s", name, method ? mono_method_full_name (method, TRUE) : ""); g_free (name); @@ -8091,6 +8167,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts) 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")) { + opts->direct_extern_calls = TRUE; } else if (str_begins_with (arg, "no-direct-calls")) { opts->no_direct_calls = TRUE; } else if (str_begins_with (arg, "print-skipped")) { @@ -8609,6 +8687,8 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) flags = (JitFlags)(flags | JIT_FLAG_INTERP); if (acfg->aot_opts.use_current_cpu) flags = (JitFlags)(flags | JIT_FLAG_USE_CURRENT_CPU); + if (method_is_externally_callable (acfg, method)) + flags = (JitFlags)(flags | JIT_FLAG_SELF_INIT); jit_time_start = mono_time_track_start (); cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), flags, 0, index); @@ -8839,6 +8919,16 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) if (cfg->llvm_only) acfg->stats.llvm_count ++; + if (acfg->llvm && !cfg->compile_llvm && method_is_externally_callable (acfg, cfg->method)) { + /* + * This is a JITted fallback method for a method which failed LLVM compilation, emit a global + * symbol for it with the same name the LLVM method would get. + */ + char *name = mono_aot_get_mangled_method_name (cfg->method); + char *export_name = g_strdup_printf ("%s%s", acfg->user_symbol_prefix, name); + g_hash_table_insert (acfg->export_names, cfg->method, export_name); + } + /* * FIXME: Instead of this mess, allocate the patches from the aot mempool. */ @@ -8964,6 +9054,12 @@ mono_aot_is_shared_got_offset (int offset) return offset < llvm_acfg->nshared_got_entries; } +gboolean +mono_aot_is_externally_callable (MonoMethod *cmethod) +{ + return method_is_externally_callable (llvm_acfg, cmethod); +} + char* mono_aot_get_method_name (MonoCompile *cfg) { @@ -9330,6 +9426,9 @@ sanitize_mangled_string (const char *input) case ':': g_string_append (s, "_colon_"); break; + case '|': + g_string_append (s, "_verbar_"); + break; default: g_string_append_c (s, c); } @@ -12186,29 +12285,32 @@ compile_asm (MonoAotCompile *acfg) g_assert (objfile != NULL); command = g_strdup_printf ("\"%s%s\" %s %s /OUT:%s %s %s", tool_prefix, LD_NAME, acfg->aot_opts.nodebug ? LD_OPTIONS : LD_DEBUG_OPTIONS, ld_flags, wrap_path (tmp_outfile_name), wrap_path (objfile), wrap_path (llvm_ofile)); -#elif defined(LD_NAME) - command = g_strdup_printf ("%s%s %s -o %s %s %s %s", tool_prefix, LD_NAME, LD_OPTIONS, - wrap_path (tmp_outfile_name), wrap_path (llvm_ofile), - wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags); +#else + GString *str; + + str = g_string_new (""); +#if defined(LD_NAME) + g_string_append_printf (str, "%s%s %s", tool_prefix, LD_NAME, LD_OPTIONS); #else // Default (linux) - if (acfg->aot_opts.tool_prefix) { + if (acfg->aot_opts.tool_prefix) /* Cross compiling */ - command = g_strdup_printf ("\"%sld\" %s -shared -o %s %s %s %s", tool_prefix, LD_OPTIONS, - wrap_path (tmp_outfile_name), wrap_path (llvm_ofile), - wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags); - } else { - char *args = g_strdup_printf ("%s -shared -o %s %s %s %s", LD_OPTIONS, - wrap_path (tmp_outfile_name), wrap_path (llvm_ofile), - wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags); + g_string_append_printf (str, "\"%sld\" %s", tool_prefix, LD_OPTIONS); + else if (acfg->aot_opts.llvm_only) + g_string_append_printf (str, "%s", acfg->aot_opts.clangxx); + else + g_string_append_printf (str, "\"%sld\"", tool_prefix); + g_string_append_printf (str, " -shared"); +#endif + g_string_append_printf (str, " -o %s %s %s %s", + wrap_path (tmp_outfile_name), wrap_path (llvm_ofile), + wrap_path (g_strdup_printf ("%s." AS_OBJECT_FILE_SUFFIX, acfg->tmpfname)), ld_flags); - if (acfg->aot_opts.llvm_only) { - command = g_strdup_printf ("%s %s", acfg->aot_opts.clangxx, args); - } else { - command = g_strdup_printf ("\"%sld\" %s", tool_prefix, args); - } - g_free (args); - } +#if defined(TARGET_MACH) + g_string_append_printf (str, " -Wl,-install_name,%s%s", g_path_get_basename (acfg->image->name), MONO_SOLIB_EXT); +#endif + + command = g_string_free (str, FALSE); #endif aot_printf (acfg, "Executing the native linker: %s\n", command); if (execute_system (command) != 0) { @@ -13026,7 +13128,6 @@ add_preinit_got_slots (MonoAotCompile *acfg) * Allocate the first few GOT entries to information which is needed frequently, or it is needed * during method initialization etc. */ - ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo)); ji->type = MONO_PATCH_INFO_IMAGE; ji->data.image = acfg->image; @@ -13471,6 +13572,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, mono_aot_parse_options (aot_options, &acfg->aot_opts); + if (acfg->aot_opts.direct_extern_calls && !(acfg->aot_opts.llvm && acfg->aot_opts.static_link)) { + aot_printerrf (acfg, "The 'direct-extern-calls' option requires the 'llvm' and 'static' options.\n"); + return 1; + } + // start dedup MonoAotState *astate = NULL; gboolean is_dedup_dummy = FALSE; @@ -14131,6 +14237,12 @@ mono_aot_is_shared_got_offset (int offset) return FALSE; } +gboolean +mono_aot_is_externally_callable (MonoMethod *cmethod) +{ + return FALSE; +} + int mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointer **aot_state) { diff --git a/mono/mini/aot-compiler.h b/mono/mini/aot-compiler.h index 2b789a65426..69090e695fa 100644 --- a/mono/mini/aot-compiler.h +++ b/mono/mini/aot-compiler.h @@ -17,6 +17,7 @@ MONO_LLVM_INTERNAL guint32 mono_aot_get_got_offset (MonoJumpInfo *ji MONO_LLVM_INTERNAL char* mono_aot_get_method_name (MonoCompile *cfg); MONO_LLVM_INTERNAL char* mono_aot_get_mangled_method_name (MonoMethod *method); MONO_LLVM_INTERNAL gboolean mono_aot_is_direct_callable (MonoJumpInfo *patch_info); +MONO_LLVM_INTERNAL gboolean mono_aot_is_externally_callable (MonoMethod *cmethod); MONO_LLVM_INTERNAL void mono_aot_mark_unused_llvm_plt_entry(MonoJumpInfo *patch_info); MONO_LLVM_INTERNAL char* mono_aot_get_plt_symbol (MonoJumpInfoType type, gconstpointer data); MONO_LLVM_INTERNAL char* mono_aot_get_direct_call_symbol (MonoJumpInfoType type, gconstpointer data); diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index ca8747e78ab..c4b9484cf63 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -61,6 +61,7 @@ #include <mono/utils/mono-digest.h> #include <mono/utils/mono-threads-coop.h> #include <mono/utils/bsearch.h> +#include <mono/utils/mono-tls-inline.h> #include "mini.h" #include "seq-points.h" @@ -70,7 +71,7 @@ #include "aot-runtime.h" #include "jit-icalls.h" #include "mini-runtime.h" -#include "mono/utils/mono-tls-inline.h" +#include "llvmonly-runtime.h" #ifndef DISABLE_AOT @@ -78,9 +79,6 @@ #define ENABLE_AOT_CACHE #endif -/* Number of got entries shared between the JIT and LLVM GOT */ -#define N_COMMON_GOT_ENTRIES 10 - #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1)) typedef struct { @@ -1985,7 +1983,7 @@ get_call_table_entry (void *table, int index, int entry_size) * Initialize the shared got entries for AMODULE. */ static void -init_amodule_got (MonoAotModule *amodule) +init_amodule_got (MonoAotModule *amodule, gboolean preinit) { MonoJumpInfo *ji; MonoMemPool *mp; @@ -2010,7 +2008,8 @@ init_amodule_got (MonoAotModule *amodule) return; } - amodule->got_initialized = GOT_INITIALIZING; + if (!preinit) + amodule->got_initialized = GOT_INITIALIZING; mp = mono_mempool_new (); npatches = amodule->info.nshared_got_entries; @@ -2024,7 +2023,19 @@ init_amodule_got (MonoAotModule *amodule) for (i = 0; i < npatches; ++i) { ji = &patches [i]; - if (ji->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR && !mono_gc_is_moving ()) { + if (amodule->shared_got [i]) { + } else if (ji->type == MONO_PATCH_INFO_AOT_MODULE) { + amodule->shared_got [i] = amodule; + } else if (preinit) { + /* + * This is called from init_amodule () during startup, so some things might not + * be setup. Initialize just the slots needed to make method initialization work. + */ + if (ji->type == MONO_PATCH_INFO_JIT_ICALL_ID) { + if (ji->data.jit_icall_id == MONO_JIT_ICALL_mini_llvm_init_method) + amodule->shared_got [i] = (gpointer)mini_llvm_init_method; + } + } else if (ji->type == MONO_PATCH_INFO_GC_CARD_TABLE_ADDR && !mono_gc_is_moving ()) { amodule->shared_got [i] = NULL; } else if (ji->type == MONO_PATCH_INFO_GC_NURSERY_START && !mono_gc_is_moving ()) { amodule->shared_got [i] = NULL; @@ -2061,8 +2072,10 @@ init_amodule_got (MonoAotModule *amodule) mono_mempool_destroy (mp); - mono_memory_barrier (); - amodule->got_initialized = GOT_INITIALIZED; + if (!preinit) { + mono_memory_barrier (); + amodule->got_initialized = GOT_INITIALIZED; + } mono_loader_unlock (); } @@ -2346,7 +2359,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer amodule->trampolines [MONO_AOT_TRAMP_FTNPTR_ARG] = (guint8 *)info->ftnptr_arg_trampolines; amodule->trampolines [MONO_AOT_TRAMP_UNBOX_ARBITRARY] = (guint8 *)info->unbox_arbitrary_trampolines; - if (mono_is_corlib_image (assembly->image)) + if (mono_is_corlib_image (assembly->image) || !strcmp (assembly->aname.name, "mscorlib") || !strcmp (assembly->aname.name, "System.Private.CoreLib")) mscorlib_aot_module = amodule; /* Compute method addresses */ @@ -2411,6 +2424,12 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer g_hash_table_insert (aot_modules, assembly, amodule); mono_aot_unlock (); + init_amodule_got (amodule, TRUE); + + if (info->flags & MONO_AOT_FILE_FLAG_WITH_LLVM) + /* Directly called methods might make calls through the PLT */ + init_plt (amodule); + if (amodule->jit_code_start) mono_jit_info_add_aot_module (assembly->image, amodule->jit_code_start, amodule->jit_code_end); if (amodule->llvm_code_start) @@ -4141,7 +4160,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM error_init (error); - init_amodule_got (amodule); + init_amodule_got (amodule, FALSE); if (domain != mono_get_root_domain ()) /* Non shared AOT code can't be used in other appdomains */ @@ -4537,6 +4556,10 @@ init_method (MonoAotModule *amodule, guint32 method_index, MonoMethod *method, M MonoGenericContext *context; MonoGenericContext ctx; + /* Might be needed if the method is externally called */ + init_plt (amodule); + init_amodule_got (amodule, FALSE); + memset (&ctx, 0, sizeof (ctx)); error_init (error); @@ -5422,7 +5445,7 @@ get_mscorlib_aot_module (void) MonoAotModule *amodule; image = mono_defaults.corlib; - if (image) + if (image && image->aot_module) amodule = image->aot_module; else amodule = mscorlib_aot_module; diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h index 31940084c2f..e774a6ca26c 100644 --- a/mono/mini/aot-runtime.h +++ b/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 171 +#define MONO_AOT_FILE_VERSION 172 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 diff --git a/mono/mini/llvmonly-runtime.c b/mono/mini/llvmonly-runtime.c index c9fbb253589..39fcb2d2888 100644 --- a/mono/mini/llvmonly-runtime.c +++ b/mono/mini/llvmonly-runtime.c @@ -790,7 +790,7 @@ init_llvmonly_method (MonoAotModule *amodule, guint32 method_index, MonoClass *i /* Called from generated code to initialize a method */ void -mini_llvm_init_method (gpointer aot_module, guint32 method_index) +mini_llvm_init_method (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index) { MonoAotModule *amodule = (MonoAotModule *)aot_module; @@ -799,7 +799,7 @@ mini_llvm_init_method (gpointer aot_module, guint32 method_index) /* Same for gshared methods with a this pointer */ void -mini_llvm_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_obj) +mini_llvm_init_gshared_method_this (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoObject *this_obj) { MonoAotModule *amodule = (MonoAotModule *)aot_module; MonoClass *klass; @@ -813,7 +813,7 @@ mini_llvm_init_gshared_method_this (gpointer aot_module, guint32 method_index, M /* Same for gshared methods with an mrgctx arg */ void -mini_llvm_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx) +mini_llvm_init_gshared_method_mrgctx (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx) { MonoAotModule *amodule = (MonoAotModule *)aot_module; @@ -822,7 +822,7 @@ mini_llvm_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, /* Same for gshared methods with a vtable arg */ void -mini_llvm_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable) +mini_llvm_init_gshared_method_vtable (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoVTable *vtable) { MonoAotModule *amodule = (MonoAotModule *)aot_module; MonoClass *klass; diff --git a/mono/mini/llvmonly-runtime.h b/mono/mini/llvmonly-runtime.h index d6e38cbba7c..55c4ed464e9 100644 --- a/mono/mini/llvmonly-runtime.h +++ b/mono/mini/llvmonly-runtime.h @@ -9,6 +9,7 @@ #define __MONO_LLVMONLY_RUNTIME_H__ #include "mini-runtime.h" +#include "aot-runtime.h" gpointer mini_llvmonly_load_method (MonoMethod *method, gboolean caller_gsharedvt, gboolean need_unbox, gpointer *out_arg, MonoError *error); MonoFtnDesc* mini_llvmonly_load_method_ftndesc (MonoMethod *method, gboolean caller_gsharedvt, gboolean need_unbox, MonoError *error); @@ -27,10 +28,10 @@ G_EXTERN_C MonoFtnDesc* mini_llvmonly_resolve_generic_virtual_iface_call (MonoVT G_EXTERN_C void mini_llvmonly_init_delegate (MonoDelegate *del); G_EXTERN_C void mini_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method); -G_EXTERN_C void mini_llvm_init_method (gpointer aot_module, guint32 method_index); -G_EXTERN_C void mini_llvm_init_gshared_method_this (gpointer aot_module, guint32 method_index, MonoObject *this_ins); -G_EXTERN_C void mini_llvm_init_gshared_method_mrgctx (gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx); -G_EXTERN_C void mini_llvm_init_gshared_method_vtable (gpointer aot_module, guint32 method_index, MonoVTable *vtable); +G_EXTERN_C void mini_llvm_init_method (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index); +G_EXTERN_C void mini_llvm_init_gshared_method_this (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoObject *this_ins); +G_EXTERN_C void mini_llvm_init_gshared_method_mrgctx (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoMethodRuntimeGenericContext *rgctx); +G_EXTERN_C void mini_llvm_init_gshared_method_vtable (MonoAotFileInfo *info, gpointer aot_module, guint32 method_index, MonoVTable *vtable); G_EXTERN_C void mini_llvmonly_throw_nullref_exception (void); diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 78a1ba847c4..1f3fc7ca606 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -6292,6 +6292,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b mono_save_args (cfg, sig, inline_args); } + if (cfg->method == method && cfg->self_init && cfg->compile_aot && !COMPILE_LLVM (cfg)) { + MonoMethod *wrapper; + MonoInst *args [2]; + int idx; + + /* + * Emit code to initialize this method by calling the init wrapper emitted by LLVM. + * This is not efficient right now, but its only used for the methods which fail + * LLVM compilation. + * FIXME: Optimize this + */ + g_assert (!cfg->gshared); + wrapper = mono_marshal_get_aot_init_wrapper (AOT_INIT_METHOD); + /* Emit this into the entry bb so it comes before the GC safe point which depends on an inited GOT */ + cfg->cbb = cfg->bb_entry; + idx = mono_aot_get_method_index (cfg->method); + EMIT_NEW_ICONST (cfg, args [0], idx); + /* Dummy */ + EMIT_NEW_ICONST (cfg, args [1], 0); + mono_emit_method_call (cfg, wrapper, args, NULL); + } + /* FIRST CODE BLOCK */ NEW_BBLOCK (cfg, tblock); tblock->cil_code = ip; diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 00cd31913b9..5f4813a5a10 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -95,6 +95,8 @@ typedef struct { LLVMValueRef unbox_tramp_indexes; LLVMValueRef unbox_trampolines; LLVMValueRef gc_poll_cold_wrapper; + LLVMValueRef info_var; + LLVMTypeRef *info_var_eltypes; int max_inited_idx, max_method_idx; gboolean has_jitted_code; gboolean static_link; @@ -423,6 +425,7 @@ static LLVMValueRef get_intrins_from_module (LLVMModuleRef lmodule, int id); static void llvm_jit_finalize_method (EmitContext *ctx); static void mono_llvm_nonnull_state_update (EmitContext *ctx, LLVMValueRef lcall, MonoMethod *call_method, LLVMValueRef *args, int num_params); static void mono_llvm_propagate_nonnull_final (GHashTable *all_specializable, MonoLLVMModule *module); +static void create_aot_info_var (MonoLLVMModule *module); static inline void set_failure (EmitContext *ctx, const char *message) @@ -1783,6 +1786,24 @@ LLVMFunctionType3 (LLVMTypeRef ReturnType, } static G_GNUC_UNUSED LLVMTypeRef +LLVMFunctionType4 (LLVMTypeRef ReturnType, + LLVMTypeRef ParamType1, + LLVMTypeRef ParamType2, + LLVMTypeRef ParamType3, + LLVMTypeRef ParamType4, + int IsVarArg) +{ + LLVMTypeRef param_types [4]; + + param_types [0] = ParamType1; + param_types [1] = ParamType2; + param_types [2] = ParamType3; + param_types [3] = ParamType4; + + return LLVMFunctionType (ReturnType, param_types, 4, IsVarArg); +} + +static G_GNUC_UNUSED LLVMTypeRef LLVMFunctionType5 (LLVMTypeRef ReturnType, LLVMTypeRef ParamType1, LLVMTypeRef ParamType2, @@ -1961,25 +1982,6 @@ typedef struct { LLVMTypeRef type; } CallSite; -static gboolean -method_is_direct_callable (MonoMethod *method) -{ - if (method->wrapper_type == MONO_WRAPPER_ALLOC) - return TRUE; - if (method->string_ctor) - return FALSE; - if (method->wrapper_type) - return FALSE; - if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) - return FALSE; - /* Can't enable this as the callee might fail llvm compilation */ - /* - if (!method->is_inflated && (mono_class_get_flags (method->klass) & TYPE_ATTRIBUTE_PUBLIC) && (method->flags & METHOD_ATTRIBUTE_PUBLIC)) - return TRUE; - */ - return FALSE; -} - static LLVMValueRef get_callee_llvmonly (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data) { @@ -1997,7 +1999,7 @@ get_callee_llvmonly (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType ty } } else if (type == MONO_PATCH_INFO_METHOD) { MonoMethod *method = (MonoMethod*)data; - if (m_class_get_image (method->klass) != ctx->module->assembly->image && method_is_direct_callable (method)) + if (m_class_get_image (method->klass) != ctx->module->assembly->image && mono_aot_is_externally_callable (method)) callee_name = mono_aot_get_mangled_method_name (method); } } @@ -2107,6 +2109,49 @@ get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gcons if (ctx->llvm_only) return get_callee_llvmonly (ctx, llvm_sig, type, data); + callee_name = NULL; + /* Cross-assembly direct calls */ + if (type == MONO_PATCH_INFO_METHOD) { + MonoMethod *cmethod = (MonoMethod*)data; + + if (m_class_get_image (cmethod->klass) != ctx->module->assembly->image) { + MonoJumpInfo tmp_ji; + + memset (&tmp_ji, 0, sizeof (MonoJumpInfo)); + tmp_ji.type = type; + tmp_ji.data.target = data; + if (mono_aot_is_direct_callable (&tmp_ji)) { + /* + * This will add a reference to cmethod's image so it will + * be loaded when the current AOT image is loaded, so + * the GOT slots used by the init method code are initialized. + */ + tmp_ji.type = MONO_PATCH_INFO_IMAGE; + tmp_ji.data.image = m_class_get_image (cmethod->klass); + ji = mono_aot_patch_info_dup (&tmp_ji); + mono_aot_get_got_offset (ji); + + callee_name = mono_aot_get_mangled_method_name (cmethod); + + callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->direct_callables, callee_name); + if (!callee) { + callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig); + + LLVMSetLinkage (callee, LLVMExternalLinkage); + + g_hash_table_insert (ctx->module->direct_callables, callee_name, callee); + } else { + /* LLVMTypeRef's are uniqued */ + if (LLVMGetElementType (LLVMTypeOf (callee)) != llvm_sig) + callee = LLVMConstBitCast (callee, LLVMPointerType (llvm_sig, 0)); + + g_free (callee_name); + } + return callee; + } + } + } + callee_name = mono_aot_get_plt_symbol (type, data); if (!callee_name) return NULL; @@ -3009,21 +3054,21 @@ static LLVMValueRef emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype) { LLVMModuleRef lmodule = module->lmodule; - LLVMValueRef func, indexes [2], got_entry_addr, args [16], callee; - LLVMBasicBlockRef entry_bb; + LLVMValueRef func, indexes [2], got_entry_addr, args [16], callee, inited_var, cmp; + LLVMBasicBlockRef entry_bb, inited_bb, notinited_bb; LLVMBuilderRef builder; LLVMTypeRef sig; MonoJumpInfo *ji; int got_offset; const char *wrapper_name = mono_marshal_get_aot_init_wrapper_name (subtype); - char *name = g_strdup_printf ("%s%s", module->global_prefix, wrapper_name); + char *name = g_strdup_printf ("%s_%s", module->global_prefix, wrapper_name); MonoJitICallId icall_id = MONO_JIT_ICALL_ZeroIsReserved; switch (subtype) { case AOT_INIT_METHOD: icall_id = MONO_JIT_ICALL_mini_llvm_init_method; func = LLVMAddFunction (lmodule, name, LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE)); - sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), FALSE); + sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), FALSE); break; case AOT_INIT_METHOD_GSHARED_MRGCTX: icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_mrgctx; // Deliberate fall-through @@ -3032,12 +3077,12 @@ emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype) if (!icall_id) icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_vtable; func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), IntPtrType (), FALSE)); - sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE); + sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), IntPtrType (), FALSE); break; case AOT_INIT_METHOD_GSHARED_THIS: icall_id = MONO_JIT_ICALL_mini_llvm_init_gshared_method_this; func = LLVMAddFunction (lmodule, name, LLVMFunctionType2 (LLVMVoidType (), LLVMInt32Type (), ObjRefType (), FALSE)); - sig = LLVMFunctionType3 (LLVMVoidType (), IntPtrType (), LLVMInt32Type (), ObjRefType (), FALSE); + sig = LLVMFunctionType4 (LLVMVoidType (), IntPtrType (), IntPtrType (), LLVMInt32Type (), ObjRefType (), FALSE); break; default: g_assert_not_reached (); @@ -3051,9 +3096,24 @@ emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype) set_cold_cconv (func); entry_bb = LLVMAppendBasicBlock (func, "ENTRY"); + builder = LLVMCreateBuilder (); LLVMPositionBuilderAtEnd (builder, entry_bb); + /* Check for is_inited here as well, since this can be called from JITted code which might not check it */ + indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + indexes [1] = LLVMGetParam (func, 0); + inited_var = LLVMBuildLoad (builder, LLVMBuildGEP (builder, module->inited_var, indexes, 2, ""), "is_inited"); + + cmp = LLVMBuildICmp (builder, LLVMIntEQ, inited_var, LLVMConstInt (LLVMTypeOf (inited_var), 0, FALSE), ""); + + inited_bb = LLVMAppendBasicBlock (func, "INITED"); + notinited_bb = LLVMAppendBasicBlock (func, "NOT_INITED"); + + LLVMBuildCondBr (builder, cmp, notinited_bb, inited_bb); + + LLVMPositionBuilderAtEnd (builder, notinited_bb); + /* get_aotconst */ ji = g_new0 (MonoJumpInfo, 1); ji->type = MONO_PATCH_INFO_AOT_MODULE; @@ -3063,10 +3123,11 @@ emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype) indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); indexes [1] = LLVMConstInt (LLVMInt32Type (), got_offset, FALSE); got_entry_addr = LLVMBuildGEP (builder, module->got_var, indexes, 2, ""); - args [0] = LLVMBuildPtrToInt (builder, LLVMBuildLoad (builder, got_entry_addr, ""), IntPtrType (), ""); - args [1] = LLVMGetParam (func, 0); + args [0] = LLVMBuildPtrToInt (builder, module->info_var, IntPtrType (), ""); + args [1] = LLVMBuildPtrToInt (builder, LLVMBuildLoad (builder, got_entry_addr, ""), IntPtrType (), ""); + args [2] = LLVMGetParam (func, 0); if (subtype) - args [2] = LLVMGetParam (func, 1); + args [3] = LLVMGetParam (func, 1); ji = g_new0 (MonoJumpInfo, 1); ji->type = MONO_PATCH_INFO_JIT_ICALL_ID; @@ -3086,6 +3147,9 @@ emit_init_icall_wrapper (MonoLLVMModule *module, MonoAotInitSubtype subtype) indexes [1] = LLVMGetParam (func, 0); LLVMBuildStore (builder, LLVMConstInt (LLVMInt8Type (), 1, FALSE), LLVMBuildGEP (builder, module->inited_var, indexes, 2, "")); + LLVMBuildBr (builder, inited_bb); + + LLVMPositionBuilderAtEnd (builder, inited_bb); LLVMBuildRetVoid (builder); LLVMVerifyFunction(func, LLVMAbortProcessAction); @@ -8281,14 +8345,6 @@ free_ctx (EmitContext *ctx) g_free (ctx); } -static gboolean -is_externally_callable (EmitContext *ctx, MonoMethod *method) -{ - if (ctx->module->llvm_only && ctx->module->static_link && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method_is_direct_callable (method))) - return TRUE; - return FALSE; -} - /* * mono_llvm_emit_method: * @@ -8343,7 +8399,7 @@ mono_llvm_emit_method (MonoCompile *cfg) if (cfg->compile_aot) { ctx->module = &aot_module; - if (is_externally_callable (ctx, cfg->method)) + if (mono_aot_is_externally_callable (cfg->method)) method_name = mono_aot_get_mangled_method_name (cfg->method); else method_name = mono_aot_get_method_name (cfg); @@ -8477,7 +8533,7 @@ emit_method_inner (EmitContext *ctx) ctx->module->max_method_idx = MAX (ctx->module->max_method_idx, cfg->method_index); const char *init_name = mono_marshal_get_aot_init_wrapper_name (info->d.aot_init.subtype); - ctx->method_name = g_strdup_printf ("%s%s", ctx->module->global_prefix, init_name); + ctx->method_name = g_strdup_printf ("%s_%s", ctx->module->global_prefix, init_name); ctx->cfg->asm_symbol = g_strdup (ctx->method_name); if (!cfg->llvm_only && ctx->module->external_symbols) { @@ -8563,7 +8619,7 @@ emit_method_inner (EmitContext *ctx) mono_llvm_add_func_attr_nv (method, "no-frame-pointer-elim", "true"); if (cfg->compile_aot) { - if (is_externally_callable (ctx, cfg->method)) { + if (mono_aot_is_externally_callable (cfg->method)) { LLVMSetLinkage (method, LLVMExternalLinkage); } else { LLVMSetLinkage (method, LLVMInternalLinkage); @@ -9977,6 +10033,7 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, module->inited_var = LLVMAddGlobal (aot_module.lmodule, inited_type, "mono_inited_tmp"); LLVMSetInitializer (module->inited_var, LLVMConstNull (inited_type)); + create_aot_info_var (module); emit_gc_safepoint_poll (module, module->lmodule, NULL); @@ -10178,22 +10235,19 @@ AddJitGlobal (MonoLLVMModule *module, LLVMTypeRef type, const char *name) g_free (s); return v; } +#define FILE_INFO_NFIELDS (2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 22 + 5) static void -emit_aot_file_info (MonoLLVMModule *module) +create_aot_info_var (MonoLLVMModule *module) { LLVMTypeRef file_info_type; - LLVMTypeRef *eltypes, eltype; + LLVMTypeRef *eltypes; LLVMValueRef info_var; - LLVMValueRef *fields; int i, nfields, tindex; - MonoAotFileInfo *info; LLVMModuleRef lmodule = module->lmodule; - info = &module->aot_info; - /* Create an LLVM type to represent MonoAotFileInfo */ - nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 22 + 5; + nfields = FILE_INFO_NFIELDS; eltypes = g_new (LLVMTypeRef, nfields); tindex = 0; eltypes [tindex ++] = LLVMInt32Type (); @@ -10214,6 +10268,26 @@ emit_aot_file_info (MonoLLVMModule *module) LLVMStructSetBody (file_info_type, eltypes, nfields, FALSE); info_var = LLVMAddGlobal (lmodule, file_info_type, "mono_aot_file_info"); + + module->info_var = info_var; + module->info_var_eltypes = eltypes; +} + +static void +emit_aot_file_info (MonoLLVMModule *module) +{ + LLVMTypeRef *eltypes, eltype; + LLVMValueRef info_var; + LLVMValueRef *fields; + int i, nfields, tindex; + MonoAotFileInfo *info; + LLVMModuleRef lmodule = module->lmodule; + + info = &module->aot_info; + info_var = module->info_var; + eltypes = module->info_var_eltypes; + nfields = FILE_INFO_NFIELDS; + if (module->static_link) { LLVMSetVisibility (info_var, LLVMHiddenVisibility); LLVMSetLinkage (info_var, LLVMInternalLinkage); @@ -10362,7 +10436,7 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = llvm_array_from_bytes (info->aotid, 16); g_assert (tindex == nfields); - LLVMSetInitializer (info_var, LLVMConstNamedStruct (file_info_type, fields, nfields)); + LLVMSetInitializer (info_var, LLVMConstNamedStruct (LLVMGetElementType (LLVMTypeOf (info_var)), fields, nfields)); if (module->static_link) { char *s, *p; diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 4da03218ad6..6b4d396c9d9 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -4646,10 +4646,10 @@ register_icalls (void) register_dyn_icall (mini_get_dbg_callbacks ()->user_break, mono_debugger_agent_user_break, mono_icall_sig_void, FALSE); - register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_int, TRUE); - register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_int_object, TRUE); - register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_int_ptr, TRUE); - register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_int_ptr, TRUE); + register_icall (mini_llvm_init_method, mono_icall_sig_void_ptr_ptr_int, TRUE); + register_icall (mini_llvm_init_gshared_method_this, mono_icall_sig_void_ptr_ptr_int_object, TRUE); + register_icall (mini_llvm_init_gshared_method_mrgctx, mono_icall_sig_void_ptr_ptr_int_ptr, TRUE); + register_icall (mini_llvm_init_gshared_method_vtable, mono_icall_sig_void_ptr_ptr_int_ptr, TRUE); register_icall_no_wrapper (mini_llvmonly_resolve_iface_call_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr); register_icall_no_wrapper (mini_llvmonly_resolve_vcall_gsharedvt, mono_icall_sig_ptr_object_int_ptr_ptr); diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 75c3eef0312..cb6a8f7737f 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -2844,7 +2844,6 @@ insert_safepoint (MonoCompile *cfg, MonoBasicBlock *bblock) } else if (bblock == cfg->bb_entry) { mono_bblock_insert_after_ins (bblock, bblock->last_ins, poll_addr); mono_bblock_insert_after_ins (bblock, poll_addr, ins); - } else { mono_bblock_insert_before_ins (bblock, NULL, poll_addr); mono_bblock_insert_after_ins (bblock, poll_addr, ins); @@ -3177,6 +3176,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0; cfg->interp = (flags & JIT_FLAG_INTERP) != 0; cfg->use_current_cpu = (flags & JIT_FLAG_USE_CURRENT_CPU) != 0; + cfg->self_init = (flags & JIT_FLAG_SELF_INIT) != 0; cfg->backend = current_backend; if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) { diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 41f50916a5e..44e9e099ee6 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1228,6 +1228,8 @@ typedef enum { JIT_FLAG_INTERP = (1 << 9), /* Allow AOT to use all current CPU instructions */ JIT_FLAG_USE_CURRENT_CPU = (1 << 10), + /* Generate code to self-init the method for AOT */ + JIT_FLAG_SELF_INIT = (1 << 11) } JitFlags; /* Bit-fields in the MonoBasicBlock.region */ @@ -1443,6 +1445,7 @@ typedef struct { guint llvm_only : 1; guint interp : 1; guint use_current_cpu : 1; + guint self_init : 1; guint domainvar_inited : 1; guint8 uses_simd_intrinsics; int r4_stack_type; |