[aot] Add support for making direct cross-assembly calls in llvm mode. (#2225)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Fri, 31 Jan 2020 16:41:39 +0000 (11:41 -0500)
committerGitHub <noreply@github.com>
Fri, 31 Jan 2020 16:41:39 +0000 (11:41 -0500)
Co-authored-by: Zoltan Varga <vargaz@gmail.com>
12 files changed:
src/mono/mono/metadata/icall-signatures.h
src/mono/mono/mini/aot-compiler.c
src/mono/mono/mini/aot-compiler.h
src/mono/mono/mini/aot-runtime.c
src/mono/mono/mini/aot-runtime.h
src/mono/mono/mini/llvmonly-runtime.c
src/mono/mono/mini/llvmonly-runtime.h
src/mono/mono/mini/method-to-ir.c
src/mono/mono/mini/mini-llvm.c
src/mono/mono/mini/mini-runtime.c
src/mono/mono/mini/mini.c
src/mono/mono/mini/mini.h

index aa15e21..876c427 100644 (file)
@@ -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))       \
index 6c43e33..d194a35 100644 (file)
@@ -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)
 {
index 2b789a6..69090e6 100644 (file)
@@ -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);
index ca8747e..c4b9484 100644 (file)
@@ -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;
index 3194008..e774a6c 100644 (file)
@@ -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
 
index c9fbb25..39fcb2d 100644 (file)
@@ -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;
index d6e38cb..55c4ed4 100644 (file)
@@ -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);
 
index 78a1ba8..1f3fc7c 100644 (file)
@@ -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;
index 00cd319..5f4813a 100644 (file)
@@ -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;
index 4da0321..6b4d396 100644 (file)
@@ -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);
index 75c3eef..cb6a8f7 100644 (file)
@@ -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) {
index 41f5091..44e9e09 100644 (file)
@@ -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;