diff options
author | Rodrigo Kumpera <kumpera@users.noreply.github.com> | 2018-11-06 15:46:18 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-06 15:46:18 +0300 |
commit | ce08c3263264559b9312e791db265ca951fab59c (patch) | |
tree | ed2cec43366461367d1bf8176c365230e6df155b | |
parent | c200ccbb6265d6564cf72217b58991874f5148e5 (diff) | |
parent | ff4496f0af83c2ef4b69ff68c30edf8584f3f548 (diff) |
Merge pull request #11444 from vargaz/wasm-work10
[wasm] AOT work.
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | mcs/class/corlib/System/TimeZoneInfo.WebAssembly.cs | 30 | ||||
-rw-r--r-- | mcs/class/corlib/System/TimeZoneInfo.cs | 4 | ||||
-rw-r--r-- | mcs/class/corlib/corlib.csproj | 1 | ||||
-rw-r--r-- | mcs/class/corlib/corlib.dll.sources | 1 | ||||
-rw-r--r-- | mono/eglib/glib.h | 4 | ||||
-rw-r--r-- | mono/metadata/class.c | 32 | ||||
-rw-r--r-- | mono/mini/aot-compiler.c | 108 | ||||
-rw-r--r-- | mono/mini/aot-runtime.c | 24 | ||||
-rw-r--r-- | mono/mini/intrinsics.c | 9 | ||||
-rw-r--r-- | mono/mini/mini-llvm-loaded.c | 9 | ||||
-rw-r--r-- | mono/mini/mini-llvm.c | 327 | ||||
-rw-r--r-- | mono/mini/mini-llvm.h | 1 | ||||
-rw-r--r-- | mono/mini/mini-runtime.c | 2 | ||||
-rw-r--r-- | mono/mini/mini.c | 2 | ||||
-rw-r--r-- | mono/mini/mini.h | 3 | ||||
-rw-r--r-- | sdks/builds/wasm.mk | 2 | ||||
-rw-r--r-- | sdks/wasm/driver.c | 3 | ||||
-rw-r--r-- | sdks/wasm/packager.cs | 117 |
19 files changed, 504 insertions, 182 deletions
diff --git a/configure.ac b/configure.ac index fa7a2d939ad..c196023b558 100644 --- a/configure.ac +++ b/configure.ac @@ -1436,7 +1436,7 @@ fi AC_ARG_ENABLE(minimal, [ --enable-minimal=LIST drop support for LIST subsystems. LIST is a comma-separated list from: aot, profiler, decimal, pinvoke, debug, appdomains, verifier, reflection_emit, reflection_emit_save, large_code, logging, com, ssa, generics, attach, jit, interpreter, simd, soft_debug, perfcounters, normalization, desktop_loader, shared_perfcounters, remoting, - security, lldb, mdb, sgen_marksweep_conc, sgen_split_nursery, sgen_gc_bridge, sgen_debug_helpers.], + security, lldb, mdb, assert_messages, sgen_marksweep_conc, sgen_split_nursery, sgen_gc_bridge, sgen_debug_helpers.], [ for feature in `echo "$enable_minimal" | sed -e "s/,/ /g"`; do eval "mono_feature_disable_$feature='yes'" @@ -1607,6 +1607,11 @@ if test "x$mono_feature_disable_mdb" = "xyes"; then AC_MSG_NOTICE([Disabled support for .mdb symbol files.]) fi +if test "x$mono_feature_disable_assert_messages" = "xyes"; then + AC_DEFINE(DISABLE_ASSERT_MESSAGES, 1, [Disable assertion messages.]) + AC_MSG_NOTICE([Disabled assertion messages.]) +fi + if test "x$mono_feature_disable_sgen_marksweep_conc" = "xyes"; then AC_DEFINE(DISABLE_SGEN_MAJOR_MARKSWEEP_CONC, 1, [Disable concurrent gc support in SGEN.]) AC_MSG_NOTICE([Disabled concurrent gc support in SGEN.]) diff --git a/mcs/class/corlib/System/TimeZoneInfo.WebAssembly.cs b/mcs/class/corlib/System/TimeZoneInfo.WebAssembly.cs new file mode 100644 index 00000000000..e58cb8e5c21 --- /dev/null +++ b/mcs/class/corlib/System/TimeZoneInfo.WebAssembly.cs @@ -0,0 +1,30 @@ +#if WASM + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Runtime.InteropServices; + +namespace System { + + public partial class TimeZoneInfo { + + static TimeZoneInfo CreateLocal () + { + return TimeZoneInfo.Utc; + } + + static TimeZoneInfo FindSystemTimeZoneByIdCore (string id) + { + throw new NotImplementedException (); + } + + static void GetSystemTimeZonesCore (List<TimeZoneInfo> systemTimeZones) + { + } + } +} + +#endif + diff --git a/mcs/class/corlib/System/TimeZoneInfo.cs b/mcs/class/corlib/System/TimeZoneInfo.cs index 7cffacce059..1496be002d7 100644 --- a/mcs/class/corlib/System/TimeZoneInfo.cs +++ b/mcs/class/corlib/System/TimeZoneInfo.cs @@ -149,7 +149,7 @@ namespace System return true; } -#if !MONODROID && !MONOTOUCH && !XAMMAC +#if !MONODROID && !MONOTOUCH && !XAMMAC && !WASM static TimeZoneInfo CreateLocal () { #if WIN_PLATFORM @@ -245,7 +245,7 @@ namespace System throw new NotImplementedException ("This method is not implemented for this platform"); #endif } -#endif // !MONODROID && !MONOTOUCH && !XAMMAC +#endif // !MONODROID && !MONOTOUCH && !XAMMAC && !WASM string standardDisplayName; public string StandardName { diff --git a/mcs/class/corlib/corlib.csproj b/mcs/class/corlib/corlib.csproj index f67b81e0262..1dd4fb207bd 100644 --- a/mcs/class/corlib/corlib.csproj +++ b/mcs/class/corlib/corlib.csproj @@ -1975,6 +1975,7 @@ <Compile Include="System\TimeZoneInfo.Android.cs" />
<Compile Include="System\TimeZoneInfo.MonoTouch.cs" />
<Compile Include="System\TimeZoneInfo.Serialization.cs" />
+ <Compile Include="System\TimeZoneInfo.WebAssembly.cs" />
<Compile Include="System\TimeZoneInfo.WinRT.cs" />
<Compile Include="System\TimeZoneInfo.cs" />
<Compile Include="System\TypeIdentifier.cs" />
diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index ff85e9c147c..94176c2222a 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -135,6 +135,7 @@ corefx/TimeZoneInfo.cs System/TimeZoneInfo.cs System/TimeZoneInfo.Android.cs System/TimeZoneInfo.MonoTouch.cs +System/TimeZoneInfo.WebAssembly.cs System/TimeZoneInfo.Serialization.cs System/TimeZoneInfo.WinRT.cs ../../build/common/MonoTODOAttribute.cs diff --git a/mono/eglib/glib.h b/mono/eglib/glib.h index edb579bb85d..098d84001f8 100644 --- a/mono/eglib/glib.h +++ b/mono/eglib/glib.h @@ -883,7 +883,11 @@ GUnicodeBreakType g_unichar_break_type (gunichar c); #endif /* g_assert is a boolean expression; the precise value is not preserved, just true or false. */ +#ifdef DISABLE_ASSERT_MESSAGES +#define g_assert(x) (G_LIKELY((x)) ? 1 : (g_assertion_message ("* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, "<disabled>"), 0)) +#else #define g_assert(x) (G_LIKELY((x)) ? 1 : (g_assertion_message ("* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, #x), 0)) +#endif #define g_assert_not_reached() G_STMT_START { g_assertion_message ("* Assertion: should not be reached at %s:%d\n", __FILE__, __LINE__); eg_unreachable(); } G_STMT_END diff --git a/mono/metadata/class.c b/mono/metadata/class.c index e170241a99c..263f2228657 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -615,6 +615,23 @@ mono_type_is_valid_generic_argument (MonoType *type) } } +static gboolean +can_inflate_gparam_with (MonoGenericParam *gparam, MonoType *type) +{ + if (!mono_type_is_valid_generic_argument (type)) + return FALSE; + /* Avoid inflating gparams with valuetype constraints with ref types during gsharing */ + MonoGenericParamInfo *info = mono_generic_param_info (gparam); + if (info && (info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT)) { + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) { + MonoGenericParam *inst_gparam = type->data.generic_param; + if (inst_gparam->gshared_constraint && inst_gparam->gshared_constraint->type == MONO_TYPE_OBJECT) + return FALSE; + } + } + return TRUE; +} + static MonoType* inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error) { @@ -627,15 +644,16 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont MonoGenericInst *inst = context->method_inst; if (!inst) return NULL; + MonoGenericParam *gparam = type->data.generic_param; if (num >= inst->type_argc) { - const char *pname = mono_generic_param_name (type->data.generic_param); + const char *pname = mono_generic_param_name (gparam); mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations", num, pname ? pname : "", inst->type_argc); return NULL; } - if (!mono_type_is_valid_generic_argument (inst->type_argv [num])) { - const char *pname = mono_generic_param_name (type->data.generic_param); + if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) { + const char *pname = mono_generic_param_name (gparam); mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x", num, pname ? pname : "", inst->type_argv [num]->type); return NULL; @@ -656,18 +674,20 @@ inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *cont MonoGenericInst *inst = context->class_inst; if (!inst) return NULL; + MonoGenericParam *gparam = type->data.generic_param; if (num >= inst->type_argc) { - const char *pname = mono_generic_param_name (type->data.generic_param); + const char *pname = mono_generic_param_name (gparam); mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations", num, pname ? pname : "", inst->type_argc); return NULL; } - if (!mono_type_is_valid_generic_argument (inst->type_argv [num])) { - const char *pname = mono_generic_param_name (type->data.generic_param); + if (!can_inflate_gparam_with (gparam, inst->type_argv [num])) { + const char *pname = mono_generic_param_name (gparam); mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x", num, pname ? pname : "", inst->type_argv [num]->type); return NULL; } + nt = mono_metadata_type_dup_with_cmods (image, inst->type_argv [num], type); nt->byref = type->byref; nt->attrs = type->attrs; diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 5a1dfad0528..10102343d82 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -3814,6 +3814,18 @@ get_plt_entry (MonoAotCompile *acfg, MonoJumpInfo *patch_info) return res; } +static guint32 +lookup_got_offset (MonoAotCompile *acfg, gboolean llvm, MonoJumpInfo *ji) +{ + guint32 got_offset; + GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info; + + got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (info->patch_to_got_offset_by_type [ji->type], ji)); + if (got_offset) + return got_offset - 1; + g_assert_not_reached (); +} + /** * get_got_offset: * @@ -5113,12 +5125,13 @@ add_types_from_method_header (MonoAotCompile *acfg, MonoMethod *method) depth = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->method_depth, method)); - sig = mono_method_signature_internal (method); - + sig = mono_method_signature_checked (method, error); if (sig) { for (j = 0; j < sig->param_count; ++j) if (sig->params [j]->type == MONO_TYPE_GENERICINST) add_generic_class_with_depth (acfg, mono_class_from_mono_type_internal (sig->params [j]), depth + 1, "arg"); + } else { + mono_error_cleanup (error); } header = mono_method_get_header_checked (method, error); @@ -6303,7 +6316,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint } static void -encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, gboolean llvm, int first_got_offset, guint8 *buf, guint8 **endbuf) +encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, gboolean llvm, guint8 *buf, guint8 **endbuf) { guint8 *p = buf; guint32 pindex, offset; @@ -6317,8 +6330,8 @@ encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, gboo if (patch_info->type == MONO_PATCH_INFO_NONE || patch_info->type == MONO_PATCH_INFO_BB) /* Nothing to do */ continue; - - offset = get_got_offset (acfg, llvm, patch_info); + /* This shouldn't allocate a new offset */ + offset = lookup_got_offset (acfg, llvm, patch_info); encode_value (offset, p, &p); } @@ -6334,7 +6347,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) MonoJumpInfo *patch_info; guint32 method_index; guint8 *p, *buf; - guint32 first_got_offset; method = cfg->orig_method; @@ -6346,8 +6358,6 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) g_ptr_array_add (patches, patch_info); g_ptr_array_sort (patches, compare_patches); - first_got_offset = acfg->cfgs [method_index]->got_offset; - /**********************/ /* Encode method info */ /**********************/ @@ -6403,7 +6413,7 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg) if (n_patches) g_assert (cfg->has_got_slots); - encode_patch_list (acfg, patches, n_patches, cfg->compile_llvm, first_got_offset, p, &p); + encode_patch_list (acfg, patches, n_patches, cfg->compile_llvm, p, &p); g_ptr_array_free (patches, TRUE); @@ -6992,7 +7002,7 @@ emit_plt (MonoAotCompile *acfg) * create_jit_info_for_trampoline (). */ static G_GNUC_UNUSED void -emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, gboolean emit_tinfo) +emit_trampoline_full (MonoAotCompile *acfg, MonoTrampInfo *info, gboolean emit_tinfo) { char start_symbol [MAX_SYMBOL_SIZE]; char end_symbol [MAX_SYMBOL_SIZE]; @@ -7053,7 +7063,7 @@ emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, buf = (guint8 *)g_malloc (buf_size); p = buf; - encode_patch_list (acfg, patches, patches->len, FALSE, got_offset, p, &p); + encode_patch_list (acfg, patches, patches->len, FALSE, p, &p); g_assert (p - buf < buf_size); g_ptr_array_free (patches, TRUE); @@ -7100,9 +7110,9 @@ emit_trampoline_full (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info, } static G_GNUC_UNUSED void -emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info) +emit_trampoline (MonoAotCompile *acfg, MonoTrampInfo *info) { - emit_trampoline_full (acfg, got_offset, info, TRUE); + emit_trampoline_full (acfg, info, TRUE); } static void @@ -7140,53 +7150,53 @@ emit_trampolines (MonoAotCompile *acfg) continue; #endif mono_arch_create_generic_trampoline ((MonoTrampolineType)tramp_type, &info, acfg->aot_opts.use_trampolines_page? 2: TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); } /* Emit the exception related code pieces */ mono_arch_get_restore_context (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_get_call_filter (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_get_throw_exception (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_get_rethrow_exception (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_get_rethrow_preserve_exception (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_get_throw_corlib_exception (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES mono_arch_create_sdb_trampoline (TRUE, &info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); mono_arch_create_sdb_trampoline (FALSE, &info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); #endif #ifdef MONO_ARCH_GSHAREDVT_SUPPORTED mono_arch_get_gsharedvt_trampoline (&info, TRUE); if (info) { - emit_trampoline_full (acfg, acfg->got_offset, info, TRUE); + emit_trampoline_full (acfg, info, TRUE); /* Create a separate out trampoline for more information in stack traces */ info->name = g_strdup ("gsharedvt_out_trampoline"); - emit_trampoline_full (acfg, acfg->got_offset, info, TRUE); + emit_trampoline_full (acfg, info, TRUE); mono_tramp_info_free (info); } #endif @@ -7198,7 +7208,7 @@ emit_trampolines (MonoAotCompile *acfg) while (l) { MonoTrampInfo *info = (MonoTrampInfo *)l->data; - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); l = l->next; } } @@ -7209,18 +7219,18 @@ emit_trampolines (MonoAotCompile *acfg) offset = MONO_RGCTX_SLOT_MAKE_RGCTX (i); mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); offset = MONO_RGCTX_SLOT_MAKE_MRGCTX (i); mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); } #ifdef MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE mono_arch_create_general_rgctx_lazy_fetch_trampoline (&info, TRUE); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); mono_tramp_info_free (info); #endif @@ -7232,17 +7242,17 @@ emit_trampolines (MonoAotCompile *acfg) while (l) { MonoTrampInfo *info = (MonoTrampInfo *)l->data; - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); l = l->next; } } if (mono_aot_mode_is_interp (&acfg->aot_opts)) { mono_arch_get_interp_to_native_trampoline (&info); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); #ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE mono_arch_get_native_to_interp_trampoline (&info); - emit_trampoline (acfg, acfg->got_offset, info); + emit_trampoline (acfg, info); #endif } @@ -8068,6 +8078,10 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) if (acfg->aot_opts.profile_only && !method->is_inflated && !g_hash_table_lookup (acfg->profile_methods, method)) return; + if (method->is_generic || mono_class_is_gtd (method->klass)) + /* generic method which has no ref instantiation */ + return; + mono_atomic_inc_i32 (&acfg->stats.mcount); #if 0 @@ -11235,6 +11249,17 @@ emit_unwind_info_sections_win32 (MonoAotCompile *acfg, const char *function_star #endif static gboolean +should_emit_gsharedvt_method (MonoAotCompile *acfg, MonoMethod *method) +{ +#ifdef TARGET_WASM + if (acfg->image == mono_get_corlib () && !strcmp (m_class_get_name (method->klass), "Vector`1")) + /* The SIMD fallback code in Vector<T> is very large, and not likely to be used */ + return FALSE; +#endif + return TRUE; +} + +static gboolean collect_methods (MonoAotCompile *acfg) { int mindex, i; @@ -11282,12 +11307,12 @@ collect_methods (MonoAotCompile *acfg) if (method->is_generic || mono_class_is_gtd (method->klass)) { /* Compile the ref shared version instead */ - method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error); - if (!method) { - aot_printerrf (acfg, "Failed to load method 0x%x from '%s' due to %s.\n", token, image->name, mono_error_get_message (error)); - aot_printerrf (acfg, "Run with MONO_LOG_LEVEL=debug for more information.\n"); - mono_error_cleanup (error); - return FALSE; + MonoMethod *shared_method = mini_get_shared_method_full (method, SHARE_MODE_NONE, error); + if (!shared_method) { + /* Fails ref constraints */ + /* Keep the original method, compile_method () will skip it */ + } else { + method = shared_method; } } @@ -11308,7 +11333,7 @@ collect_methods (MonoAotCompile *acfg) method = mono_get_method_checked (acfg->image, token, NULL, NULL, error); report_loader_error (acfg, error, TRUE, "Failed to load method token 0x%x due to %s\n", i, mono_error_get_message (error)); - if (method->is_generic || mono_class_is_gtd (method->klass)) { + if ((method->is_generic || mono_class_is_gtd (method->klass)) && should_emit_gsharedvt_method (acfg, method)) { MonoMethod *gshared; gshared = mini_get_shared_method_full (method, SHARE_MODE_GSHAREDVT, error); @@ -11391,6 +11416,11 @@ compile_methods (MonoAotCompile *acfg) /* This can add new methods to acfg->methods */ compile_method (acfg, (MonoMethod *)g_ptr_array_index (acfg->methods, i)); } + +#ifdef ENABLE_LLVM + if (acfg->llvm) + mono_llvm_fixup_aot_module (); +#endif } static int @@ -12695,6 +12725,7 @@ mono_compile_deferred_assemblies (guint32 opts, const char *aot_options, gpointe return res; } +#ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE static const char* interp_in_static_sigs[] = { "bool ptr int32 ptr&", "bool ptr ptr&", @@ -12726,6 +12757,7 @@ static const char* interp_in_static_sigs[] = { "void uint32 ptr&", "void" }; +#endif int mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options, gpointer **global_aot_state) diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 28f40585739..71ca8543400 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -4336,10 +4336,29 @@ add_module_cb (gpointer key, gpointer value, gpointer user_data) gboolean mono_aot_can_dedup (MonoMethod *method) { +#ifdef TARGET_WASM + /* Use a set of wrappers/instances which work */ + switch (method->wrapper_type) { + case MONO_WRAPPER_RUNTIME_INVOKE: + case MONO_WRAPPER_UNKNOWN: + return TRUE; + break; + default: + break; + } + + if (method->is_inflated && !mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE) && + !mini_is_gsharedvt_signature (mono_method_signature_internal (method)) && + !mini_is_gsharedvt_klass (method->klass)) + return TRUE; + + return FALSE; +#else gboolean not_normal_gshared = method->is_inflated && !mono_method_is_generic_sharable_full (method, TRUE, FALSE, FALSE); gboolean extra_method = (method->wrapper_type != MONO_WRAPPER_NONE) || not_normal_gshared; return extra_method; +#endif } @@ -4577,6 +4596,11 @@ mono_aot_init_gshared_method_this (gpointer aot_module, guint32 method_index, Mo g_assert (this_obj); klass = this_obj->vtable->klass; + /* + * We can't obtain the context from THIS_OBJ since it can point to a child class etc., so + * we depend on these methods to be called indirectly which causes them to be added + * to extra_methods. + */ amodule_lock (amodule); method = (MonoMethod *)g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index)); amodule_unlock (amodule); diff --git a/mono/mini/intrinsics.c b/mono/mini/intrinsics.c index 2c71bc968c2..eeaae84a58c 100644 --- a/mono/mini/intrinsics.c +++ b/mono/mini/intrinsics.c @@ -1242,6 +1242,15 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } #endif + /* Fallback if SIMD is disabled */ + if (in_corlib && !strcmp ("System.Numerics", cmethod_klass_name_space) && !strcmp ("Vector", cmethod_klass_name)) { + if (!strcmp (cmethod->name, "get_IsHardwareAccelerated")) { + EMIT_NEW_ICONST (cfg, ins, 0); + ins->type = STACK_I4; + return ins; + } + } + ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args); if (ins) return ins; diff --git a/mono/mini/mini-llvm-loaded.c b/mono/mini/mini-llvm-loaded.c index fb1dcac9813..8da76a13901 100644 --- a/mono/mini/mini-llvm-loaded.c +++ b/mono/mini/mini-llvm-loaded.c @@ -15,6 +15,7 @@ typedef struct { void (*emit_method)(MonoCompile *cfg); void (*emit_call)(MonoCompile *cfg, MonoCallInst *call); void (*create_aot_module)(MonoAssembly *assembly, const char *global_prefix, int initial_got_size, gboolean emit_dwarf, gboolean static_link, gboolean llvm_only); + void (*fixup_aot_module)(void); void (*emit_aot_module)(const char *filename, const char *cu_name); void (*check_method_supported)(MonoCompile *cfg); void (*emit_aot_file_info)(MonoAotFileInfo *info, gboolean has_jitted_code); @@ -62,6 +63,12 @@ mono_llvm_emit_aot_module (const char *filename, const char *cu_name) } void +mono_llvm_fixup_aot_module (void) +{ + backend.fixup_aot_module (); +} + +void mono_llvm_check_method_supported (MonoCompile *cfg) { backend.check_method_supported (cfg); @@ -117,6 +124,8 @@ mono_llvm_load (const char* bpath) if (err) goto symbol_error; err = mono_dl_symbol (llvm_lib, "mono_llvm_emit_aot_module", (void**)&backend.emit_aot_module); if (err) goto symbol_error; + err = mono_dl_symbol (llvm_lib, "mono_llvm_fixup_aot_module", (void**)&backend.fixup_aot_module); + if (err) goto symbol_error; err = mono_dl_symbol (llvm_lib, "mono_llvm_check_method_supported", (void**)&backend.check_method_supported); if (err) goto symbol_error; err = mono_dl_symbol (llvm_lib, "mono_llvm_free_domain_info", (void**)&backend.free_domain_info); diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 48227acc551..13755dd5686 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -100,6 +100,7 @@ typedef struct { LLVMValueRef sentinel_exception; void *di_builder, *cu; GHashTable *objc_selector_to_var; + GPtrArray *cfgs; } MonoLLVMModule; /* @@ -1669,7 +1670,7 @@ get_aotconst_typed (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data, if (!mono_aot_is_shared_got_offset (got_offset)) { //mono_print_ji (ji); //printf ("\n"); - ctx->has_got_access = TRUE; + ctx->cfg->got_access_count ++; } indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); @@ -1696,98 +1697,153 @@ get_aotconst (EmitContext *ctx, MonoJumpInfoType type, gconstpointer data) return get_aotconst_typed (ctx, type, data, NULL); } +typedef struct { + MonoJumpInfo *ji; + MonoMethod *method; + LLVMValueRef load; + LLVMTypeRef type; +} CallSite; + static LLVMValueRef -get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data) +get_callee_llvmonly (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data) { LLVMValueRef callee; char *callee_name; - if (ctx->llvm_only) { - callee_name = mono_aot_get_direct_call_symbol (type, data); - if (callee_name) { - /* Directly callable */ - // FIXME: Locking - callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->direct_callables, callee_name); - if (!callee) { - callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig); + callee_name = mono_aot_get_direct_call_symbol (type, data); + if (callee_name) { + /* Directly callable */ + // FIXME: Locking + callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->direct_callables, callee_name); + if (!callee) { + callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig); - LLVMSetVisibility (callee, LLVMHiddenVisibility); + LLVMSetVisibility (callee, LLVMHiddenVisibility); - g_hash_table_insert (ctx->module->direct_callables, (char*)callee_name, callee); - } else { - /* LLVMTypeRef's are uniqued */ - if (LLVMGetElementType (LLVMTypeOf (callee)) != llvm_sig) - return LLVMConstBitCast (callee, LLVMPointerType (llvm_sig, 0)); + g_hash_table_insert (ctx->module->direct_callables, (char*)callee_name, callee); + } else { + /* LLVMTypeRef's are uniqued */ + if (LLVMGetElementType (LLVMTypeOf (callee)) != llvm_sig) + return LLVMConstBitCast (callee, LLVMPointerType (llvm_sig, 0)); - g_free (callee_name); - } - return callee; + g_free (callee_name); } + return callee; + } - /* - * Change references to jit icalls to the icall wrappers when in corlib, so - * they can be called directly. - */ - if (ctx->module->assembly->image == mono_get_corlib () && type == MONO_PATCH_INFO_INTERNAL_METHOD) { - MonoJitICallInfo *info = mono_find_jit_icall_by_name ((const char*)data); - g_assert (info); + /* + * Change references to jit icalls to the icall wrappers when in corlib, so + * they can be called directly. + */ + if (ctx->module->assembly->image == mono_get_corlib () && type == MONO_PATCH_INFO_INTERNAL_METHOD) { + MonoJitICallInfo *info = mono_find_jit_icall_by_name ((const char*)data); + g_assert (info); - if (info->func != info->wrapper) { - type = MONO_PATCH_INFO_METHOD; - data = mono_icall_get_wrapper_method (info); - } + if (info->func != info->wrapper) { + type = MONO_PATCH_INFO_METHOD; + data = mono_icall_get_wrapper_method (info); } + } - /* - * Calls are made through the GOT. - */ - LLVMValueRef callee = get_aotconst_typed (ctx, type, data, LLVMPointerType (llvm_sig, 0)); + /* + * Instead of emitting an indirect call through a got slot, emit a placeholder, and + * replace it with a direct call or an indirect call in mono_llvm_fixup_aot_module () + * after all methods have been emitted. + */ + if (type == MONO_PATCH_INFO_METHOD) { + MonoMethod *method = (MonoMethod*)data; + if (m_class_get_image (method->klass)->assembly == ctx->module->assembly) { + MonoJumpInfo tmp_ji; + tmp_ji.type = type; + tmp_ji.data.target = data; - if (type == MONO_PATCH_INFO_METHOD) { - MonoMethod *method = (MonoMethod*)data; - if (m_class_get_image (method->klass)->assembly == ctx->module->assembly) { - /* - * Collect instructions representing the callee into a hash so they can be replaced - * by the llvm method for the callee if the callee turns out to be direct - * callable. Currently this only requires it to not fail llvm compilation. - */ - GSList *l = (GSList*)g_hash_table_lookup (ctx->method_to_callers, method); - l = g_slist_prepend (l, callee); - g_hash_table_insert (ctx->method_to_callers, method, l); - } - } - return callee; - } else { - MonoJumpInfo *ji = NULL; + MonoJumpInfo *ji = mono_aot_patch_info_dup (&tmp_ji); + ji->next = ctx->cfg->patch_info; + ctx->cfg->patch_info = ji; + LLVMTypeRef llvm_type = LLVMPointerType (llvm_sig, 0); - callee_name = mono_aot_get_plt_symbol (type, data); - if (!callee_name) - return NULL; + ctx->cfg->got_access_count ++; - if (ctx->cfg->compile_aot) - /* Add a patch so referenced wrappers can be compiled in full aot mode */ - mono_add_patch_info (ctx->cfg, 0, type, data); + CallSite *info = g_new0 (CallSite, 1); + info->method = method; + info->ji = ji; + info->type = llvm_type; - // FIXME: Locking - callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->plt_entries, callee_name); - if (!callee) { - callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig); + /* + * Emit a dummy load to represent the callee, and either replace it with + * a reference to the llvm method for the callee, or from a load from the + * GOT. + */ + LLVMValueRef indexes [2]; + LLVMValueRef got_entry_addr, load; - LLVMSetVisibility (callee, LLVMHiddenVisibility); + LLVMBuilderRef builder = ctx->builder; + indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + got_entry_addr = LLVMBuildGEP (builder, ctx->module->got_var, indexes, 2, ""); - g_hash_table_insert (ctx->module->plt_entries, (char*)callee_name, callee); - } + load = LLVMBuildLoad (builder, got_entry_addr, ""); + load = convert (ctx, load, llvm_type); + info->load = load; - if (ctx->cfg->compile_aot) { - ji = g_new0 (MonoJumpInfo, 1); - ji->type = type; - ji->data.target = data; + GSList *l = (GSList*)g_hash_table_lookup (ctx->method_to_callers, method); + l = g_slist_prepend (l, info); + g_hash_table_insert (ctx->method_to_callers, method, l); - g_hash_table_insert (ctx->module->plt_entries_ji, ji, callee); + return load; } + } - return callee; + /* + * Calls are made through the GOT. + */ + callee = get_aotconst_typed (ctx, type, data, LLVMPointerType (llvm_sig, 0)); + + return callee; +} + +/* + * get_callee: + * + * Return an llvm value representing the callee given by the arguments. + */ +static LLVMValueRef +get_callee (EmitContext *ctx, LLVMTypeRef llvm_sig, MonoJumpInfoType type, gconstpointer data) +{ + LLVMValueRef callee; + char *callee_name; + MonoJumpInfo *ji = NULL; + + if (ctx->llvm_only) + return get_callee_llvmonly (ctx, llvm_sig, type, data); + + callee_name = mono_aot_get_plt_symbol (type, data); + if (!callee_name) + return NULL; + + if (ctx->cfg->compile_aot) + /* Add a patch so referenced wrappers can be compiled in full aot mode */ + mono_add_patch_info (ctx->cfg, 0, type, data); + + // FIXME: Locking + callee = (LLVMValueRef)g_hash_table_lookup (ctx->module->plt_entries, callee_name); + if (!callee) { + callee = LLVMAddFunction (ctx->lmodule, callee_name, llvm_sig); + + LLVMSetVisibility (callee, LLVMHiddenVisibility); + + g_hash_table_insert (ctx->module->plt_entries, (char*)callee_name, callee); } + + if (ctx->cfg->compile_aot) { + ji = g_new0 (MonoJumpInfo, 1); + ji->type = type; + ji->data.target = data; + + g_hash_table_insert (ctx->module->plt_entries_ji, ji, callee); + } + + return callee; } static LLVMValueRef @@ -2915,7 +2971,7 @@ emit_init_method (EmitContext *ctx) inited_bb = ctx->inited_bb; notinited_bb = gen_bb (ctx, "NOTINITED_BB"); - LLVMBuildCondBr (ctx->builder, cmp, notinited_bb, inited_bb); + ctx->cfg->llvmonly_init_cond = LLVMBuildCondBr (ctx->builder, cmp, notinited_bb, inited_bb); builder = ctx->builder = create_builder (ctx); LLVMPositionBuilderAtEnd (ctx->builder, notinited_bb); @@ -5531,7 +5587,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (!mono_aot_is_shared_got_offset (got_offset)) { //mono_print_ji (ji); //printf ("\n"); - ctx->has_got_access = TRUE; + ctx->cfg->got_access_count ++; } indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); @@ -7652,7 +7708,7 @@ emit_method_inner (EmitContext *ctx) * NATIVE_TO_MANAGED methods might be called on a thread not attached to the runtime, so they are initialized when loaded * in load_method (). */ - gboolean needs_init = ctx->has_got_access; + gboolean needs_init = ctx->cfg->got_access_count > 0; if (!needs_init && mono_class_get_cctor (cfg->method->klass)) { /* Needs init to run the cctor */ if (cfg->method->flags & METHOD_ATTRIBUTE_STATIC) @@ -7678,6 +7734,8 @@ emit_method_inner (EmitContext *ctx) MonoMethod *method; GSList *callers, *l, *l2; + g_ptr_array_add (ctx->module->cfgs, cfg); + /* * Add the contents of ctx->method_to_callers to module->method_to_callers. * We can't do this earlier, as it contains llvm instructions which can be @@ -7718,8 +7776,11 @@ emit_method_inner (EmitContext *ctx) if (cfg->compile_aot) { /* Don't generate native code, keep the LLVM IR */ - if (cfg->verbose_level) - printf ("%s emitted as %s\n", mono_method_full_name (cfg->method, TRUE), ctx->method_name); + if (cfg->verbose_level) { + char *name = mono_method_get_full_name (cfg->method); + printf ("%s emitted as %s\n", name, ctx->method_name); + g_free (name); + } //LLVMDumpValue (ctx->lmethod); #if LLVM_API_VERSION < 100 @@ -8818,6 +8879,7 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, /* The first few entries are reserved */ module->max_got_offset = initial_got_size; module->context = LLVMGetGlobalContext (); + module->cfgs = g_ptr_array_new (); if (llvm_only) /* clang ignores our debug info because it has an invalid version */ @@ -8943,6 +9005,94 @@ mono_llvm_create_aot_module (MonoAssembly *assembly, const char *global_prefix, module->method_to_callers = g_hash_table_new (NULL, NULL); } +void +mono_llvm_fixup_aot_module (void) +{ + MonoLLVMModule *module = &aot_module; + GHashTableIter iter; + MonoMethod *method; + GSList *callers, *l; + + if (!module->llvm_only) + return; + + /* + * Replace GOT entries for directly callable methods with the methods themselves. + * It would be easier to implement this by predefining all methods before compiling + * their bodies, but that couldn't handle the case when a method fails to compile + * with llvm. + */ + + GHashTable *patches_to_null = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal); + + g_hash_table_iter_init (&iter, module->method_to_callers); + while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&callers)) { + LLVMValueRef lmethod; + + lmethod = (LLVMValueRef)g_hash_table_lookup (module->method_to_lmethod, method); + for (l = callers; l; l = l->next) { + CallSite *site = (CallSite*)l->data; + LLVMValueRef placeholder = (LLVMValueRef)site->load; + LLVMValueRef indexes [2], got_entry_addr, load; + char *name; + + /* + * FIXME: Support inflated methods, it asserts in mono_aot_init_gshared_method_this () because the method is not in + * amodule->extra_methods. + */ + if (lmethod && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && !method->is_inflated) { + mono_llvm_replace_uses_of (placeholder, lmethod); + g_hash_table_insert (patches_to_null, site->ji, site->ji); + } else { + int got_offset = mono_aot_get_got_offset (site->ji); + module->max_got_offset = MAX (module->max_got_offset, got_offset); + + LLVMBuilderRef builder = LLVMCreateBuilder (); + LLVMPositionBuilderBefore (builder, placeholder); + indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE); + indexes [1] = LLVMConstInt (LLVMInt32Type (), (gssize)got_offset, FALSE); + got_entry_addr = LLVMBuildGEP (builder, module->got_var, indexes, 2, ""); + + name = get_aotconst_name (site->ji->type, site->ji->data.target, got_offset); + load = LLVMBuildLoad (builder, got_entry_addr, ""); + load = LLVMBuildBitCast (builder, load, site->type, name ? name : ""); + LLVMReplaceAllUsesWith (placeholder, load); + } + g_free (site); + } + } + + for (int i = 0; i < module->cfgs->len; ++i) { + /* + * Nullify the patches pointing to direct calls. This is needed to + * avoid allocating extra got slots, which is a perf problem and it + * makes module->max_got_offset invalid. + * It would be better to just store the patch_info in CallSite, but + * cfg->patch_info is copied in aot-compiler.c. + */ + MonoCompile *cfg = (MonoCompile *)g_ptr_array_index (module->cfgs, i); + for (MonoJumpInfo *patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { + if (patch_info->type == MONO_PATCH_INFO_METHOD) { + if (g_hash_table_lookup (patches_to_null, patch_info)) { + patch_info->type = MONO_PATCH_INFO_NONE; + /* Nullify the call to init_method () if possible */ + g_assert (cfg->got_access_count); + cfg->got_access_count --; +#if LLVM_API_VERSION >= 600 + if (cfg->got_access_count == 0) { + LLVMValueRef br = (LLVMValueRef)cfg->llvmonly_init_cond; + + LLVMSetSuccessor (br, 0, LLVMGetSuccessor (br, 1)); + } +#endif + } + } + } + } + + g_hash_table_destroy (patches_to_null); +} + static LLVMValueRef llvm_array_from_uints (LLVMTypeRef el_type, guint32 *values, int nvalues) { @@ -9268,35 +9418,6 @@ mono_llvm_emit_aot_module (const char *filename, const char *cu_name) emit_dbg_info (&aot_module, filename, cu_name); emit_aot_file_info (&aot_module); - /* - * Replace GOT entries for directly callable methods with the methods themselves. - * It would be easier to implement this by predefining all methods before compiling - * their bodies, but that couldn't handle the case when a method fails to compile - * with llvm. - */ - if (module->llvm_only) { - GHashTableIter iter; - MonoMethod *method; - GSList *callers, *l; - - g_hash_table_iter_init (&iter, module->method_to_callers); - while (g_hash_table_iter_next (&iter, (void**)&method, (void**)&callers)) { - LLVMValueRef lmethod; - - if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - continue; - - lmethod = (LLVMValueRef)g_hash_table_lookup (module->method_to_lmethod, method); - if (lmethod) { - for (l = callers; l; l = l->next) { - LLVMValueRef caller = (LLVMValueRef)l->data; - - mono_llvm_replace_uses_of (caller, lmethod); - } - } - } - } - /* Replace PLT entries for directly callable methods with the methods themselves */ { GHashTableIter iter; diff --git a/mono/mini/mini-llvm.h b/mono/mini/mini-llvm.h index 212bbedbb59..b2a1cc53551 100644 --- a/mono/mini/mini-llvm.h +++ b/mono/mini/mini-llvm.h @@ -23,6 +23,7 @@ void mono_llvm_free_domain_info (MonoDomain *domain) MONO_LLVM_INTER MONO_API void mono_personality (void); int mono_llvm_load (const char* bpath); void mono_llvm_create_vars (MonoCompile *cfg) MONO_LLVM_INTERNAL; +void mono_llvm_fixup_aot_module (void) MONO_LLVM_INTERNAL; gboolean mini_llvm_init (void); diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 09cac0155c0..99d430c4e69 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -2424,7 +2424,7 @@ lookup_start: } if (mono_aot_only) { - char *fullname = mono_method_full_name (method, TRUE); + char *fullname = mono_method_get_full_name (method); mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.\n", fullname); g_free (fullname); diff --git a/mono/mini/mini.c b/mono/mini/mini.c index a31eb364d06..bb3996a25c8 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -3874,7 +3874,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl } if (cfg->verbose_level > 0 && !cfg->compile_aot) { - nm = mono_method_full_name (cfg->method, TRUE); + nm = mono_method_get_full_name (cfg->method); g_print ("LLVM Method %s emitted at %p to %p (code length %d) [%s]\n", nm, cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name); diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 3ac749cd760..78ca9054131 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1474,6 +1474,9 @@ typedef struct { /* Used by AOT */ guint32 got_offset, ex_info_offset, method_info_offset, method_index; + /* For llvm */ + guint32 got_access_count; + gpointer llvmonly_init_cond; /* Symbol used to refer to this method in generated assembly */ char *asm_symbol; char *asm_debug_symbol; diff --git a/sdks/builds/wasm.mk b/sdks/builds/wasm.mk index 4342f04429d..328915f7746 100644 --- a/sdks/builds/wasm.mk +++ b/sdks/builds/wasm.mk @@ -41,7 +41,7 @@ WASM_RUNTIME_CONFIGURE_FLAGS = \ --disable-support-build \ --disable-visibility-hidden \ --enable-maintainer-mode \ - --enable-minimal=ssa,com,jit,reflection_emit_save,portability,assembly_remapping,attach,verifier,full_messages,appdomains,security,sgen_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,logging,remoting,shared_perfcounters,sgen_debug_helpers,soft_debug,interpreter \ + --enable-minimal=ssa,com,jit,reflection_emit_save,portability,assembly_remapping,attach,verifier,full_messages,appdomains,security,sgen_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,logging,remoting,shared_perfcounters,sgen_debug_helpers,soft_debug,interpreter,assert_messages \ --host=wasm32 \ --enable-llvm-runtime \ --enable-icall-export \ diff --git a/sdks/wasm/driver.c b/sdks/wasm/driver.c index 6a11b2ed45b..796b01aeb16 100644 --- a/sdks/wasm/driver.c +++ b/sdks/wasm/driver.c @@ -157,9 +157,8 @@ mono_wasm_load_runtime (const char *managed_path, int enable_debugging) mono_wasm_enable_debugging (); #endif - mono_icall_table_init (); - #ifndef ENABLE_AOT + mono_icall_table_init (); mono_ee_interp_init (""); mono_marshal_ilgen_init (); mono_method_builder_ilgen_init (); diff --git a/sdks/wasm/packager.cs b/sdks/wasm/packager.cs index a14b9cfb805..9c925af8423 100644 --- a/sdks/wasm/packager.cs +++ b/sdks/wasm/packager.cs @@ -8,13 +8,31 @@ using Mono.Options; class Driver { static bool enable_debug, enable_linker; static string app_prefix, framework_prefix, bcl_prefix, bcl_facades_prefix, out_prefix; - static HashSet<string> asm_list = new HashSet<string> (); + static HashSet<string> asm_map = new HashSet<string> (); static List<string> file_list = new List<string> (); - static List<string> assembly_names = new List<string> (); const string BINDINGS_ASM_NAME = "WebAssembly.Bindings"; const string BINDINGS_RUNTIME_CLASS_NAME = "WebAssembly.Runtime"; + class AssemblyData { + // Assembly name + public string name; + // Base filename + public string filename; + // Path outside build tree + public string src_path; + // Path of .bc file + public string bc_path; + // Path in appdir + public string app_path; + // Linker input path + public string linkin_path; + // Linker output path + public string linkout_path; + } + + static List<AssemblyData> assemblies = new List<AssemblyData> (); + enum AssemblyKind { User, Framework, @@ -115,6 +133,8 @@ class Driver { } static void Import (string ra, AssemblyKind kind) { + if (!asm_map.Add (ra)) + return; ReaderParameters rp = new ReaderParameters(); bool add_pdb = enable_debug && File.Exists (Path.ChangeExtension (ra, "pdb")); if (add_pdb) { @@ -122,14 +142,13 @@ class Driver { } rp.InMemory = true; - var image = ModuleDefinition.ReadModule (ra, rp); - if (!asm_list.Add (ra)) - return; file_list.Add (ra); - assembly_names.Add (image.Assembly.Name.Name); Debug ($"Processing {ra} debug {add_pdb}"); + var data = new AssemblyData () { name = image.Assembly.Name.Name, src_path = ra }; + assemblies.Add (data); + if (add_pdb && kind == AssemblyKind.User) file_list.Add (Path.ChangeExtension (ra, "pdb")); @@ -139,10 +158,10 @@ class Driver { } } - void GenDriver (string builddir, List<string> assembly_names, List<string> profilers) { + void GenDriver (string builddir, List<string> profilers) { var symbols = new List<string> (); - foreach (var img in assembly_names) { - symbols.Add (String.Format ("mono_aot_module_{0}_info", img.Replace ('.', '_').Replace ('-', '_'))); + foreach (var adata in assemblies) { + symbols.Add (String.Format ("mono_aot_module_{0}_info", adata.name.Replace ('.', '_').Replace ('-', '_'))); } var w = File.CreateText (Path.Combine (builddir, "driver-gen.c.in")); @@ -189,6 +208,7 @@ class Driver { var vfs_prefix = "managed"; var use_release_runtime = true; var enable_aot = false; + var enable_dedup = true; var print_usage = false; var emit_ninja = false; var runtimeTemplate = "runtime.js"; @@ -306,6 +326,19 @@ class Driver { } } + AssemblyData dedup_asm = null; + + if (enable_dedup) { + dedup_asm = new AssemblyData () { name = "aot-dummy", + filename = "aot-dummy.dll", + bc_path = "$builddir/aot-dummy.dll.bc", + app_path = "$appdir/$deploy_prefix/aot-dummy.dll", + linkout_path = "$builddir/linker-out/aot-dummy.dll" + }; + assemblies.Add (dedup_asm); + file_list.Add ("aot-dummy.dll"); + } + var file_list_str = string.Join (",", file_list.Select (f => $"\"{Path.GetFileName (f)}\"").Distinct()); var config = String.Format ("config = {{\n \tvfs_prefix: \"{0}\",\n \tdeploy_prefix: \"{1}\",\n \tenable_debugging: {2},\n \tfile_list: [ {3} ],\n", vfs_prefix, deploy_prefix, enable_debug ? "1" : "0", file_list_str); if (add_binding || true) @@ -346,8 +379,10 @@ class Driver { Console.WriteLine ("The --emscripten-sdkdir argument is required when using AOT."); Environment.Exit (1); } - GenDriver (builddir, assembly_names, profilers); + GenDriver (builddir, profilers); } + if (!enable_linker || !enable_aot) + enable_dedup = false; string profiler_libs = ""; string profiler_aot_args = ""; @@ -380,10 +415,14 @@ class Driver { // Rules ninja.WriteLine ("rule aot"); - ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross --debug {profiler_aot_args} --aot=llvmonly,asmonly,no-opt,static,direct-icalls,llvm-outfile=$outfile $src_file"); + ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross --debug {profiler_aot_args} --aot=$aot_args,llvmonly,asmonly,no-opt,static,direct-icalls,llvm-outfile=$outfile $src_file"); ninja.WriteLine (" description = [AOT] $src_file -> $outfile"); + ninja.WriteLine ("rule aot-instances"); + ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross --debug {profiler_aot_args} --aot=llvmonly,asmonly,no-opt,static,direct-icalls,llvm-outfile=$outfile,dedup-include=$dedup_image $src_files"); + ninja.WriteLine (" description = [AOT-INSTANCES] $outfile"); ninja.WriteLine ("rule mkdir"); ninja.WriteLine (" command = mkdir -p $out"); + // Copy $in to $out only if it changed ninja.WriteLine ("rule cpifdiff"); ninja.WriteLine (" command = if cmp -s $in $out ; then : ; else cp $in $out ; fi"); ninja.WriteLine (" restat = true"); @@ -424,7 +463,11 @@ class Driver { if (!Directory.Exists (path)) Directory.CreateDirectory (path); } - foreach (var assembly in asm_list) { + string aot_in_path = enable_linker ? "$builddir/linker-out" : "$builddir"; + foreach (var a in assemblies) { + var assembly = a.src_path; + if (assembly == null) + continue; string filename = Path.GetFileName (assembly); var filename_noext = Path.GetFileNameWithoutExtension (filename); @@ -432,10 +475,12 @@ class Driver { string infile = ""; if (enable_linker) { - linker_infiles += $" $builddir/linker-in/{filename}"; - linker_ofiles += $" $builddir/linker-out/{filename}"; - infile = $"$builddir/linker-out/{filename}"; - ninja.WriteLine ($"build $builddir/linker-in/{filename}: cpifdiff {source_file_path}"); + a.linkin_path = $"$builddir/linker-in/{filename}"; + a.linkout_path = $"$builddir/linker-out/{filename}"; + linker_infiles += $" {a.linkin_path}"; + linker_ofiles += $" {a.linkout_path}"; + infile = $"{a.linkout_path}"; + ninja.WriteLine ($"build {a.linkin_path}: cpifdiff {source_file_path}"); } else { infile = $"$builddir/{filename}"; ninja.WriteLine ($"build $builddir/{filename}: cpifdiff {source_file_path}"); @@ -443,21 +488,40 @@ class Driver { ninja.WriteLine ($"build $appdir/$deploy_prefix/{filename}: cpifdiff {infile}"); if (enable_aot) { - string mono_path = enable_linker ? "$builddir/linker-out" : "$builddir"; - string destdir = "$builddir"; - string srcfile = infile; + a.bc_path = $"$builddir/{filename}.bc"; - string outputs = $"{destdir}/{filename}.bc"; - ninja.WriteLine ($"build {outputs}: aot {srcfile}"); - ninja.WriteLine ($" src_file={srcfile}"); - ninja.WriteLine ($" outfile={destdir}/{filename}.bc"); - ninja.WriteLine ($" mono_path={mono_path}"); + ninja.WriteLine ($"build {a.bc_path}: aot {infile}"); + ninja.WriteLine ($" src_file={infile}"); + ninja.WriteLine ($" outfile={a.bc_path}"); + ninja.WriteLine ($" mono_path={aot_in_path}"); + if (enable_dedup) + ninja.WriteLine ($" aot_args=dedup-skip"); - ofiles += " " + ($"{destdir}/{filename}.bc"); + ofiles += " " + ($"{a.bc_path}"); } } + if (enable_dedup) { + /* + * Run the aot compiler in dedup mode: + * mono --aot=<args>,dedup-include=aot-dummy.dll <assemblies> aot-dummy.dll + * This will process all assemblies and emit all instances into the aot image of aot-dummy.dll + */ + var a = dedup_asm; + /* + * The dedup process will read in the .dedup files created when running with dedup-skip, so add all the + * .bc files as dependencies. + */ + ninja.WriteLine ($"build {a.bc_path}: aot-instances | {ofiles} {a.linkout_path}"); + ninja.WriteLine ($" dedup_image={a.filename}"); + ninja.WriteLine ($" src_files={linker_ofiles} {a.linkout_path}"); + ninja.WriteLine ($" outfile={a.bc_path}"); + ninja.WriteLine ($" mono_path={aot_in_path}"); + ninja.WriteLine ($"build {a.app_path}: cpifdiff {a.linkout_path}"); + ofiles += $" {a.bc_path}"; + linker_ofiles += $" {a.linkout_path}"; + } if (enable_aot) { - ninja.WriteLine ($"build $appdir/mono.js: emcc-link $builddir/driver.o {ofiles} {profiler_libs} $mono_sdkdir/wasm-runtime-release/lib/libmonosgen-2.0.a $mono_sdkdir/wasm-runtime-release/lib/libmono-icall-table.a | $tool_prefix/library_mono.js $tool_prefix/binding_support.js $tool_prefix/dotnet_support.js"); + ninja.WriteLine ($"build $appdir/mono.js: emcc-link $builddir/driver.o {ofiles} {profiler_libs} $mono_sdkdir/wasm-runtime-release/lib/libmonosgen-2.0.a | $tool_prefix/library_mono.js $tool_prefix/binding_support.js $tool_prefix/dotnet_support.js"); } if (enable_linker) { string linker_args = ""; @@ -480,7 +544,6 @@ class Driver { ninja.WriteLine ($"build $appdir/{filename}: cpifdiff {abs_path}"); } - ninja.Close (); } |