From d4b06b1a9e3c56e343c42efad2211c04c196a0cf Mon Sep 17 00:00:00 2001 From: monojenkins Date: Fri, 14 Feb 2020 20:34:11 -0500 Subject: [PATCH] [llvm] Fix LLVM JIT when used with multiple AppDomains. (#32219) We currently reuse LLVM's command line parsing system to configure and enable passes. When using the default code generator pass configuration, the `ImplicitNullChecks` and `X86CallFrameOptimization` passes can only be enabled or disabled via the command line argument parser: the `cl::opt`s controlling these (and many other) passes are private to their translation units, and `TargetPassConfig`/`X86PassConfig` read from these `cl::opt`s with no other means to override these values. Unfortunately, some LLVM command line options have restrictions on the number of times they may be set, and running the LLVM command line argument parser more than once can fail, because the 'number of occurrences' counter is stored in each global `cl::opt`. This causes several tests to fail--one such test is unhandled-exception-7.cs. This change: - removes the lazy LLVM JIT initialization logic and instead runs this initialization once during `mini_init`, - moves some stray JIT-only code from mini-llvm.c to llvm-jit.cpp, - wraps the declarations in domain-internals.h with a `G_BEGIN_DECLS`/`G_END_DECLS` pair, so that they avoid name mangling when included in C++ source, and - removes `exception_cb` and `emitted_cb`: neither were actually used by live code. --- src/mono/mono/metadata/domain-internals.h | 4 + src/mono/mono/mini/llvm-jit.cpp | 60 +++++++--- src/mono/mono/mini/llvm-jit.h | 12 +- src/mono/mono/mini/mini-llvm-loaded.c | 6 +- src/mono/mono/mini/mini-llvm.c | 133 ++-------------------- src/mono/mono/mini/mini-llvm.h | 2 +- src/mono/mono/mini/mini-runtime.c | 4 +- 7 files changed, 67 insertions(+), 154 deletions(-) diff --git a/src/mono/mono/metadata/domain-internals.h b/src/mono/mono/metadata/domain-internals.h index 987487f1c8925..3c2830da7ed8c 100644 --- a/src/mono/mono/metadata/domain-internals.h +++ b/src/mono/mono/metadata/domain-internals.h @@ -39,6 +39,8 @@ #define MONO_APPDOMAIN_SETUP_CLASS_NAME "MonoDomainSetup" #endif +G_BEGIN_DECLS + /* * If this is set, the memory belonging to appdomains is not freed when a domain is * unloaded, and assemblies loaded by the appdomain are not unloaded either. This @@ -702,4 +704,6 @@ mono_domain_ambient_alc (MonoDomain *domain) return mono_domain_default_alc (domain); } +G_END_DECLS + #endif /* __MONO_METADATA_DOMAIN_INTERNALS_H__ */ diff --git a/src/mono/mono/mini/llvm-jit.cpp b/src/mono/mono/mini/llvm-jit.cpp index 9f4d4d2cb8c2a..06e4ef46b0a91 100644 --- a/src/mono/mono/mini/llvm-jit.cpp +++ b/src/mono/mono/mini/llvm-jit.cpp @@ -65,7 +65,22 @@ void bzero (void *to, size_t count) { memset (to, 0, count); } #endif -static AllocCodeMemoryCb *alloc_code_mem_cb; +static MonoNativeTlsKey current_cfg_tls_id; + +static unsigned char* +alloc_code (LLVMValueRef function, int size) +{ + MonoCompile *cfg; + + cfg = (MonoCompile*)mono_native_tls_get_value (current_cfg_tls_id); + + if (cfg) { + // FIXME: dynamic + return (unsigned char*)mono_domain_code_reserve (cfg->domain, size); + } else { + return (unsigned char*)mono_domain_code_reserve (mono_domain_get (), size); + } +} class MonoJitMemoryManager : public RTDyldMemoryManager { @@ -118,7 +133,7 @@ MonoJitMemoryManager::allocateCodeSection(uintptr_t Size, unsigned SectionID, StringRef SectionName) { - uint8_t *mem = alloc_code_mem_cb (NULL, Size); + uint8_t *mem = alloc_code (NULL, Size); PendingCodeMem.push_back (sys::MemoryBlock ((void *)mem, Size)); return mem; } @@ -254,11 +269,6 @@ struct MonoLLVMJIT { } }; -static void -init_mono_llvm_jit () -{ -} - static MonoLLVMJIT * make_mono_llvm_jit (TargetMachine *target_machine) { @@ -420,15 +430,10 @@ class MonoLLVMJIT { static MonoJitMemoryManager *mono_mm; -static void -init_mono_llvm_jit () -{ - mono_mm = new MonoJitMemoryManager (); -} - static MonoLLVMJIT * make_mono_llvm_jit (TargetMachine *target_machine) { + mono_mm = new MonoJitMemoryManager (); return new MonoLLVMJIT(target_machine, mono_mm); } @@ -436,10 +441,12 @@ make_mono_llvm_jit (TargetMachine *target_machine) static MonoLLVMJIT *jit; -MonoEERef -mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee) +void +mono_llvm_jit_init () { - alloc_code_mem_cb = alloc_cb; + if (jit != nullptr) return; + + mono_native_tls_alloc (¤t_cfg_tls_id, NULL); InitializeNativeTarget (); InitializeNativeTargetAsmPrinter(); @@ -464,9 +471,17 @@ mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, auto TM = EB.selectTarget (); assert (TM); - init_mono_llvm_jit (); jit = make_mono_llvm_jit (TM); +} + +void +mono_llvm_jit_set_tls_cfg (MonoCompile *cfg) { + mono_native_tls_set_value (current_cfg_tls_id, cfg); +} +MonoEERef +mono_llvm_create_ee (LLVMExecutionEngineRef *ee) +{ return NULL; } @@ -494,8 +509,17 @@ mono_llvm_set_unhandled_exception_handler (void) { } +void +mono_llvm_jit_init () +{ +} + +void +mono_llvm_jit_set_tls_cfg (MonoCompile *cfg) { +} + MonoEERef -mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee) +mono_llvm_create_ee (LLVMExecutionEngineRef *ee) { g_error ("LLVM JIT not supported on this platform."); return NULL; diff --git a/src/mono/mono/mini/llvm-jit.h b/src/mono/mono/mini/llvm-jit.h index 220ae1b86c26a..d59edaf40c64a 100644 --- a/src/mono/mono/mini/llvm-jit.h +++ b/src/mono/mono/mini/llvm-jit.h @@ -31,14 +31,16 @@ G_BEGIN_DECLS -typedef unsigned char * (AllocCodeMemoryCb) (LLVMValueRef function, int size); -typedef void (FunctionEmittedCb) (LLVMValueRef function, void *start, void *end); -typedef void (ExceptionTableCb) (void *data); - typedef void* MonoEERef; +void +mono_llvm_jit_init (void); + +void +mono_llvm_jit_set_tls_cfg (MonoCompile *cfg); + MonoEERef -mono_llvm_create_ee (AllocCodeMemoryCb *alloc_cb, FunctionEmittedCb *emitted_cb, ExceptionTableCb *exception_cb, LLVMExecutionEngineRef *ee); +mono_llvm_create_ee (LLVMExecutionEngineRef *ee); void mono_llvm_dispose_ee (MonoEERef *mono_ee); diff --git a/src/mono/mono/mini/mini-llvm-loaded.c b/src/mono/mono/mini/mini-llvm-loaded.c index 6b0e0dfdc4bbe..9d21ae8629f0f 100644 --- a/src/mono/mono/mini/mini-llvm-loaded.c +++ b/src/mono/mono/mini/mini-llvm-loaded.c @@ -10,7 +10,7 @@ #ifdef MONO_LLVM_LOADED typedef struct { - void (*init)(void); + void (*init)(gboolean); void (*cleanup)(void); void (*emit_method)(MonoCompile *cfg); void (*emit_call)(MonoCompile *cfg, MonoCallInst *call); @@ -28,9 +28,9 @@ typedef struct { static LoadedBackend backend; void -mono_llvm_init (void) +mono_llvm_init (gboolean enable_jit) { - backend.init (); + backend.init (enable_jit); } void diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 9235488ac1cd7..329c868e9e3a8 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -410,8 +410,6 @@ typedef enum { INTRINS_NUM } IntrinsicId; -static MonoNativeTlsKey current_cfg_tls_id; - static MonoLLVMModule aot_module; static GHashTable *intrins_id_to_name; @@ -8381,7 +8379,7 @@ mono_llvm_emit_method (MonoCompile *cfg) mono_loader_lock (); /* Used to communicate with the callbacks */ - mono_native_tls_set_value (current_cfg_tls_id, cfg); + mono_llvm_jit_set_tls_cfg (cfg); ctx = g_new0 (EmitContext, 1); ctx->cfg = cfg; @@ -8482,7 +8480,7 @@ mono_llvm_emit_method (MonoCompile *cfg) free_ctx (ctx); - mono_native_tls_set_value (current_cfg_tls_id, NULL); + mono_llvm_jit_set_tls_cfg (NULL); mono_loader_unlock (); } @@ -9949,13 +9947,11 @@ add_types (MonoLLVMModule *module) } void -mono_llvm_init (void) +mono_llvm_init (gboolean enable_jit) { GHashTable *h; int i; - mono_native_tls_alloc (¤t_cfg_tls_id, NULL); - h = g_hash_table_new (NULL, NULL); for (i = 0; i < INTRINS_NUM; ++i) g_hash_table_insert (h, GINT_TO_POINTER (intrinsics [i].id), (gpointer)intrinsics [i].name); @@ -9965,6 +9961,9 @@ mono_llvm_init (void) for (i = 0; i < INTRINS_NUM; ++i) g_hash_table_insert (h, (gpointer)intrinsics [i].name, GINT_TO_POINTER (intrinsics [i].id + 1)); intrins_name_to_id = h; + + if (enable_jit) + mono_llvm_jit_init (); } void @@ -11030,7 +11029,7 @@ mono_llvm_free_domain_info (MonoDomain *domain) } void -mono_llvm_init (void) +mono_llvm_init (gboolean enable_jit) { } @@ -11040,122 +11039,6 @@ mono_llvm_init (void) /* LLVM JIT support */ -static unsigned char* -alloc_cb (LLVMValueRef function, int size) -{ - MonoCompile *cfg; - - cfg = (MonoCompile*)mono_native_tls_get_value (current_cfg_tls_id); - - if (cfg) { - // FIXME: dynamic - return (unsigned char*)mono_domain_code_reserve (cfg->domain, size); - } else { - return (unsigned char*)mono_domain_code_reserve (mono_domain_get (), size); - } -} - -static void -emitted_cb (LLVMValueRef function, void *start, void *end) -{ - MonoCompile *cfg; - - cfg = (MonoCompile*)mono_native_tls_get_value (current_cfg_tls_id); - g_assert (cfg); - cfg->code_len = (guint8*)end - (guint8*)start; -} - -static void -exception_cb (void *data) -{ - MonoCompile *cfg; - MonoJitExceptionInfo *ei; - guint32 ei_len, i, j, nested_len, nindex; - gpointer *type_info; - int this_reg, this_offset; - - cfg = (MonoCompile*)mono_native_tls_get_value (current_cfg_tls_id); - g_assert (cfg); - - /* - * data points to a DWARF FDE structure, convert it to our unwind format and - * save it. - * An alternative would be to save it directly, and modify our unwinder to work - * with it. - */ - cfg->encoded_unwind_ops = mono_unwind_decode_fde ((guint8*)data, &cfg->encoded_unwind_ops_len, NULL, &ei, &ei_len, &type_info, &this_reg, &this_offset); - if (cfg->verbose_level > 1) - mono_print_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len); - - /* Count nested clauses */ - nested_len = 0; - for (i = 0; i < ei_len; ++i) { - gint32 cindex1 = *(gint32*)type_info [i]; - MonoExceptionClause *clause1 = &cfg->header->clauses [cindex1]; - - for (j = 0; j < cfg->header->num_clauses; ++j) { - int cindex2 = j; - MonoExceptionClause *clause2 = &cfg->header->clauses [cindex2]; - - if (cindex1 != cindex2 && clause1->try_offset >= clause2->try_offset && clause1->handler_offset <= clause2->handler_offset) { - nested_len ++; - } - } - } - - cfg->llvm_ex_info = (MonoJitExceptionInfo*)mono_mempool_alloc0 (cfg->mempool, (ei_len + nested_len) * sizeof (MonoJitExceptionInfo)); - cfg->llvm_ex_info_len = ei_len + nested_len; - memcpy (cfg->llvm_ex_info, ei, ei_len * sizeof (MonoJitExceptionInfo)); - /* Fill the rest of the information from the type info */ - for (i = 0; i < ei_len; ++i) { - gint32 clause_index = *(gint32*)type_info [i]; - MonoExceptionClause *clause = &cfg->header->clauses [clause_index]; - - cfg->llvm_ex_info [i].flags = clause->flags; - cfg->llvm_ex_info [i].data.catch_class = clause->data.catch_class; - cfg->llvm_ex_info [i].clause_index = clause_index; - } - - /* - * For nested clauses, the LLVM produced exception info associates the try interval with - * the innermost handler, while mono expects it to be associated with all nesting clauses. - * So add new clauses which use the IL info (catch class etc.) from the nesting clause, - * and everything else from the nested clause. - */ - nindex = ei_len; - for (i = 0; i < ei_len; ++i) { - gint32 cindex1 = *(gint32*)type_info [i]; - MonoExceptionClause *clause1 = &cfg->header->clauses [cindex1]; - - for (j = 0; j < cfg->header->num_clauses; ++j) { - int cindex2 = j; - MonoExceptionClause *clause2 = &cfg->header->clauses [cindex2]; - MonoJitExceptionInfo *nesting_ei, *nested_ei; - - if (cindex1 != cindex2 && clause1->try_offset >= clause2->try_offset && clause1->handler_offset <= clause2->handler_offset) { - /* clause1 is the nested clause */ - nested_ei = &cfg->llvm_ex_info [i]; - nesting_ei = &cfg->llvm_ex_info [nindex]; - nindex ++; - - memcpy (nesting_ei, nested_ei, sizeof (MonoJitExceptionInfo)); - - nesting_ei->flags = clause2->flags; - nesting_ei->data.catch_class = clause2->data.catch_class; - nesting_ei->clause_index = cindex2; - } - } - } - g_assert (nindex == ei_len + nested_len); - cfg->llvm_this_reg = this_reg; - cfg->llvm_this_offset = this_offset; - - /* type_info [i] is cfg mempool allocated, no need to free it */ - - g_free (ei); - g_free (type_info); -} - /* * decode_llvm_eh_info: * @@ -11269,7 +11152,7 @@ init_jit_module (MonoDomain *domain) module->context = LLVMGetGlobalContext (); module->intrins_by_id = g_new0 (LLVMValueRef, INTRINS_NUM); - module->mono_ee = (MonoEERef*)mono_llvm_create_ee (alloc_cb, emitted_cb, exception_cb, &module->ee); + module->mono_ee = (MonoEERef*)mono_llvm_create_ee (&module->ee); add_intrinsics (module->lmodule); add_types (module); diff --git a/src/mono/mono/mini/mini-llvm.h b/src/mono/mono/mini/mini-llvm.h index d46676ae328d7..048812c3bcfc1 100644 --- a/src/mono/mono/mini/mini-llvm.h +++ b/src/mono/mono/mini/mini-llvm.h @@ -19,7 +19,7 @@ typedef enum { } LLVMModuleFlags; /* KEEP THIS IN SYNCH WITH mini-llvm-loaded.c */ -MONO_LLVM_INTERNAL void mono_llvm_init (void); +MONO_LLVM_INTERNAL void mono_llvm_init (gboolean enable_jit); MONO_LLVM_INTERNAL void mono_llvm_cleanup (void); MONO_LLVM_INTERNAL void mono_llvm_emit_method (MonoCompile *cfg); MONO_LLVM_INTERNAL void mono_llvm_emit_call (MonoCompile *cfg, MonoCallInst *call); diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index a3dae0fa5fea6..7358aae12b44a 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -4015,7 +4015,7 @@ llvm_init_inner (void) if (!mono_llvm_load (NULL)) return FALSE; - mono_llvm_init (); + mono_llvm_init (!mono_compile_aot); return TRUE; } #endif @@ -4270,7 +4270,7 @@ mini_init (const char *filename, const char *runtime_version) } } if (mono_use_llvm) - mono_llvm_init (); + mono_llvm_init (!mono_compile_aot); #endif mono_trampolines_init ();