From 11bfaa6e04e844dd089c67a1973e46dee5a6aa5e Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Thu, 29 Oct 2020 14:07:37 +0100 Subject: [PATCH 1/9] [browser][bindings] Add support for calling the async Task entry point. - When the entry point of an assembly is async we need to execute that method and return the Task object - The Task object that is return from the execution of the async entry point will be marshaled to a JavaScript Promise. --- .../InteropServices/JavaScript/Runtime.cs | 34 +++++++++++++++++++ src/mono/wasm/runtime-test.js | 27 +++++++++------ src/mono/wasm/runtime/binding_support.js | 20 +++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs index 93d24cce4fe2a4..2c4785904d8bc9 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs @@ -479,5 +479,39 @@ public static IntPtr SafeHandleGetHandle(SafeHandle safeHandle, bool addRef) return safeHandle.DangerousGetHandle(); } + public static string? FindUnderlyingEntrypoint(IntPtr entryPoint) + { + IntPtrAndHandle tmp = default(IntPtrAndHandle); + tmp.ptr = entryPoint; + + // This is the entrypoint declared in .NET metadata. In the case of async main, it's the + // compiler-generated wrapper method. Otherwise it's the developer-defined method. + MethodBase? metadataEntrypointMethodBase = MethodBase.GetMethodFromHandle(tmp.handle);; + // For "async Task Main", the C# compiler generates a method called "
" + // that is marked as the assembly entrypoint. Detect this case, and instead of + // calling "", call the sibling "Whatever". + if (metadataEntrypointMethodBase?.IsSpecialName ?? false) + { + string origName = metadataEntrypointMethodBase.Name; + int origNameLength = origName.Length; + if (origNameLength > 2) + { + string candidateMethodName = origName.Substring(1, origNameLength - 2); + MethodInfo? candidateMethod = metadataEntrypointMethodBase?.DeclaringType?.GetMethod( + candidateMethodName, + BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + + if (candidateMethod != null) + { + return $"[{candidateMethod?.DeclaringType?.Assembly.FullName}]{candidateMethod?.DeclaringType}:{candidateMethod?.Name}"; + } + } + } + + // Either it's not async main, or for some reason we couldn't locate the underlying entrypoint, + // so use the one from assembly metadata. + return null; + } + } } diff --git a/src/mono/wasm/runtime-test.js b/src/mono/wasm/runtime-test.js index 579eafa7d33a94..93cfd9623d27d9 100644 --- a/src/mono/wasm/runtime-test.js +++ b/src/mono/wasm/runtime-test.js @@ -365,19 +365,24 @@ var App = { } wasm_set_main_args (main_argc, main_argv); + function isThenable(js_obj) { + // When using an external Promise library the Promise.resolve may not be sufficient + // to identify the object as a Promise. + return Promise.resolve(js_obj) === js_obj || + ((typeof js_obj === "object" || typeof js_obj === "function") && typeof js_obj.then === "function") + } + try { - var invoke_args = Module._malloc (4); - Module.setValue (invoke_args, app_args, "i32"); - var eh_exc = Module._malloc (4); - Module.setValue (eh_exc, 0, "i32"); - var res = runtime_invoke (main_method, 0, invoke_args, eh_exc); - var eh_res = Module.getValue (eh_exc, "i32"); - if (eh_res != 0) { - print ("Exception:" + string_get_utf8 (res)); - test_exit (1); - return; + let exit_code = Module.mono_call_assembly_entry_point("WasmSample", [app_args]); + + if (isThenable(exit_code)) + { + exit_code.then( + (result) => { + test_exit (result); + } + ) } - var exit_code = unbox_int (res); test_exit (exit_code); } catch (ex) { print ("JS exception: " + ex); diff --git a/src/mono/wasm/runtime/binding_support.js b/src/mono/wasm/runtime/binding_support.js index af6202f5adb439..103589dfa1b8d3 100644 --- a/src/mono/wasm/runtime/binding_support.js +++ b/src/mono/wasm/runtime/binding_support.js @@ -124,6 +124,8 @@ var BindingSupportLib = { this.safehandle_get_handle = get_method ("SafeHandleGetHandle"); this.safehandle_release_by_handle = get_method ("SafeHandleReleaseByHandle"); + this.find_underlying_entry_point = get_method ("FindUnderlyingEntrypoint"); + this.init = true; }, @@ -881,6 +883,15 @@ var BindingSupportLib = { if (!method) throw new Error ("Could not find entry point for assembly: " + assembly); + // For async entry methods we need to drill down to the async method. + var underlying_entry_point = this.call_method(this.find_underlying_entry_point, null, "is", [ method ]); + if (underlying_entry_point) + { + method = this.resolve_method_fqn(underlying_entry_point); + if (!method) + throw new Error ("Could not find entry point for assembly: " + assembly); + } + if (typeof signature === "undefined") signature = Module.mono_method_get_call_signature (method); @@ -899,6 +910,15 @@ var BindingSupportLib = { if (!method) throw new Error ("Could not find entry point for assembly: " + assembly); + // For async entry methods we need to drill down to the async method. + var underlying_entry_point = this.call_method(this.find_underlying_entry_point, null, "is", [ method ]); + if (underlying_entry_point) + { + method = this.resolve_method_fqn(underlying_entry_point); + if (!method) + throw new Error ("Could not find entry point for assembly: " + assembly); + } + if (typeof signature === "undefined") signature = Module.mono_method_get_call_signature (method); From 260d9af25c337401a2be5ad1a7b1610d5a967973 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 29 Oct 2020 14:31:19 -0500 Subject: [PATCH 2/9] Get async main working from runtime-test.js --- .../tests/WasmTestRunner/WasmTestRunner.cs | 5 ++- .../InteropServices/JavaScript/Runtime.cs | 34 ----------------- .../JavaScript/Http/HttpRequestMessageTest.cs | 24 ++++++++++++ .../netcore/sample/wasm/console/Program.cs | 13 +++++-- src/mono/wasm/runtime-test.js | 38 +++++-------------- src/mono/wasm/runtime/binding_support.js | 20 ---------- src/mono/wasm/runtime/driver.c | 25 +++++++++++- 7 files changed, 71 insertions(+), 88 deletions(-) diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 1a88e4881021ac..46a942a0f9cde1 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -3,12 +3,13 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.DotNet.XHarness.TestRunners.Xunit; public class SimpleWasmTestRunner : WasmApplicationEntryPoint { - public static int Main(string[] args) + public static async Task Main(string[] args) { var testAssembly = args[0]; var excludedTraits = new List(); @@ -57,6 +58,6 @@ public static int Main(string[] args) IncludedMethods = includedMethods }; - return runner.Run(); + return await runner.Run(); } } diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs index 2c4785904d8bc9..93d24cce4fe2a4 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs @@ -479,39 +479,5 @@ public static IntPtr SafeHandleGetHandle(SafeHandle safeHandle, bool addRef) return safeHandle.DangerousGetHandle(); } - public static string? FindUnderlyingEntrypoint(IntPtr entryPoint) - { - IntPtrAndHandle tmp = default(IntPtrAndHandle); - tmp.ptr = entryPoint; - - // This is the entrypoint declared in .NET metadata. In the case of async main, it's the - // compiler-generated wrapper method. Otherwise it's the developer-defined method. - MethodBase? metadataEntrypointMethodBase = MethodBase.GetMethodFromHandle(tmp.handle);; - // For "async Task Main", the C# compiler generates a method called "
" - // that is marked as the assembly entrypoint. Detect this case, and instead of - // calling "", call the sibling "Whatever". - if (metadataEntrypointMethodBase?.IsSpecialName ?? false) - { - string origName = metadataEntrypointMethodBase.Name; - int origNameLength = origName.Length; - if (origNameLength > 2) - { - string candidateMethodName = origName.Substring(1, origNameLength - 2); - MethodInfo? candidateMethod = metadataEntrypointMethodBase?.DeclaringType?.GetMethod( - candidateMethodName, - BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - - if (candidateMethod != null) - { - return $"[{candidateMethod?.DeclaringType?.Assembly.FullName}]{candidateMethod?.DeclaringType}:{candidateMethod?.Name}"; - } - } - } - - // Either it's not async main, or for some reason we couldn't locate the underlying entrypoint, - // so use the one from assembly metadata. - return null; - } - } } diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs index d3794eda8af152..81d197f8ff0946 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs @@ -383,6 +383,30 @@ public void ToString_NonDefaultInstanceWithCustomHeaders_DumpAllFields(string ur "}", rm.ToString()); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowserDomSupported))] + public async Task BlobUri_Marshal_CorrectValues_Browser() + { + Runtime.InvokeJS(@" + function typedArrayToURL(typedArray, mimeType) { + return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType})) + } + const bytes = new Uint8Array(59); + for(let i = 0; i < 59; i++) { + bytes[i] = 32 + i; + } + const url = typedArrayToURL(bytes, 'text/plain'); + // Calls method with string that will be marshaled as valid URI + App.call_test_method (""InvokeString"", [ url ]); + "); + + var client = new HttpClient (); + Assert.StartsWith ("blob:", HelperMarshal._stringResource); + + var rm = new HttpRequestMessage(HttpMethod.Get, new Uri (HelperMarshal._stringResource)); + var resp = client.SendAsync (rm); + var resp2 = await resp; + } + [Fact] public void BlobStringUri_Marshal_CorrectValues() { diff --git a/src/mono/netcore/sample/wasm/console/Program.cs b/src/mono/netcore/sample/wasm/console/Program.cs index 98cade6e29cb37..eb79574fb7dc47 100644 --- a/src/mono/netcore/sample/wasm/console/Program.cs +++ b/src/mono/netcore/sample/wasm/console/Program.cs @@ -2,11 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Threading.Tasks; public class Test { - public static void Main (string[] args) + + public static async Task Main(string[] args) { - Console.WriteLine ("Hello, World!"); + await Task.Delay(1); + Console.WriteLine("Hello World!"); + for (int i = 0; i < args.Length; i++) { + Console.WriteLine($"args[{i}] = {args[i]}"); + } + return args.Length; } -} +} \ No newline at end of file diff --git a/src/mono/wasm/runtime-test.js b/src/mono/wasm/runtime-test.js index 93cfd9623d27d9..d5b392013ccf13 100644 --- a/src/mono/wasm/runtime-test.js +++ b/src/mono/wasm/runtime-test.js @@ -338,17 +338,8 @@ var App = { fail_exec ("Error: Missing main executable argument."); return; } - main_assembly = assembly_load (args[1]); - if (main_assembly == 0) { - fail_exec ("Error: Unable to load main executable '" + args[1] + "'"); - return; - } - main_method = assembly_get_entry_point (main_assembly); - if (main_method == 0) { - fail_exec ("Error: Main (string[]) method not found."); - return; - } + main_assembly_name = args[1]; var app_args = string_array_new (args.length - 2); for (var i = 2; i < args.length; ++i) { obj_array_set (app_args, i - 2, string_from_js (args [i])); @@ -373,39 +364,30 @@ var App = { } try { - let exit_code = Module.mono_call_assembly_entry_point("WasmSample", [app_args]); + // Automatic signature isn't working correctly + let exit_code = Module.mono_call_assembly_entry_point(main_assembly_name, [app_args], "mi"); if (isThenable(exit_code)) { exit_code.then( (result) => { test_exit (result); + }, + reason => { + console.error (reason); + test_exit (1); } ) + } else { + test_exit (exit_code); + return; } - test_exit (exit_code); } catch (ex) { print ("JS exception: " + ex); print (ex.stack); test_exit (1); return; } - -/* - // For testing tp/timers etc. - while (true) { - // Sleep by busy waiting - var start = performance.now (); - useconds = 1e6 / 10; - while (performance.now() - start < useconds / 1000) { - // Do nothing. - } - - Module.pump_message (); - } -*/ - - return; } else { fail_exec ("Unhandled argument: " + args [0]); } diff --git a/src/mono/wasm/runtime/binding_support.js b/src/mono/wasm/runtime/binding_support.js index 103589dfa1b8d3..af6202f5adb439 100644 --- a/src/mono/wasm/runtime/binding_support.js +++ b/src/mono/wasm/runtime/binding_support.js @@ -124,8 +124,6 @@ var BindingSupportLib = { this.safehandle_get_handle = get_method ("SafeHandleGetHandle"); this.safehandle_release_by_handle = get_method ("SafeHandleReleaseByHandle"); - this.find_underlying_entry_point = get_method ("FindUnderlyingEntrypoint"); - this.init = true; }, @@ -883,15 +881,6 @@ var BindingSupportLib = { if (!method) throw new Error ("Could not find entry point for assembly: " + assembly); - // For async entry methods we need to drill down to the async method. - var underlying_entry_point = this.call_method(this.find_underlying_entry_point, null, "is", [ method ]); - if (underlying_entry_point) - { - method = this.resolve_method_fqn(underlying_entry_point); - if (!method) - throw new Error ("Could not find entry point for assembly: " + assembly); - } - if (typeof signature === "undefined") signature = Module.mono_method_get_call_signature (method); @@ -910,15 +899,6 @@ var BindingSupportLib = { if (!method) throw new Error ("Could not find entry point for assembly: " + assembly); - // For async entry methods we need to drill down to the async method. - var underlying_entry_point = this.call_method(this.find_underlying_entry_point, null, "is", [ method ]); - if (underlying_entry_point) - { - method = this.resolve_method_fqn(underlying_entry_point); - if (!method) - throw new Error ("Could not find entry point for assembly: " + assembly); - } - if (typeof signature === "undefined") signature = Module.mono_method_get_call_signature (method); diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 3bf8387ccb9f64..35b71e404558fb 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -624,8 +624,31 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) return NULL; mono_domain_ensure_entry_assembly (root_domain, assembly); + method = mono_get_method (image, entry, NULL); - return mono_get_method (image, entry, NULL); + /* + * If the entry point looks like a compliler generated wrapper around + * an async method in the form "" then try to look up the async method + * "Name" it is wrapping. + */ + if (mono_method_get_flags (method, NULL) & 0x0800 /* METHOD_ATTRIBUTE_SPECIAL_NAME */) { + const char *name = mono_method_get_name (method); + int name_length = strlen (name); + + if ((*name != '<') || (name[name_length-1] != '>')) + return method; + + MonoClass *klass = mono_method_get_class (method); + char *async_name = strdup (name); + + async_name[name_length -1] = '\0'; + + MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1 /* any number of parameters */); + free (async_name); + if (async_method != NULL) + return async_method; + } + return method; } EMSCRIPTEN_KEEPALIVE char * From 432a600fc0edbc07d5bebc7987e7b6325c1e88a7 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 29 Oct 2020 21:33:16 -0500 Subject: [PATCH 3/9] Remove the test changes to wait for the xharness pr --- .../tests/WasmTestRunner/WasmTestRunner.cs | 5 ++-- .../JavaScript/Http/HttpRequestMessageTest.cs | 24 ------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs index 46a942a0f9cde1..1a88e4881021ac 100644 --- a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -3,13 +3,12 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.DotNet.XHarness.TestRunners.Xunit; public class SimpleWasmTestRunner : WasmApplicationEntryPoint { - public static async Task Main(string[] args) + public static int Main(string[] args) { var testAssembly = args[0]; var excludedTraits = new List(); @@ -58,6 +57,6 @@ public static async Task Main(string[] args) IncludedMethods = includedMethods }; - return await runner.Run(); + return runner.Run(); } } diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs index 81d197f8ff0946..d3794eda8af152 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs @@ -383,30 +383,6 @@ public void ToString_NonDefaultInstanceWithCustomHeaders_DumpAllFields(string ur "}", rm.ToString()); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowserDomSupported))] - public async Task BlobUri_Marshal_CorrectValues_Browser() - { - Runtime.InvokeJS(@" - function typedArrayToURL(typedArray, mimeType) { - return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType})) - } - const bytes = new Uint8Array(59); - for(let i = 0; i < 59; i++) { - bytes[i] = 32 + i; - } - const url = typedArrayToURL(bytes, 'text/plain'); - // Calls method with string that will be marshaled as valid URI - App.call_test_method (""InvokeString"", [ url ]); - "); - - var client = new HttpClient (); - Assert.StartsWith ("blob:", HelperMarshal._stringResource); - - var rm = new HttpRequestMessage(HttpMethod.Get, new Uri (HelperMarshal._stringResource)); - var resp = client.SendAsync (rm); - var resp2 = await resp; - } - [Fact] public void BlobStringUri_Marshal_CorrectValues() { From 65c3417ad31a2468c80805848aa9fb68c85cdaea Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 29 Oct 2020 22:43:41 -0500 Subject: [PATCH 4/9] Formatting fixes --- src/mono/wasm/runtime-test.js | 15 +++++++-------- src/mono/wasm/runtime/driver.c | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/mono/wasm/runtime-test.js b/src/mono/wasm/runtime-test.js index d5b392013ccf13..fbfacaaf9986a9 100644 --- a/src/mono/wasm/runtime-test.js +++ b/src/mono/wasm/runtime-test.js @@ -356,28 +356,27 @@ var App = { } wasm_set_main_args (main_argc, main_argv); - function isThenable(js_obj) { + function isThenable (js_obj) { // When using an external Promise library the Promise.resolve may not be sufficient // to identify the object as a Promise. - return Promise.resolve(js_obj) === js_obj || + return Promise.resolve (js_obj) === js_obj || ((typeof js_obj === "object" || typeof js_obj === "function") && typeof js_obj.then === "function") } try { // Automatic signature isn't working correctly - let exit_code = Module.mono_call_assembly_entry_point(main_assembly_name, [app_args], "mi"); + let exit_code = Module.mono_call_assembly_entry_point (main_assembly_name, [app_args], "mi"); - if (isThenable(exit_code)) + if (isThenable (exit_code)) { - exit_code.then( + exit_code.then ( (result) => { test_exit (result); }, - reason => { + (reason) => { console.error (reason); test_exit (1); - } - ) + }); } else { test_exit (exit_code); return; diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 35b71e404558fb..24ea48942e5b72 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -627,7 +627,7 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) method = mono_get_method (image, entry, NULL); /* - * If the entry point looks like a compliler generated wrapper around + * If the entry point looks like a compiler generated wrapper around * an async method in the form "" then try to look up the async method * "Name" it is wrapping. */ From 65dd42bfe2bfd4962193678b10975fe758a58a38 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 29 Oct 2020 23:56:20 -0500 Subject: [PATCH 5/9] Fix the signature --- src/mono/wasm/runtime-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/runtime-test.js b/src/mono/wasm/runtime-test.js index fbfacaaf9986a9..51d494eb2c2fa2 100644 --- a/src/mono/wasm/runtime-test.js +++ b/src/mono/wasm/runtime-test.js @@ -365,7 +365,7 @@ var App = { try { // Automatic signature isn't working correctly - let exit_code = Module.mono_call_assembly_entry_point (main_assembly_name, [app_args], "mi"); + let exit_code = Module.mono_call_assembly_entry_point (main_assembly_name, [app_args], "m"); if (isThenable (exit_code)) { From c798031563c1b54e9c1eba233abfb57b1026b324 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 30 Oct 2020 00:10:13 -0500 Subject: [PATCH 6/9] Address more feedback --- src/mono/wasm/runtime/driver.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 24ea48942e5b72..59035dfcccaad5 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -635,15 +635,15 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) const char *name = mono_method_get_name (method); int name_length = strlen (name); - if ((*name != '<') || (name[name_length-1] != '>')) + if ((*name != '<') || (name [name_length - 1] != '>')) return method; MonoClass *klass = mono_method_get_class (method); char *async_name = strdup (name); - async_name[name_length -1] = '\0'; + async_name [name_length - 1] = '\0'; - MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1 /* any number of parameters */); + MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1 /* MonoMethodSignature.param_count is hard to access here */); free (async_name); if (async_method != NULL) return async_method; From 37850c2d2288263c6fd2db47f931816124dc8d0d Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 30 Oct 2020 00:46:12 -0500 Subject: [PATCH 7/9] Update comments --- src/mono/wasm/runtime/driver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 59035dfcccaad5..8540956b5acf2a 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -629,7 +629,9 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) /* * If the entry point looks like a compiler generated wrapper around * an async method in the form "" then try to look up the async method - * "Name" it is wrapping. + * "Name" it is wrapping. We do this because the generated sync wrapper will + * call task.GetAwaiter().GetResult() when we actually want to yield + * to the host runtime. */ if (mono_method_get_flags (method, NULL) & 0x0800 /* METHOD_ATTRIBUTE_SPECIAL_NAME */) { const char *name = mono_method_get_name (method); @@ -643,7 +645,7 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) async_name [name_length - 1] = '\0'; - MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1 /* MonoMethodSignature.param_count is hard to access here */); + MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1); free (async_name); if (async_method != NULL) return async_method; From d78694f8c1df2c109a198aef3df442190fd70a8b Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 30 Oct 2020 13:38:06 -0500 Subject: [PATCH 8/9] Pass the param count from the sync method for completeness --- src/mono/wasm/runtime/driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 8540956b5acf2a..b178b8e2c9ff8b 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -645,7 +645,8 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) async_name [name_length - 1] = '\0'; - MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, -1); + MonoMethodSignature *sig = mono_method_get_signature (method, image, mono_method_get_token (method)); + MonoMethod *async_method = mono_class_get_method_from_name (klass, async_name + 1, mono_signature_get_param_count (sig)); free (async_name); if (async_method != NULL) return async_method; From 531b1fc05c92223bd7a1589a12e8bf36c442c0df Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 2 Nov 2020 19:25:22 -0600 Subject: [PATCH 9/9] Force a reference to System.Private.Runtime.InteropServices.JavaScript.dll --- src/tests/Common/wasm-test-runner/WasmTestRunner.proj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/Common/wasm-test-runner/WasmTestRunner.proj b/src/tests/Common/wasm-test-runner/WasmTestRunner.proj index 9d1c5ca51dcca1..61f2f55345977d 100644 --- a/src/tests/Common/wasm-test-runner/WasmTestRunner.proj +++ b/src/tests/Common/wasm-test-runner/WasmTestRunner.proj @@ -30,6 +30,7 @@ MicrosoftNetCoreAppRuntimePackDir="$(MicrosoftNetCoreAppRuntimePackDir)" MainAssembly="$(TestAssembly)" MainJS="$(CORE_ROOT)\runtime-test\runtime-test.js" + ExtraAssemblies="$(CORE_ROOT)\System.Private.Runtime.InteropServices.JavaScript.dll" AssemblySearchPaths="@(AssemblySearchPaths)" SkipMissingAssemblies="True" />