From 1cfeab38e121fbb4aabecfbf80867523426721b8 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sun, 24 Oct 2021 18:44:55 -0400 Subject: [PATCH 1/5] [wasm] Fixup symbol names with invalid chars --- .../WasmAppBuilder/PInvokeTableGenerator.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs index fddc4ba4e7d836..2b7931880868cd 100644 --- a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs @@ -24,7 +24,7 @@ public class PInvokeTableGenerator : Task [Output] public string FileWrites { get; private set; } = string.Empty; - private static char[] s_charsToReplace = new[] { '.', '-', }; + private static char[] s_charsToReplace = new[] { '.', '-', ',', '|', '<', '>' }; public override bool Execute() { @@ -157,7 +157,7 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules foreach (var module in modules.Keys) { - string symbol = ModuleNameToId(module) + "_imports"; + string symbol = FixupSymbolName(module) + "_imports"; w.WriteLine("static PinvokeImport " + symbol + " [] = {"); var assemblies_pinvokes = pinvokes. @@ -176,7 +176,7 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules w.Write("static void *pinvoke_tables[] = { "); foreach (var module in modules.Keys) { - string symbol = ModuleNameToId(module) + "_imports"; + string symbol = FixupSymbolName(module) + "_imports"; w.Write(symbol + ","); } w.WriteLine("};"); @@ -187,18 +187,6 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary modules } w.WriteLine("};"); - static string ModuleNameToId(string name) - { - if (name.IndexOfAny(s_charsToReplace) < 0) - return name; - - string fixedName = name; - foreach (char c in s_charsToReplace) - fixedName = fixedName.Replace(c, '_'); - - return fixedName; - } - static bool ShouldTreatAsVariadic(PInvoke[] candidates) { if (candidates.Length < 2) @@ -216,6 +204,26 @@ static bool ShouldTreatAsVariadic(PInvoke[] candidates) } } + private static string FixupSymbolName(string name) + { + if (name.IndexOfAny(s_charsToReplace) < 0) + return name; + + string fixedName = name; + foreach (char c in s_charsToReplace) + fixedName = fixedName.Replace(c, '_'); + + return fixedName; + } + + private static string SymbolNameForMethod(MethodInfo method) + { + string module_symbol = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!; + string class_name = method.DeclaringType.Name; + string method_name = method.Name; + return FixupSymbolName($"{module_symbol}_{class_name}_{method_name}"); + } + private string MapType (Type t) { string name = t.Name; @@ -343,15 +351,12 @@ private void EmitNativeToInterp(StreamWriter w, List callbacks) bool is_void = method.ReturnType.Name == "Void"; - string module_symbol = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!.Replace(".", "_"); - uint token = (uint)method.MetadataToken; - string class_name = method.DeclaringType.Name; - string method_name = method.Name; - string entry_name = $"wasm_native_to_interp_{module_symbol}_{class_name}_{method_name}"; + string entry_name = $"wasm_native_to_interp_{SymbolNameForMethod(method)}"; if (callbackNames.Contains (entry_name)) { - Error($"Two callbacks with the same name '{method_name}' are not supported."); + Error($"Two callbacks with the same name '{entry_name}' are not supported."); } + callbackNames.Add (entry_name); cb.EntryName = entry_name; sb.Append(MapType(method.ReturnType)); @@ -395,7 +400,7 @@ private void EmitNativeToInterp(StreamWriter w, List callbacks) // Array of function pointers w.Write ("static void *wasm_native_to_interp_funcs[] = { "); foreach (var cb in callbacks) { - w.Write (cb.EntryName + ","); + w.Write ($"\t{cb.EntryName},{Environment.NewLine}"); } w.WriteLine ("};"); @@ -403,13 +408,8 @@ private void EmitNativeToInterp(StreamWriter w, List callbacks) // The key is a string of the form _ // FIXME: Use a better encoding w.Write ("static const char *wasm_native_to_interp_map[] = { "); - foreach (var cb in callbacks) { - var method = cb.Method; - string module_symbol = method.DeclaringType!.Module!.Assembly!.GetName()!.Name!.Replace(".", "_"); - string class_name = method.DeclaringType.Name; - string method_name = method.Name; - w.WriteLine ($"\"{module_symbol}_{class_name}_{method_name}\","); - } + foreach (var cb in callbacks) + w.WriteLine ($"\"{SymbolNameForMethod(cb.Method)}\","); w.WriteLine ("};"); } From 68192c0efb19fe31475f84f138f6469db5fe14ec Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 26 Oct 2021 16:40:54 -0400 Subject: [PATCH 2/5] Add UnmanagedCallersOnly testcase using local functions and nested classes --- .../Wasm.Build.Tests/BuildTestBase.cs | 1 + .../Wasm.Build.Tests/NativeLibraryTests.cs | 6 ++-- .../testassets/AppUsingNativeLib/Program.cs | 30 ++++++++++++++++++ .../AppUsingNativeLib/native-lib.cpp | 5 +++ .../testassets/AppUsingNativeLib/native-lib.h | 4 +++ .../testassets/native-libs/native-lib.o | Bin 542 -> 0 bytes 6 files changed, 43 insertions(+), 3 deletions(-) delete mode 100644 src/tests/BuildWasmApps/testassets/native-libs/native-lib.o diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs index b6fab5c6c434b7..7ad0725c91b88f 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs @@ -253,6 +253,7 @@ protected static void InitProjectDir(string dir) {s_targetFramework} Exe + true true runtime-test.js ##EXTRA_PROPERTIES## diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs index eb306286ba5e0d..73a2b38fb633a6 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs @@ -17,14 +17,14 @@ public NativeLibraryTests(ITestOutputHelper output, SharedBuildPerTestClassFixtu { } - [ConditionalTheory(typeof(BuildTestBase), nameof(IsUsingWorkloads))] + [Theory] [BuildAndRun(aot: false)] [BuildAndRun(aot: true)] public void ProjectWithNativeReference(BuildArgs buildArgs, RunHost host, string id) { string projectName = $"AppUsingNativeLib-a"; buildArgs = buildArgs with { ProjectName = projectName }; - buildArgs = ExpandBuildArgs(buildArgs, extraItems: ""); + buildArgs = ExpandBuildArgs(buildArgs, extraItems: ""); if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? _)) { @@ -33,7 +33,6 @@ public void ProjectWithNativeReference(BuildArgs buildArgs, RunHost host, string Directory.Delete(_projectDir, recursive: true); Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, "AppUsingNativeLib"), _projectDir); - File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "native-lib.o"), Path.Combine(_projectDir, "native-lib.o")); } BuildProject(buildArgs, @@ -45,6 +44,7 @@ public void ProjectWithNativeReference(BuildArgs buildArgs, RunHost host, string host: host, id: id); Assert.Contains("print_line: 100", output); + Assert.Contains("total in helper: 253", output); Assert.Contains("from pinvoke: 142", output); } diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs index 5134392c9d8ca3..920c99c8c3daaa 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs @@ -15,7 +15,37 @@ public static int Main(string[] args) return 0; } + class Helper { + public Helper () { + int t = 0; + unsafe { + delegate *unmanaged fn = &nested_helper; + t += native_intint_callback_acceptor ((IntPtr)fn, 1); + + fn = &member_helper; + + t += native_intint_callback_acceptor ((IntPtr)fn, 2); + } + + Console.WriteLine ("total in helper: {t}"); + + // local function inside a nested class ctor. Mangled name will be something like + // int32 SimpleConsole.Test/Helper::'<.ctor>g__Helper|1_0' + [UnmanagedCallersOnly] + static int nested_helper (int j) => j + 20; + + } + } + + [UnmanagedCallersOnly] + private static int member_helper(int x) => x + 30; + + [DllImport("native-lib")] public static extern int print_line(int x); + + // FIXME: support function pointers in pinvoke arguments + [DllImport("native-lib")] + public static unsafe extern int native_intint_callback_acceptor(/*delegate *unmanaged*/ IntPtr fn, int i); } } diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.cpp b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.cpp index 329a593279fe2d..d0f1225c00cccc 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.cpp +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.cpp @@ -9,3 +9,8 @@ int print_line(int x) printf("print_line: %d\n", x); return 42 + x; } + +int native_intint_callback_acceptor(ManagedIntIntCallback fn, int i) +{ + return fn(i + 100); +} diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.h b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.h index 826637b3a2d812..8d55b398665314 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.h +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/native-lib.h @@ -10,6 +10,10 @@ extern "C" { int print_line(int x); +typedef int (*ManagedIntIntCallback)(int x); + +int native_intint_callback_acceptor(ManagedIntIntCallback fn, int i); + #ifdef __cplusplus } #endif diff --git a/src/tests/BuildWasmApps/testassets/native-libs/native-lib.o b/src/tests/BuildWasmApps/testassets/native-libs/native-lib.o deleted file mode 100644 index 10ccf42c5ff2397c2201e74ed6ffa7237ed4f24f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 542 zcmYLG&5qMB5T0?8rcEn0XSg^5qy;HSn=0MHt^C}Oc!aL&m^5t?S5CUio>Dk*;KYF& z2adc055Vj21~}eI$kzOP^Z6T(4XmjU0PySSbOLgX9d_5G)0X`15z7+w&Bc0M7PVk% zU5QGnI|6uyo0jqY`XGzC70T)iJUA$we$brHy#m7IlkwhP<0N|BV;!9!z?B~mij?dF zi&{?%NG%ErGNINbnFO}Z>;-|Q`YwR{slyeAA+&jXhZsJjb>T5P2Gqg~)p?<_XF z7>~dAy%1I~_RY=AEHCNP%met-*IYf^zNm9D{Mn~A*y#Od5+9HZqIXf#Dga+E=bKS{ z5Gk3lmPO|p!jB&Jlqe;SUcZ0y)^^+hx{t6Q0bW_|7U7qE3m6^r$s-r4!HEvJXd01) zn>%!P$?E(I&gRiHn$pWy9@@BxZ{tG6obj!Q^P-LUR>`V3R#7fxUW!H@6&DegRVY5{ zZ>U)rYTEX=F<4pNRG~4U?zI!VrRg$F(q)p)lg(V{&6XKUXKW^tt0Y@y)7jM~n=kl_ GXa4|FRg;1M From 45c60aea10ee3f1dad481af19e4557f91c93cafc Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 26 Oct 2021 16:45:19 -0400 Subject: [PATCH 3/5] fix whitespace --- .../BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs | 4 ++-- .../BuildWasmApps/testassets/AppUsingNativeLib/Program.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs index 73a2b38fb633a6..08a02be53dfa3d 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/NativeLibraryTests.cs @@ -17,7 +17,7 @@ public NativeLibraryTests(ITestOutputHelper output, SharedBuildPerTestClassFixtu { } - [Theory] + [Theory] [BuildAndRun(aot: false)] [BuildAndRun(aot: true)] public void ProjectWithNativeReference(BuildArgs buildArgs, RunHost host, string id) @@ -44,7 +44,7 @@ public void ProjectWithNativeReference(BuildArgs buildArgs, RunHost host, string host: host, id: id); Assert.Contains("print_line: 100", output); - Assert.Contains("total in helper: 253", output); + Assert.Contains("total in helper: 253", output); Assert.Contains("from pinvoke: 142", output); } diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs index 920c99c8c3daaa..d29afed0602d1c 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs @@ -44,8 +44,8 @@ public Helper () { [DllImport("native-lib")] public static extern int print_line(int x); - // FIXME: support function pointers in pinvoke arguments - [DllImport("native-lib")] - public static unsafe extern int native_intint_callback_acceptor(/*delegate *unmanaged*/ IntPtr fn, int i); + // FIXME: support function pointers in pinvoke arguments + [DllImport("native-lib")] + public static unsafe extern int native_intint_callback_acceptor(/*delegate *unmanaged*/ IntPtr fn, int i); } } From 10dca6cdf9514c94a1df4e77acaf63bf9aeb418a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Tue, 26 Oct 2021 19:18:31 -0400 Subject: [PATCH 4/5] Run the new test --- src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs index d29afed0602d1c..57b4779ff1e9fc 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs @@ -12,6 +12,7 @@ public class Test public static int Main(string[] args) { Console.WriteLine ($"from pinvoke: {SimpleConsole.Test.print_line(100)}"); + new Helper(); return 0; } From 582d3b7b0ad2ca2feaefd9d8278cbd410dfe74cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Tue, 26 Oct 2021 21:40:08 -0400 Subject: [PATCH 5/5] Fix string interpolation --- src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs index 57b4779ff1e9fc..f250459d06248b 100644 --- a/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs +++ b/src/tests/BuildWasmApps/testassets/AppUsingNativeLib/Program.cs @@ -28,7 +28,7 @@ public Helper () { t += native_intint_callback_acceptor ((IntPtr)fn, 2); } - Console.WriteLine ("total in helper: {t}"); + Console.WriteLine ($"total in helper: {t}"); // local function inside a nested class ctor. Mangled name will be something like // int32 SimpleConsole.Test/Helper::'<.ctor>g__Helper|1_0'