diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 81bab8cf90b096..16dd9413608570 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -403,6 +403,9 @@ typedef struct MonoAotCompile { GHashTable *gshared_instances; /* Hash of gshared methods where specific instances are preferred */ GHashTable *prefer_instances; + GPtrArray *exported_methods; + guint32 n_exported_methods; + guint32 exported_methods_offset; #ifdef EMIT_WIN32_UNWIND_INFO GList *unwind_info_section_cache; #endif @@ -5303,6 +5306,8 @@ MONO_RESTORE_WARNING export_name = (char *)g_malloc (slen + 1); sprintf (export_name, "%s%s", acfg->user_symbol_prefix, named); export_name [slen] = 0; + + g_ptr_array_add (acfg->exported_methods, method); } } mono_reflection_free_custom_attr_data_args_noalloc (decoded_args); @@ -10874,6 +10879,24 @@ emit_method_info_table (MonoAotCompile *acfg) method_flags [acfg->cfgs [i]->method_index] = GUINT32_TO_UINT8 (acfg->cfgs [i]->aot_method_flags); } emit_aot_data (acfg, MONO_AOT_TABLE_METHOD_FLAGS_TABLE, "method_flags_table", method_flags, acfg->nmethods); + + /* + * If there is a runtime init callback, emit a table of exported methods. + * These methods can be called before the runtime is initialized, so they need to + * be inited when their AOT image is loaded. + */ + if (acfg->aot_opts.runtime_init_callback) { + acfg->n_exported_methods = acfg->exported_methods->len; + if (acfg->exported_methods->len) { + guint32 *arr = g_new0 (guint32, acfg->exported_methods->len); + for (i = 0; i < acfg->exported_methods->len; ++i) { + MonoMethod *m = (MonoMethod*)g_ptr_array_index (acfg->exported_methods, i); + arr [i] = mono_method_get_token (m); + } + acfg->exported_methods_offset = add_to_blob_aligned (acfg, (guint8*)arr, acfg->exported_methods->len * sizeof (guint32), 4); + g_free (arr); + } + } } #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */ @@ -11860,6 +11883,9 @@ init_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info) info->simd_opts = acfg->simd_opts; info->gc_name_index = acfg->gc_name_offset; info->datafile_size = acfg->datafile_offset; + info->n_exported_methods = acfg->n_exported_methods; + info->exported_methods = acfg->exported_methods_offset; + for (i = 0; i < MONO_AOT_TABLE_NUM; ++i) info->table_offsets [i] = acfg->table_offsets [i]; for (i = 0; i < MONO_AOT_TRAMP_NUM; ++i) @@ -12029,6 +12055,8 @@ emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info) emit_int32 (acfg, info->datafile_size); emit_int32 (acfg, 0); emit_int32 (acfg, 0); + emit_int32 (acfg, info->n_exported_methods); + emit_int32 (acfg, info->exported_methods); for (i = 0; i < MONO_AOT_TABLE_NUM; ++i) emit_int32 (acfg, info->table_offsets [i]); @@ -13867,6 +13895,7 @@ acfg_create (MonoAssembly *ass, guint32 jit_opts) acfg->profile_methods = g_hash_table_new (NULL, NULL); acfg->gshared_instances = g_hash_table_new (NULL, NULL); acfg->prefer_instances = g_hash_table_new (NULL, NULL); + acfg->exported_methods = g_ptr_array_new (); mono_os_mutex_init_recursive (&acfg->mutex); init_got_info (&acfg->got_info); @@ -13947,6 +13976,7 @@ acfg_free (MonoAotCompile *acfg) g_ptr_array_free (acfg->image_table, TRUE); g_ptr_array_free (acfg->globals, TRUE); g_ptr_array_free (acfg->unwind_ops, TRUE); + g_ptr_array_free (acfg->exported_methods, TRUE); g_hash_table_destroy (acfg->method_indexes); g_hash_table_destroy (acfg->method_depth); g_hash_table_destroy (acfg->plt_offset_to_entry); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 683fee00852e75..4d92418cb74d1c 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -2346,6 +2346,25 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer } else { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT: image '%s' found.", found_aot_name); } + + /* Initialize exported methods since they can be called without being loaded */ + if (!amodule->out_of_date && info->n_exported_methods) { + guint32 *exported = (guint32*)(amodule->blob + info->exported_methods); + + for (guint32 i = 0; i < info->n_exported_methods; ++i) { + ERROR_DECL (load_error); + guint32 token = exported [i]; + MonoMethod *m = mono_get_method_checked (assembly->image, token, NULL, NULL, load_error); + mono_error_cleanup (load_error); /* FIXME don't swallow the error */ + error_init (load_error); + if (m) { + mono_class_init_internal (m->klass); + mono_aot_get_method (m, load_error); + mono_error_cleanup (load_error); /* FIXME don't swallow the error */ + error_init (load_error); + } + } + } } /* diff --git a/src/mono/mono/mini/aot-runtime.h b/src/mono/mono/mini/aot-runtime.h index e9da680fa5c591..77f227f6c65950 100644 --- a/src/mono/mono/mini/aot-runtime.h +++ b/src/mono/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 184 +#define MONO_AOT_FILE_VERSION 185 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 @@ -221,6 +221,8 @@ typedef struct MonoAotFileInfo guint32 llvm_unbox_tramp_num; /* Size of entries in llvm_unbox_tramp_indexes (2/4) */ guint32 llvm_unbox_tramp_elemsize; + guint32 n_exported_methods; + guint32 exported_methods; /* Arrays */ /* Offsets for tables inside the data file if MONO_AOT_FILE_FLAG_SEPARATE_DATA is set */ diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 479e767c5a5ff4..9e1e3d61b00579 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -13405,7 +13405,7 @@ AddJitGlobal (MonoLLVMModule *module, LLVMTypeRef type, const char *name) return v; } #define FILE_INFO_NUM_HEADER_FIELDS 2 -#define FILE_INFO_NUM_SCALAR_FIELDS 23 +#define FILE_INFO_NUM_SCALAR_FIELDS 25 #define FILE_INFO_NUM_ARRAY_FIELDS 5 #define FILE_INFO_NUM_AOTID_FIELDS 1 #define FILE_INFO_NFIELDS (FILE_INFO_NUM_HEADER_FIELDS + MONO_AOT_FILE_INFO_NUM_SYMBOLS + FILE_INFO_NUM_SCALAR_FIELDS + FILE_INFO_NUM_ARRAY_FIELDS + FILE_INFO_NUM_AOTID_FIELDS) @@ -13603,6 +13603,8 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = const_int32 (info->datafile_size); fields [tindex ++] = const_int32 (module->unbox_tramp_num); fields [tindex ++] = const_int32 (module->unbox_tramp_elemsize); + fields [tindex ++] = const_int32 (info->n_exported_methods); + fields [tindex ++] = const_int32 (info->exported_methods); /* Arrays */ fields [tindex ++] = llvm_array_from_uints (LLVMInt32Type (), info->table_offsets, MONO_AOT_TABLE_NUM); fields [tindex ++] = llvm_array_from_uints (LLVMInt32Type (), info->num_trampolines, MONO_AOT_TRAMP_NUM);