diff options
-rw-r--r-- | mono/mini/aot-runtime.c | 29 | ||||
-rw-r--r-- | mono/mini/builtin-types.cs | 6 | ||||
-rw-r--r-- | mono/mini/mini-codegen.c | 1 | ||||
-rw-r--r-- | mono/mini/mini-llvm.c | 57 | ||||
-rw-r--r-- | mono/mini/mini-wasm.h | 2 | ||||
-rwxr-xr-x | scripts/ci/run-jenkins.sh | 1 | ||||
-rw-r--r-- | sdks/builds/emsdk-eh.diff | 19 | ||||
-rw-r--r-- | sdks/builds/wasm.mk | 1 | ||||
-rw-r--r-- | sdks/wasm/Makefile | 22 | ||||
-rw-r--r-- | sdks/wasm/aot-driver.js | 126 | ||||
-rw-r--r-- | sdks/wasm/driver.c | 2 | ||||
-rw-r--r-- | sdks/wasm/packager.cs | 16 |
12 files changed, 252 insertions, 30 deletions
diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index 0a1bd8e8d73..3c31eae4a2d 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -2724,11 +2724,36 @@ compute_llvm_code_range (MonoAotModule *amodule, guint8 **code_start, guint8 **c if (amodule->info.llvm_get_method) { gpointer (*get_method) (int) = (gpointer (*)(int))amodule->info.llvm_get_method; +#ifdef HOST_WASM + gsize min = 1 << 30, max = 0; + gsize prev = 0; + + // FIXME: This depends on emscripten allocating ftnptr ids sequentially + for (int i = 0; i < amodule->info.nmethods; ++i) { + void *addr = NULL; + + addr = get_method (i); + gsize val = (gsize)addr; + if (val) { + g_assert (val > prev); + if (val < min) + min = val; + else if (val > max) + max = val; + prev = val; + } + } + if (max) { + *code_start = (guint8*)min; + *code_end = (guint8*)(max + 1); + } else { + *code_start = NULL; + *code_end = NULL; + } +#else *code_start = (guint8 *)get_method (-1); *code_end = (guint8 *)get_method (-2); - //WASM doesn't support this -#ifndef HOST_WASM g_assert (*code_end > *code_start); #endif return; diff --git a/mono/mini/builtin-types.cs b/mono/mini/builtin-types.cs index 69b328de8c0..af2b249f72b 100644 --- a/mono/mini/builtin-types.cs +++ b/mono/mini/builtin-types.cs @@ -259,7 +259,7 @@ public class BuiltinTests { return 0; } - public int test_0_nint_unboxed_member_calls () + static int test_0_nint_unboxed_member_calls () { var x = (nint)10; #if FALSE @@ -521,7 +521,7 @@ public class BuiltinTests { return 0; } - public int test_0_nuint_unboxed_member_calls () + static int test_0_nuint_unboxed_member_calls () { var x = (nuint)10; #if FALSE @@ -780,7 +780,7 @@ public class BuiltinTests { return 0; } - public int test_0_nfloat_unboxed_member_calls () + static int test_0_nfloat_unboxed_member_calls () { var x = (nfloat)10f; #if FALSE diff --git a/mono/mini/mini-codegen.c b/mono/mini/mini-codegen.c index 096c0979eeb..c8053799ec7 100644 --- a/mono/mini/mini-codegen.c +++ b/mono/mini/mini-codegen.c @@ -2346,6 +2346,7 @@ mono_opcode_to_cond (int opcode) case OP_CMOV_LEQ: return CMP_EQ; case OP_FCNEQ: + case OP_RCNEQ: case OP_ICNEQ: case OP_IBNE_UN: case OP_LBNE_UN: diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 3c8f840328b..f97c96d961e 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -3193,6 +3193,58 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) ctx->builder = old_builder; } +static gboolean +needs_extra_arg (EmitContext *ctx, MonoMethod *method) +{ + WrapperInfo *info = NULL; + + /* + * When targeting wasm, the caller and callee signature has to match exactly. This means + * that every method which can be called indirectly need an extra arg since the caller + * will call it through an ftnptr and will pass an extra arg. + */ + if (!ctx->cfg->llvm_only || !ctx->emit_dummy_arg) + return FALSE; + if (method->wrapper_type) + info = mono_marshal_get_wrapper_info (method); + + switch (method->wrapper_type) { + case MONO_WRAPPER_UNKNOWN: + if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN_SIG || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT_SIG) + /* Already have an explicit extra arg */ + return FALSE; + break; + case MONO_WRAPPER_MANAGED_TO_NATIVE: + if (strstr (method->name, "icall_wrapper")) + /* These are JIT icall wrappers which are only called from JITted code directly */ + return FALSE; + /* Normal icalls can be virtual methods which need an extra arg */ + break; + case MONO_WRAPPER_RUNTIME_INVOKE: + case MONO_WRAPPER_ALLOC: + case MONO_WRAPPER_CASTCLASS: + case MONO_WRAPPER_WRITE_BARRIER: + return FALSE; + case MONO_WRAPPER_STELEMREF: + if (info->subtype != WRAPPER_SUBTYPE_VIRTUAL_STELEMREF) + return FALSE; + break; + case MONO_WRAPPER_MANAGED_TO_MANAGED: + if (info->subtype == WRAPPER_SUBTYPE_STRING_CTOR) + return FALSE; + break; + default: + break; + } + if (method->string_ctor) + return FALSE; + + /* These are called from gsharedvt code with an indirect call which doesn't pass an extra arg */ + if (method->klass == mono_defaults.string_class && (strstr (method->name, "memcpy") || strstr (method->name, "bzero"))) + return FALSE; + return TRUE; +} + static void process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, MonoInst *ins) { @@ -3227,7 +3279,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, cinfo->rgctx_arg = TRUE; if (call->imt_arg_reg) cinfo->imt_arg = TRUE; - if (cfg->llvm_only && ctx->emit_dummy_arg && call->method && !call->method->wrapper_type) + if (call->method && needs_extra_arg (ctx, call->method)) cinfo->dummy_arg = TRUE; vretaddr = (cinfo->ret.storage == LLVMArgVtypeRetAddr || cinfo->ret.storage == LLVMArgVtypeByRef || cinfo->ret.storage == LLVMArgGsharedvtFixed || cinfo->ret.storage == LLVMArgGsharedvtVariable || cinfo->ret.storage == LLVMArgGsharedvtFixedVtype); @@ -4660,6 +4712,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) break; } case OP_RCEQ: + case OP_RCNEQ: case OP_RCLT: case OP_RCLT_UN: case OP_RCGT: @@ -7145,7 +7198,7 @@ emit_method_inner (EmitContext *ctx) if (cfg->rgctx_var) linfo->rgctx_arg = TRUE; - else if (ctx->emit_dummy_arg && cfg->llvm_only && !cfg->method->wrapper_type) + else if (needs_extra_arg (ctx, cfg->method)) linfo->dummy_arg = TRUE; ctx->method_type = method_type = sig_to_llvm_sig_full (ctx, sig, linfo); if (!ctx_ok (ctx)) diff --git a/mono/mini/mini-wasm.h b/mono/mini/mini-wasm.h index 7e500b3155e..b5c9e1c979e 100644 --- a/mono/mini/mini-wasm.h +++ b/mono/mini/mini-wasm.h @@ -19,8 +19,10 @@ #define MONO_ARCH_AOT_SUPPORTED 1 #define MONO_ARCH_LLVM_SUPPORTED 1 +#define MONO_ARCH_GSHARED_SUPPORTED 1 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1 +#define MONO_ARCH_NEED_DIV_CHECK 1 #define MONO_ARCH_EMULATE_FREM 1 #define MONO_ARCH_FLOAT32_SUPPORTED 1 diff --git a/scripts/ci/run-jenkins.sh b/scripts/ci/run-jenkins.sh index 3fd9c212dee..6323603cbaa 100755 --- a/scripts/ci/run-jenkins.sh +++ b/scripts/ci/run-jenkins.sh @@ -195,6 +195,7 @@ if [[ ${CI_TAGS} == *'webassembly'* ]]; ${TESTCMD} --label=v8-system-core --timeout=60m make -C sdks/wasm run-v8-system-core ${TESTCMD} --label=sm-system-core --timeout=60m make -C sdks/wasm run-sm-system-core ${TESTCMD} --label=jsc-system-core --timeout=60m make -C sdks/wasm run-jsc-system-core + #${TESTCMD} --label=check-aot --timeout=60m make -C sdks/wasm check-aot ${TESTCMD} --label=package --timeout=60m make -C sdks/wasm package exit 0 fi diff --git a/sdks/builds/emsdk-eh.diff b/sdks/builds/emsdk-eh.diff new file mode 100644 index 00000000000..67da70e2482 --- /dev/null +++ b/sdks/builds/emsdk-eh.diff @@ -0,0 +1,19 @@ +commit 09c043e560b69c5ba803f0b35eea75fb8f1ee85e +Author: Zoltan Varga <vargaz@gmail.com> +Date: Mon Sep 24 21:54:47 2018 +0200 + + Add '___cxa_is_pointer_type', '___cxa_can_catch' to the list of exported functions when exception catching is enabled. + +diff --git a/emcc.py b/emcc.py +index bb2889fdb..65c71a174 100755 +--- a/emcc.py ++++ b/emcc.py +@@ -1134,6 +1134,8 @@ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR P + if shared.Settings.DEMANGLE_SUPPORT: + shared.Settings.EXPORTED_FUNCTIONS += ['___cxa_demangle'] + forced_stdlibs += ['libcxxabi'] ++ if shared.Settings.DISABLE_EXCEPTION_CATCHING != 1: ++ shared.Settings.EXPORTED_FUNCTIONS += ['___cxa_is_pointer_type', '___cxa_can_catch'] + + if not shared.Settings.ONLY_MY_CODE: + if type(shared.Settings.EXPORTED_FUNCTIONS) in (list, tuple): diff --git a/sdks/builds/wasm.mk b/sdks/builds/wasm.mk index 788e5192dc0..2814bece9c5 100644 --- a/sdks/builds/wasm.mk +++ b/sdks/builds/wasm.mk @@ -32,6 +32,7 @@ $(TOP)/sdks/builds/toolchains/emsdk: git clone https://github.com/juj/emsdk.git $(EMSCRIPTEN_SDK_DIR) cd $(TOP)/sdks/builds/toolchains/emsdk && ./emsdk install sdk-$(EMSCRIPTEN_VERSION)-64bit cd $(TOP)/sdks/builds/toolchains/emsdk && ./emsdk activate --embedded sdk-$(EMSCRIPTEN_VERSION)-64bit + -cd $(TOP)/sdks/builds/toolchains/emsdk/emscripten/$(EMSCRIPTEN_VERSION) && patch -p1 < $(TOP)/sdks/builds/emsdk-eh.diff .stamp-wasm-toolchain: | $(TOP)/sdks/builds/toolchains/emsdk touch $@ diff --git a/sdks/wasm/Makefile b/sdks/wasm/Makefile index 167f654ebf2..f64526db54e 100644 --- a/sdks/wasm/Makefile +++ b/sdks/wasm/Makefile @@ -142,26 +142,12 @@ TEST_ASSEMBLIES = $(WASM_BCL_DIR)/nunitlite.dll $(WASM_BCL_DIR)/tests/wasm_corli ninja -v -C obj/test-suite touch $@ -MINI_BASIC_TEST_FILES= \ - basic-calls.cs \ - basic-float.cs \ - basic-long.cs \ - basic-math.cs \ - basic.cs \ - objects.cs - -MINI_BASIC_TEST_SOURCES= $(patsubst %,$(MINI_PATH)/%,$(MINI_BASIC_TEST_FILES)) - -mini_tests_basic.dll: $(MINI_BASIC_TEST_SOURCES) - $(CSC) $(CSC_FLAGS) /unsafe -target:library -out:$@ -define:__MOBILE__,ARCH_32,NO_BITCODE /r:$(WASM_BCL_DIR)/mscorlib.dll $(MINI_BASIC_TEST_SOURCES) - - -aot-sample: $(DRIVER_CONF)/.stamp-build packager.exe mini_tests_basic.dll main.exe runtime.g.js - mono packager.exe --emscripten-sdkdir=$(EMSCRIPTEN_SDKDIR) --mono-sdkdir=$(PWD)/../out -appdir=bin/aot-sample --nobinding --builddir=obj/aot-sample --aot --template=runtime-tests.g.js mini_tests_basic.dll +aot-sample: $(DRIVER_CONF)/.stamp-build packager.exe mini_tests.dll main.exe runtime.g.js + mono packager.exe --emscripten-sdkdir=$(EMSCRIPTEN_SDKDIR) --mono-sdkdir=$(PWD)/../out -appdir=bin/aot-sample --nobinding --builddir=obj/aot-sample --aot --template=runtime-tests.g.js mini_tests.dll ninja -v -C obj/aot-sample do-aot-sample: aot-sample - (cd bin/aot-sample && $(SM) runtime.js mini) + (cd bin/aot-sample && $(SM) runtime.js --regression mini_tests.dll) build-debug-sample: .stamp-build-debug-sample @@ -248,3 +234,5 @@ serve: canary: /Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --remote-debugging-port=9222 + +check-aot: do-aot-sample diff --git a/sdks/wasm/aot-driver.js b/sdks/wasm/aot-driver.js new file mode 100644 index 00000000000..8f0385f083f --- /dev/null +++ b/sdks/wasm/aot-driver.js @@ -0,0 +1,126 @@ +//glue code to deal with the differences between ch, d8, jsc and sm. +if (print == undefined) + print = console.log; + + +if (console != undefined) { + var has_console_warn = false; + try { + if (console.warn != undefined) + has_console_warn = true; + } catch(e) {} + + if (!has_console_warn) + console.warn = console.log; +} + +fail_exec = function(reason) { + print (reason); + throw "FAIL"; +} + +try { + arguments = WScript.Arguments; + load = WScript.LoadScriptFile; + read = WScript.LoadBinaryFile; + fail_exec = function(reason) { + print (reason); + WScript.Quit(1); + } +} catch(e) {} + +try { + if (scriptArgs !== undefined) + arguments = scriptArgs; +} catch(e) {} + + +// load("runtime.js") + +var App = { + init: function () { print ("runtime init finished"); } +}; + +function ResolveEagerPromise(value) { + this.then = function(cb) { + var res = cb (value); + return new ResolveEagerPromise(res); + } +} + +var Module = { + onRuntimeInitialized: function () { + print("initing the runtime"); + MONO.mono_load_runtime_and_bcl ( + "managed", + "managed", + 0, + [ "mscorlib.dll", "mini_tests_basic.dll", ], + function () { App.init (); }, + function (file) { + // print("loading " + file) + return new ResolveEagerPromise ({ + ok: true, + url: file, + arrayBuffer: function() { return read (file, 'binary') } + }) + }); + }, + + print: function(x) { print ("WASM: " + x) }, + printErr: function(x) { print ("WASM-ERR: " + x) }, + + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + print("STATUS: "+ (left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.')); + }, + + instantiateWasm: function (env, receiveInstance) { + //merge Module's env with emcc's env + env.env = Object.assign({}, env.env, this.env); + var module = new WebAssembly.Module (read ('mono.wasm', 'binary')) + this.wasm_instance = new WebAssembly.Instance (module, env); + this.em_cb = receiveInstance; + return this + }, + + finish_loading: function () { + this.em_cb (this.wasm_instance); + }, + + env: { + }, + +}; + + +load("mono.js") +Module.finish_loading (); + +function not_null(value) { + if (!value) + throw "error"; + return value; +} + +var assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']) +var find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']) +var find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']) +var mono_runtime_invoke = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']); +var mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']); +const IGNORE_PARAM_COUNT = -1; + +var test_suite = not_null (assembly_load("mini_tests_basic")) +var basic_tests = not_null (find_class (test_suite, "", "BasicTests")) +var test_0_return = not_null (find_method (basic_tests, "test_0_return", IGNORE_PARAM_COUNT)) + +var eh_throw = Module._malloc (4); +Module.setValue (eh_throw, 0, "i32"); +var res = mono_unbox_int (mono_runtime_invoke (test_0_return, 0, 0, eh_throw)); +var eh_res = Module.getValue (eh_throw, "i32"); +print ("res is " + res + " eh is " + eh_res); + + + + diff --git a/sdks/wasm/driver.c b/sdks/wasm/driver.c index 5a5b127d20f..e86e3d34846 100644 --- a/sdks/wasm/driver.c +++ b/sdks/wasm/driver.c @@ -592,5 +592,5 @@ mono_wasm_array_to_heap (MonoArray *src, char *dest) EMSCRIPTEN_KEEPALIVE int mono_wasm_exec_regression (int verbose_level, char *image) { - return mono_regression_test_step (verbose_level, image, NULL); + return mono_regression_test_step (verbose_level, image, NULL) ? 0 : 1; } diff --git a/sdks/wasm/packager.cs b/sdks/wasm/packager.cs index ab061f7ae26..41fc6c1c6c6 100644 --- a/sdks/wasm/packager.cs +++ b/sdks/wasm/packager.cs @@ -258,6 +258,9 @@ class Driver { if (vfs_prefix.EndsWith ("/")) vfs_prefix = vfs_prefix.Substring (0, vfs_prefix.Length - 1); + var dontlink_assemblies = new Dictionary<string, bool> (); + dontlink_assemblies [BINDINGS_ASM_NAME] = true; + var template = File.ReadAllText (Path.Combine (tool_prefix, runtimeTemplate)); var file_list_str = string.Join (",", file_list.Select (f => $"\"{Path.GetFileName (f)}\"")); @@ -329,7 +332,7 @@ class Driver { ninja.WriteLine ("cross = $mono_sdkdir/wasm-cross/bin/wasm32-mono-sgen"); ninja.WriteLine ("emcc = source $emscripten_sdkdir/emsdk_env.sh && emcc"); // -s ASSERTIONS=2 is very slow - ninja.WriteLine ("emcc_flags = -Os -g -s ASSERTIONS=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s \"BINARYEN_TRAP_MODE='clamp'\" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 -s NO_EXIT_RUNTIME=1 -s \"EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString']\""); + ninja.WriteLine ("emcc_flags = -Os -g -s DISABLE_EXCEPTION_CATCHING=0 -s ASSERTIONS=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s \"BINARYEN_TRAP_MODE=\'clamp\'\" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 -s NO_EXIT_RUNTIME=1 -s \"EXTRA_EXPORTED_RUNTIME_METHODS=[\'ccall\', \'FS_createPath\', \'FS_createDataFile\', \'cwrap\', \'setValue\', \'getValue\', \'UTF8ToString\']\""); // Rules ninja.WriteLine ("rule aot"); @@ -341,13 +344,14 @@ class Driver { ninja.WriteLine (" command = if cmp -s $in $out ; then : ; else cp $in $out ; fi"); ninja.WriteLine (" restat = true"); ninja.WriteLine ("rule emcc"); - ninja.WriteLine (" command = $emcc $emcc_flags $flags -c -o $out $in"); + ninja.WriteLine (" command = bash -c '$emcc $emcc_flags $flags -c -o $out $in'"); ninja.WriteLine (" description = [EMCC] $in -> $out"); ninja.WriteLine ("rule emcc-link"); - ninja.WriteLine (" command = $emcc $emcc_flags -o $out --js-library $tool_prefix/library_mono.js --js-library $tool_prefix/binding_support.js --js-library $tool_prefix/dotnet_support.js $in"); + ninja.WriteLine (" command = bash -c '$emcc $emcc_flags -o $out --js-library $tool_prefix/library_mono.js --js-library $tool_prefix/binding_support.js --js-library $tool_prefix/dotnet_support.js $in'"); ninja.WriteLine (" description = [EMCC-LINK] $in -> $out"); ninja.WriteLine ("rule linker"); - ninja.WriteLine (" command = mono $bcl_dir/monolinker.exe -out $builddir/linker-out $linker_args"); + + ninja.WriteLine (" command = mono $bcl_dir/monolinker.exe -out $builddir/linker-out -l none $linker_args; for f in $out; do if test ! -f $$f; then echo > empty.cs; csc /out:$$f /target:library empty.cs; fi; done"); ninja.WriteLine (" description = [IL-LINK]"); // Targets @@ -379,7 +383,6 @@ class Driver { var filename_noext = Path.GetFileNameWithoutExtension (filename); var source_file_path = Path.GetFullPath (assembly); - ninja.WriteLine ($"build $builddir/{filename}: cpifdiff {source_file_path}"); string infile = ""; if (enable_linker) { @@ -416,6 +419,9 @@ class Driver { string filename = Path.GetFileName (assembly); linker_args += $"-a linker-in/{filename} "; } + foreach (var assembly in dontlink_assemblies.Keys) { + linker_args += $"-p copy {assembly} "; + } linker_args += " -d $bcl_dir -c link"; ninja.WriteLine ("build $builddir/linker-out: mkdir"); ninja.WriteLine ($"build {linker_ofiles}: linker"); |