From a2974980e8ab0421d4c5d0436f44d1defe87ad92 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Tue, 28 Feb 2023 21:56:16 -0500 Subject: [PATCH] [mono][aot] Emit a list of exported methods into the AOT image and load them when the image is loaded. If there is a runtime attach function specified, these methods can call into the runtime before its initialized. In order for this to work, the runtime attach function needs to load all the AOT images containing such methods, and load_aot_module () will load and initialize these methods using the newly emitted table. --- src/mono/mono/mini/aot-compiler.c | 30 ++++++++++++++++++++++++++++++ src/mono/mono/mini/aot-runtime.c | 19 +++++++++++++++++++ src/mono/mono/mini/aot-runtime.h | 4 +++- src/mono/mono/mini/mini-llvm.c | 4 +++- 4 files changed, 55 insertions(+), 2 deletions(-) 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);