Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodrigo Kumpera <kumpera@users.noreply.github.com>2018-11-06 15:46:18 +0300
committerGitHub <noreply@github.com>2018-11-06 15:46:18 +0300
commitce08c3263264559b9312e791db265ca951fab59c (patch)
treeed2cec43366461367d1bf8176c365230e6df155b
parentc200ccbb6265d6564cf72217b58991874f5148e5 (diff)
parentff4496f0af83c2ef4b69ff68c30edf8584f3f548 (diff)
Merge pull request #11444 from vargaz/wasm-work10
[wasm] AOT work.
-rw-r--r--configure.ac7
-rw-r--r--mcs/class/corlib/System/TimeZoneInfo.WebAssembly.cs30
-rw-r--r--mcs/class/corlib/System/TimeZoneInfo.cs4
-rw-r--r--mcs/class/corlib/corlib.csproj1
-rw-r--r--mcs/class/corlib/corlib.dll.sources1
-rw-r--r--mono/eglib/glib.h4
-rw-r--r--mono/metadata/class.c32
-rw-r--r--mono/mini/aot-compiler.c108
-rw-r--r--mono/mini/aot-runtime.c24
-rw-r--r--mono/mini/intrinsics.c9
-rw-r--r--mono/mini/mini-llvm-loaded.c9
-rw-r--r--mono/mini/mini-llvm.c327
-rw-r--r--mono/mini/mini-llvm.h1
-rw-r--r--mono/mini/mini-runtime.c2
-rw-r--r--mono/mini/mini.c2
-rw-r--r--mono/mini/mini.h3
-rw-r--r--sdks/builds/wasm.mk2
-rw-r--r--sdks/wasm/driver.c3
-rw-r--r--sdks/wasm/packager.cs117
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 ();
}