From aa670c98cbea64350d19cf48c4e7e98d42ee2af7 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Sun, 21 Oct 2018 22:44:43 +0200 Subject: [PATCH] [wasm] Fix AOT support. (#11291) * [wasm] Fix the creation of runtime.js in ninja mode. * [wasm] Exit with an error code if the emscripten runtime hits an abort. * [wasm] Error out when mono_wasm_load_runtime () fails too. * [wasm] Wrap some code in ENVIRONMENT_IS_SHELL. * [aot] Emit runtime invoke wrappers for up to 40 parameters for bitcode, newly added tests depend on it. * [aot] Fix a buffer overflow in mini_get_gsharedvt_out_sig_wrapper_signature (). * [wasm] Remove some filesystem code which is no longer needed. * [wasm] Disable coop gc on the cross compiler, it effects the generated code. * [wasm] Use a different random device under wasm so we can override its behavior. This is needed because /dev/random no longer works in emscripten 1.38.13 in JS shells. * [wasm] Bump emscripten to 1.38.13. * [wasm] Print a stack in one more abort case. * [wasm] Add putchar to EXPORTED_FUNCTIONS, llvm-lto seems to create references to it after linking. --- configure.ac | 5 +++++ mono/mini/aot-compiler.c | 2 +- mono/mini/mini-generic-sharing.c | 2 +- mono/utils/mono-rand.c | 7 ++++++- sdks/builds/wasm.mk | 4 +++- sdks/wasm/Makefile | 2 +- sdks/wasm/driver.c | 1 - sdks/wasm/library_mono.js | 30 ++++++++++++++++++++++++++++-- sdks/wasm/packager.cs | 16 ++++++++++------ sdks/wasm/runtime-tests.js | 9 +++++++++ 10 files changed, 64 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index bef7213abc1..990d50a9f60 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ case "$host" in libdl="-ldl" libgc_threads=pthreads platform_wasm=yes + MONO_DEV_RANDOM=/dev/mono_random ;; *-mingw*|*-*-cygwin*) AC_DEFINE(DISABLE_PORTABILITY,1,[Disable the io-portability layer]) @@ -3622,6 +3623,10 @@ esac AC_DEFINE_UNQUOTED(NAME_DEV_RANDOM, "$NAME_DEV_RANDOM", [Name of /dev/random]) +if test "x$MONO_DEV_RANDOM" != "x"; then + AC_DEFINE_UNQUOTED(MONO_DEV_RANDOM, "$MONO_DEV_RANDOM", [Name of random device]) +fi + dnl Now check if the device actually exists if test "x$try_dev_random" = "xyes"; then diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index 491fb78497d..71578dcf410 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -4172,7 +4172,7 @@ add_wrappers (MonoAotCompile *acfg) /* Create simplified signatures which match the signature used by the gsharedvt out wrappers */ for (variants = 0; variants < 4; ++variants) { - for (i = 0; i < 16; ++i) { + for (i = 0; i < 40; ++i) { sig = mini_get_gsharedvt_out_sig_wrapper_signature ((variants & 1) > 0, (variants & 2) > 0, i); add_extra_method (acfg, mono_marshal_get_runtime_invoke_for_sig (sig)); diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index ab7e3ba377b..f1112d938b1 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -1732,7 +1732,7 @@ mini_get_interp_lmf_wrapper (void) MonoMethodSignature* mini_get_gsharedvt_out_sig_wrapper_signature (gboolean has_this, gboolean has_ret, int param_count) { - MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + (32 * sizeof (MonoType*))); + MonoMethodSignature *sig = g_malloc0 (sizeof (MonoMethodSignature) + ((param_count + 3) * sizeof (MonoType*))); int i, pindex; MonoType *int_type = mono_get_int_type (); diff --git a/mono/utils/mono-rand.c b/mono/utils/mono-rand.c index ecd5ee47b60..198f479da9b 100644 --- a/mono/utils/mono-rand.c +++ b/mono/utils/mono-rand.c @@ -209,8 +209,13 @@ mono_rand_open (void) return TRUE; } +#ifdef MONO_DEV_RANDOM + file = open (MONO_DEV_RANDOM, O_RDONLY); + printf ("B: %d\n", file); +#endif #ifdef NAME_DEV_URANDOM - file = open (NAME_DEV_URANDOM, O_RDONLY); + if (file < 0) + file = open (NAME_DEV_URANDOM, O_RDONLY); #endif #ifdef NAME_DEV_RANDOM if (file < 0) diff --git a/sdks/builds/wasm.mk b/sdks/builds/wasm.mk index 9ea9f0bad4d..9a58ce167c1 100644 --- a/sdks/builds/wasm.mk +++ b/sdks/builds/wasm.mk @@ -1,7 +1,7 @@ #emcc has lots of bash'isms SHELL:=/bin/bash -EMSCRIPTEN_VERSION=1.38.11 +EMSCRIPTEN_VERSION=1.38.13 EMSCRIPTEN_SDK_DIR=$(TOP)/sdks/builds/toolchains/emsdk $(TOP)/sdks/builds/toolchains/emsdk: @@ -103,6 +103,8 @@ _wasm-$(1)_CONFIGURE_FLAGS= \ --enable-maintainer-mode \ --enable-minimal=appdomains,com,remoting \ --enable-icall-symbol-map \ + --with-cooperative-gc=no \ + --enable-hybrid-suspend=no \ --with-cross-offsets=wasm32-unknown-none.h $$(eval $$(call CrossRuntimeTemplate,wasm-$(1),$$(if $$(filter $$(UNAME),Darwin),$(2)-apple-darwin10,$$(if $$(filter $$(UNAME),Linux),$(2)-linux-gnu,$$(error "Unknown UNAME='$$(UNAME)'"))),$(3)-unknown-none,$(4),$(5),$(6))) diff --git a/sdks/wasm/Makefile b/sdks/wasm/Makefile index 9a01c374ac7..8af28f8c4a3 100644 --- a/sdks/wasm/Makefile +++ b/sdks/wasm/Makefile @@ -85,7 +85,7 @@ debug/.stamp-build: driver.o library_mono.js binding_support.js dotnet_support.j # Notice that release/.stamp-build depends on debug/.stamp-build. This is the case as emcc is believed to not work well with parallel builds. release/.stamp-build: driver.o library_mono.js binding_support.js dotnet_support.js $(TOP)/sdks/out/wasm-runtime-release/lib/libmonosgen-2.0.a debug/.stamp-build | release/ - $(EMCC) -Oz --llvm-opts 2 --llvm-lto 1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s ALIASING_FUNCTION_POINTERS=0 --js-library library_mono.js --js-library binding_support.js --js-library dotnet_support.js driver.o $(MONO_LIBS) -o release/mono.js -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString']" + $(EMCC) -Oz --llvm-opts 2 --llvm-lto 1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s ALIASING_FUNCTION_POINTERS=0 --js-library library_mono.js --js-library binding_support.js --js-library dotnet_support.js driver.o $(MONO_LIBS) -o release/mono.js -s NO_EXIT_RUNTIME=1 -s "EXPORTED_FUNCTIONS=['_putchar']" -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString']" touch $@ $(WASM_BCL_DIR)/monolinker.exe: $(TOP)/mcs/class/lib/build/monolinker.exe diff --git a/sdks/wasm/driver.c b/sdks/wasm/driver.c index 20cf98b915b..6a11b2ed45b 100644 --- a/sdks/wasm/driver.c +++ b/sdks/wasm/driver.c @@ -181,7 +181,6 @@ mono_wasm_load_runtime (const char *managed_path, int enable_debugging) mono_trace_init (); mono_trace_set_log_handler (wasm_logger, NULL); - mono_set_assemblies_path (m_strdup (managed_path)); root_domain = mono_jit_init_version ("mono", "v4.0.30319"); mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js); diff --git a/sdks/wasm/library_mono.js b/sdks/wasm/library_mono.js index 2b946f73a01..dd714b9ef8c 100644 --- a/sdks/wasm/library_mono.js +++ b/sdks/wasm/library_mono.js @@ -80,7 +80,19 @@ var MonoSupportLib = { }, mono_load_runtime_and_bcl: function (vfs_prefix, deploy_prefix, enable_debugging, file_list, loaded_cb, fetch_file_cb) { - Module.FS_createPath ("/", vfs_prefix, true, true); + // /dev/random doesn't work on js shells, so define our own + // See library_fs.js:createDefaultDevices () + var random_device; + if (typeof crypto !== 'undefined') { + var randomBuffer = new Uint8Array(1); + random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; + } else if (ENVIRONMENT_IS_NODE) { + random_device = function() { return require('crypto')['randomBytes'](1)[0]; }; + } else { + // This is not crypto quality + random_device = function() { return (Math.random()*256)|0; }; + } + FS.createDevice('/dev', 'mono_random', random_device); var pending = file_list.length; var loaded_files = []; @@ -139,7 +151,21 @@ var MonoSupportLib = { var load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']); console.log ("initializing mono runtime"); - load_runtime (vfs_prefix, enable_debugging); + if (ENVIRONMENT_IS_SHELL) { + try { + load_runtime (vfs_prefix, enable_debugging); + } catch (ex) { + print ("load_runtime () failed: " + ex); + var err = new Error(); + print ("Stacktrace: \n"); + print (err.stack); + + var wasm_exit = Module.cwrap ('mono_wasm_exit', 'void', ['number']); + wasm_exit (1); + } + } else { + load_runtime (vfs_prefix, enable_debugging); + } MONO.mono_wasm_runtime_ready (); loaded_cb (); } diff --git a/sdks/wasm/packager.cs b/sdks/wasm/packager.cs index 851940d850f..a006312efc4 100644 --- a/sdks/wasm/packager.cs +++ b/sdks/wasm/packager.cs @@ -288,13 +288,17 @@ class Driver { dontlink_assemblies [BINDINGS_ASM_NAME] = true; var runtime_js = Path.Combine (emit_ninja ? builddir : out_prefix, "runtime.js"); - if (File.Exists(runtime_js)) - CopyFile (runtimeTemplate, runtime_js, CopyType.IfNewer, $"runtime template <{runtimeTemplate}> "); - else - { - var runtime_gen = "\nvar Module = {\n\tonRuntimeInitialized: function () {\n\t\tMONO.mono_load_runtime_and_bcl (\n\t\tconfig.vfs_prefix,\n\t\tconfig.deploy_prefix,\n\t\tconfig.enable_debugging,\n\t\tconfig.file_list,\n\t\tfunction () {\n\t\t\tconfig.add_bindings ();\n\t\t\tApp.init ();\n\t\t}\n\t)\n\t},\n};"; + if (emit_ninja) { File.Delete (runtime_js); - File.WriteAllText (runtime_js, runtime_gen); + File.Copy (runtimeTemplate, runtime_js); + } else { + if (File.Exists(runtime_js)) { + CopyFile (runtimeTemplate, runtime_js, CopyType.IfNewer, $"runtime template <{runtimeTemplate}> "); + } else { + var runtime_gen = "\nvar Module = {\n\tonRuntimeInitialized: function () {\n\t\tMONO.mono_load_runtime_and_bcl (\n\t\tconfig.vfs_prefix,\n\t\tconfig.deploy_prefix,\n\t\tconfig.enable_debugging,\n\t\tconfig.file_list,\n\t\tfunction () {\n\t\t\tconfig.add_bindings ();\n\t\t\tApp.init ();\n\t\t}\n\t)\n\t},\n};"; + File.Delete (runtime_js); + File.WriteAllText (runtime_js, runtime_gen); + } } var file_list_str = string.Join (",", file_list.Select (f => $"\"{Path.GetFileName (f)}\"").Distinct()); diff --git a/sdks/wasm/runtime-tests.js b/sdks/wasm/runtime-tests.js index c6075aceea2..57a7f72f7a3 100644 --- a/sdks/wasm/runtime-tests.js +++ b/sdks/wasm/runtime-tests.js @@ -85,6 +85,14 @@ var Module = { print: function(x) { print ("WASM: " + x) }, printErr: function(x) { print ("WASM-ERR: " + x) }, + onAbort: function(x) { + print ("ABORT: " + x); + var err = new Error(); + print ("Stacktrace: \n"); + print (err.stack); + wasm_exit (1); + }, + onRuntimeInitialized: function () { // Have to set env vars here to enable setting MONO_LOG_LEVEL etc. var wasm_setenv = Module.cwrap ('mono_wasm_setenv', 'void', ['string', 'string']); @@ -159,6 +167,7 @@ var App = { Module.print ("REGRESSION RESULT: " + res); } catch (e) { Module.print ("ABORT: " + e); + print (e.stack); res = 1; } -- 2.11.4.GIT