diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 3348e6024210..ee1d4b943d38 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -307,6 +307,7 @@ typedef struct MonoAotCompile { MonoAotOptions aot_opts; guint32 nmethods; + guint32 nextra_methods; guint32 opts; guint32 simd_opts; MonoMemPool *mempool; @@ -3716,8 +3717,12 @@ add_method_with_index (MonoAotCompile *acfg, MonoMethod *method, int index, gboo acfg->nmethods = acfg->methods->len + 1; } - if (method->wrapper_type || extra) + if (method->wrapper_type || extra) { + int token = mono_metadata_token_index (method->token) - 1; + if (token >= 0) + acfg->nextra_methods++; g_ptr_array_add (acfg->extra_methods, method); + } } static gboolean @@ -6969,7 +6974,7 @@ emit_trampolines (MonoAotCompile *acfg) int tramp_type; #endif - if ((!mono_aot_mode_is_full (&acfg->aot_opts) || acfg->aot_opts.llvm_only) && !acfg->aot_opts.interp) + if ((!mono_aot_mode_is_full (&acfg->aot_opts) || acfg->aot_opts.llvm_only) && !mono_aot_mode_is_interp (&acfg->aot_opts)) return; g_assert (acfg->image->assembly); @@ -10328,6 +10333,7 @@ init_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info) info->got_size = acfg->got_offset * sizeof (gpointer); info->plt_size = acfg->plt_offset; info->nmethods = acfg->nmethods; + info->nextra_methods = acfg->nextra_methods; info->flags = acfg->flags; info->opts = acfg->opts; info->simd_opts = acfg->simd_opts; @@ -10464,6 +10470,7 @@ emit_aot_file_info (MonoAotCompile *acfg, MonoAotFileInfo *info) emit_int32 (acfg, info->got_size); emit_int32 (acfg, info->plt_size); emit_int32 (acfg, info->nmethods); + emit_int32 (acfg, info->nextra_methods); emit_int32 (acfg, info->flags); emit_int32 (acfg, info->opts); emit_int32 (acfg, info->simd_opts); @@ -12654,6 +12661,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, acfg->is_full_aot = TRUE; } + if (mono_aot_mode_is_interp (&acfg->aot_opts)) { + acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_INTERP); + acfg->is_full_aot = TRUE; + } + if (mono_threads_are_safepoints_enabled ()) acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_SAFEPOINTS); @@ -12679,7 +12691,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, } } - if (!(acfg->aot_opts.interp && !mono_aot_mode_is_full (&acfg->aot_opts))) { + if (!(mono_aot_mode_is_interp (&acfg->aot_opts) && !mono_aot_mode_is_full (&acfg->aot_opts))) { for (int method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) g_ptr_array_add (acfg->method_order,GUINT_TO_POINTER (method_index)); } @@ -12738,7 +12750,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, if (mono_aot_mode_is_full (&acfg->aot_opts) || mono_aot_mode_is_hybrid (&acfg->aot_opts)) mono_set_partial_sharing_supported (TRUE); - if (!(acfg->aot_opts.interp && !mono_aot_mode_is_full (&acfg->aot_opts))) { + if (!(mono_aot_mode_is_interp (&acfg->aot_opts) && !mono_aot_mode_is_full (&acfg->aot_opts))) { res = collect_methods (acfg); if (!res) return 1; diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 3039554ee745..5c3fd563565d 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -1821,7 +1821,7 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char char *build_info; char *msg = NULL; gboolean usable = TRUE; - gboolean full_aot, safepoints; + gboolean full_aot, interp, safepoints; guint32 excluded_cpu_optimizations; if (strcmp (assembly->image->guid, info->assembly_guid)) { @@ -1837,15 +1837,22 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char g_free (build_info); full_aot = info->flags & MONO_AOT_FILE_FLAG_FULL_AOT; + interp = info->flags & MONO_AOT_FILE_FLAG_INTERP; if (mono_aot_only && !full_aot) { - msg = g_strdup_printf ("not compiled with --aot=full"); - usable = FALSE; + if (!interp) { + msg = g_strdup_printf ("not compiled with --aot=full"); + usable = FALSE; + } } if (!mono_aot_only && full_aot) { msg = g_strdup_printf ("compiled with --aot=full"); usable = FALSE; } + if (mono_use_interpreter && !interp) { + msg = g_strdup_printf ("not compiled with --aot=interp"); + usable = FALSE; + } if (mono_llvm_only && !(info->flags & MONO_AOT_FILE_FLAG_LLVM_ONLY)) { msg = g_strdup_printf ("not compiled with --aot=llvmonly"); usable = FALSE; @@ -2149,7 +2156,7 @@ if (container_assm_name && !container_amodule) { } if (!usable) { - if (mono_aot_only && !mono_use_interpreter) { + if (mono_aot_only) { g_error ("Failed to load AOT module '%s' while running in aot-only mode: %s.\n", found_aot_name, msg); } else { mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT: module %s is unusable: %s.", found_aot_name, msg); @@ -4048,7 +4055,8 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM } return NULL; } - code = (guint8 *)amodule->methods [method_index]; + if (method_index < amodule->info.nmethods) + code = (guint8 *)amodule->methods [method_index]; } info = &amodule->blob [mono_aot_get_offset (amodule->method_info_offsets, method_index)]; @@ -4815,6 +4823,11 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method, MonoError *error) } else { /* Common case */ method_index = mono_metadata_token_index (method->token) - 1; + + guint32 num_methods = amodule->info.nmethods - amodule->info.nextra_methods; + if (method_index >= num_methods) + /* method not available in AOT image */ + return NULL; } code = (guint8 *)load_method (domain, amodule, m_class_get_image (klass), method, method->token, method_index, error); diff --git a/mono/mini/aot-runtime.h b/mono/mini/aot-runtime.h index d0249e3d274c..5da167fc17b6 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 145 +#define MONO_AOT_FILE_VERSION 146 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 @@ -69,6 +69,7 @@ typedef enum { MONO_AOT_FILE_FLAG_SAFEPOINTS = 32, MONO_AOT_FILE_FLAG_SEPARATE_DATA = 64, MONO_AOT_FILE_FLAG_EAGER_LOAD = 128, + MONO_AOT_FILE_FLAG_INTERP = 256, } MonoAotFileFlags; typedef enum { @@ -168,6 +169,8 @@ typedef struct MonoAotFileInfo guint32 plt_size; /* Number of methods */ guint32 nmethods; + /* Number of extra methods */ + guint32 nextra_methods; /* A union of MonoAotFileFlags */ guint32 flags; /* Optimization flags used to compile the module */ diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index a92ba91641be..7c0ebaa7a5f4 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -774,9 +774,12 @@ jit_call_supported (MonoMethod *method, MonoMethodSignature *sig) if (method->string_ctor) return FALSE; - if (mono_aot_only && m_class_get_image (method->klass)->aot_module) - /* The AOTed version of the called method is assumed to be available in full-aot mode */ - return TRUE; + if (mono_aot_only && m_class_get_image (method->klass)->aot_module) { + ERROR_DECL (error); + gpointer addr = mono_jit_compile_method_jit_only (method, error); + if (addr && mono_error_ok (error)) + return TRUE; + } for (l = mono_interp_jit_classes; l; l = l->next) { char *class_name = l->data; diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 321fccb49ebb..a787d0f12f73 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -8802,7 +8802,7 @@ emit_aot_file_info (MonoLLVMModule *module) info = &module->aot_info; /* Create an LLVM type to represent MonoAotFileInfo */ - nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 16 + 5; + nfields = 2 + MONO_AOT_FILE_INFO_NUM_SYMBOLS + 17 + 5; eltypes = g_new (LLVMTypeRef, nfields); tindex = 0; eltypes [tindex ++] = LLVMInt32Type (); @@ -8811,7 +8811,7 @@ emit_aot_file_info (MonoLLVMModule *module) for (i = 0; i < MONO_AOT_FILE_INFO_NUM_SYMBOLS; ++i) eltypes [tindex ++] = LLVMPointerType (LLVMInt8Type (), 0); /* Scalars */ - for (i = 0; i < 15; ++i) + for (i = 0; i < 16; ++i) eltypes [tindex ++] = LLVMInt32Type (); /* Arrays */ eltypes [tindex ++] = LLVMArrayType (LLVMInt32Type (), MONO_AOT_TABLE_NUM); @@ -8933,6 +8933,7 @@ emit_aot_file_info (MonoLLVMModule *module) fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->got_size, FALSE); fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->plt_size, FALSE); fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->nmethods, FALSE); + fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->nextra_methods, FALSE); fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->flags, FALSE); fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->opts, FALSE); fields [tindex ++] = LLVMConstInt (LLVMInt32Type (), info->simd_opts, FALSE); diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 2f16279167cc..9586703403af 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -2144,7 +2144,7 @@ compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error mono_lookup_pinvoke_call (method, NULL, NULL); } nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only); - gpointer compiled_method = mono_compile_method_checked (nm, error); + gpointer compiled_method = mono_jit_compile_method_jit_only (nm, error); return_val_if_nok (error, NULL); code = mono_get_addr_from_ftnptr (compiled_method); jinfo = mono_jit_info_table_find (target_domain, code); @@ -2176,19 +2176,24 @@ compile_special (MonoMethod *method, MonoDomain *target_domain, MonoError *error } else if (*name == 'I' && (strcmp (name, "Invoke") == 0)) { if (mono_llvm_only) { nm = mono_marshal_get_delegate_invoke (method, NULL); - gpointer compiled_ptr = mono_compile_method_checked (nm, error); + gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error); mono_error_assert_ok (error); return mono_get_addr_from_ftnptr (compiled_ptr); } + + /* HACK: missing gsharedvt_out wrappers to do transition to del tramp in interp-only mode */ + if (mono_use_interpreter) + return NULL; + return mono_create_delegate_trampoline (target_domain, method->klass); } else if (*name == 'B' && (strcmp (name, "BeginInvoke") == 0)) { nm = mono_marshal_get_delegate_begin_invoke (method); - gpointer compiled_ptr = mono_compile_method_checked (nm, error); + gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error); mono_error_assert_ok (error); return mono_get_addr_from_ftnptr (compiled_ptr); } else if (*name == 'E' && (strcmp (name, "EndInvoke") == 0)) { nm = mono_marshal_get_delegate_end_invoke (method); - gpointer compiled_ptr = mono_compile_method_checked (nm, error); + gpointer compiled_ptr = mono_jit_compile_method_jit_only (nm, error); mono_error_assert_ok (error); return mono_get_addr_from_ftnptr (compiled_ptr); } @@ -2372,7 +2377,7 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_ if (!code) code = compile_special (method, target_domain, error); - if (!code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_UNKNOWN) + if (!jit_only && !code && mono_aot_only && mono_use_interpreter && method->wrapper_type != MONO_WRAPPER_UNKNOWN) code = mini_get_interp_callbacks ()->create_method_pointer (method, error); if (!code) { @@ -2661,17 +2666,19 @@ typedef struct { MonoClass *ret_box_class; MonoMethodSignature *sig; gboolean gsharedvt_invoke; + gboolean use_interp; gpointer *wrapper_arg; } RuntimeInvokeInfo; static RuntimeInvokeInfo* -create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error) +create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, gboolean use_interp, MonoError *error) { MonoMethod *invoke; RuntimeInvokeInfo *info; info = g_new0 (RuntimeInvokeInfo, 1); info->compiled_method = compiled_method; + info->use_interp = use_interp; if (mono_llvm_only && method->string_ctor) info->sig = mono_marshal_get_string_ctor_signature (method); else @@ -2953,27 +2960,33 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } } + gboolean use_interp = FALSE; + if (callee) { - compiled_method = mono_jit_compile_method (callee, error); + compiled_method = mono_jit_compile_method_jit_only (callee, error); if (!compiled_method) { g_assert (!mono_error_ok (error)); - return NULL; - } - if (mono_llvm_only) { - ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL); - callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); - if (callee_gsharedvt) - callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji))); - } + if (mono_use_interpreter) + use_interp = TRUE; + else + return NULL; + } else { + if (mono_llvm_only) { + ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL); + callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); + if (callee_gsharedvt) + callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji))); + } - if (!callee_gsharedvt) - compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE); + if (!callee_gsharedvt) + compiled_method = mini_add_method_trampoline (callee, compiled_method, mono_method_needs_static_rgctx_invoke (callee, TRUE), FALSE); + } } else { compiled_method = NULL; } - info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error); + info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, use_interp, error); if (!mono_error_ok (error)) return NULL; @@ -3009,21 +3022,30 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec *exc = NULL; #ifdef MONO_ARCH_DYN_CALL_SUPPORTED + static RuntimeInvokeDynamicFunction dyn_runtime_invoke = NULL; + if (info->dyn_call_info) { + if (!dyn_runtime_invoke) { + mono_domain_lock (domain); + + invoke = mono_marshal_get_runtime_invoke_dynamic (); + dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method_jit_only (invoke, error); + if (!dyn_runtime_invoke && mono_use_interpreter) { + info->use_interp = TRUE; + info->dyn_call_info = NULL; + } else if (!mono_error_ok (error)) { + mono_domain_unlock (domain); + return NULL; + } + mono_domain_unlock (domain); + } + } if (info->dyn_call_info) { MonoMethodSignature *sig = mono_method_signature (method); gpointer *args; - static RuntimeInvokeDynamicFunction dyn_runtime_invoke; int i, pindex, buf_size; guint8 *buf; guint8 retval [256]; - if (!dyn_runtime_invoke) { - invoke = mono_marshal_get_runtime_invoke_dynamic (); - dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error); - if (!mono_error_ok (error)) - return NULL; - } - /* Convert the arguments to the format expected by start_dyn_call () */ args = (void **)g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer)); pindex = 0; @@ -3064,6 +3086,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } #endif + if (info->use_interp) { + error_init (error); + return mini_get_interp_callbacks ()->runtime_invoke (method, obj, params, exc, error); + } + MonoObject *result; if (mono_llvm_only) {