From 75228aca01a24087d21a76f32bf8d87dc9888648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Sat, 13 Aug 2022 10:56:21 +0200 Subject: [PATCH] [wasm] Support parameters of type Enum with icalls (#73817) * [wasm] Support parameters of type Enum with icalls, with tests * [wasm] WBT: convert sdk path to full, if needed Co-authored-by: Ankit Jain --- .../WasmAppBuilder/IcallTableGenerator.cs | 4 + .../Wasm.Build.Tests/BuildEnvironment.cs | 13 +- .../Wasm.Build.Tests/BuildTestBase.cs | 5 +- .../PInvokeTableGeneratorTests.cs | 115 +++++++++++++++++- 4 files changed, 133 insertions(+), 4 deletions(-) diff --git a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs index a1620338bcb..01d7d0eb447 100644 --- a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs +++ b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs @@ -245,6 +245,10 @@ private void AppendType(StringBuilder sb, Type t) AppendType(sb, t.GetElementType()!); sb.Append('*'); } + else if (t.IsEnum) + { + AppendType(sb, Enum.GetUnderlyingType(t)); + } else { sb.Append(t.Name switch diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs index 16c9e2e7fd0..c119db17c28 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildEnvironment.cs @@ -15,6 +15,7 @@ public class BuildEnvironment { public string DotNet { get; init; } public string RuntimePackDir { get; init; } + public string WorkloadPacksVersion { get; init; } public bool IsWorkload { get; init; } public string DefaultBuildArgs { get; init; } public IDictionary EnvVars { get; init; } @@ -23,6 +24,8 @@ public class BuildEnvironment public string RuntimeNativeDir { get; init; } public string LogRootPath { get; init; } + public string WorkloadPacksDir { get; init; } + public static readonly string RelativeTestAssetsPath = @"..\testassets\"; public static readonly string TestAssetsPath = Path.Combine(AppContext.BaseDirectory, "testassets"); public static readonly string TestDataPath = Path.Combine(AppContext.BaseDirectory, "data"); @@ -57,6 +60,9 @@ public BuildEnvironment() if (!Directory.Exists(sdkForWorkloadPath)) throw new Exception($"Could not find SDK_FOR_WORKLOAD_TESTING_PATH={sdkForWorkloadPath}"); + if (!Path.IsPathRooted(sdkForWorkloadPath)) + sdkForWorkloadPath = Path.GetFullPath(sdkForWorkloadPath); + EnvVars = new Dictionary(); bool workloadInstalled = EnvironmentVariables.SdkHasWorkloadInstalled != null && EnvironmentVariables.SdkHasWorkloadInstalled == "true"; if (workloadInstalled) @@ -65,7 +71,10 @@ public BuildEnvironment() if (string.IsNullOrEmpty(workloadPacksVersion)) throw new Exception($"Cannot test with workloads without WORKLOAD_PACKS_VER environment variable being set"); - RuntimePackDir = Path.Combine(sdkForWorkloadPath, "packs", "Microsoft.NETCore.App.Runtime.Mono.browser-wasm", workloadPacksVersion); + WorkloadPacksDir = Path.Combine(sdkForWorkloadPath, "packs"); + WorkloadPacksVersion = workloadPacksVersion; + + RuntimePackDir = Path.Combine(WorkloadPacksDir, "Microsoft.NETCore.App.Runtime.Mono.browser-wasm", WorkloadPacksVersion); DirectoryBuildPropsContents = s_directoryBuildPropsForWorkloads; DirectoryBuildTargetsContents = s_directoryBuildTargetsForWorkloads; @@ -78,6 +87,8 @@ public BuildEnvironment() } else { + WorkloadPacksDir = "/dont-use-this-no-workload-installed"; + WorkloadPacksVersion = "dont-use-this-no-workload-installed"; RuntimePackDir = "/dont-check-runtime-pack-dir-for-no-workloads-case"; var appRefDir = EnvironmentVariables.AppRefDir; if (string.IsNullOrEmpty(appRefDir)) diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs index dfb2d35d1be..e05792c9678 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs @@ -359,7 +359,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp _testOutput.WriteLine($"Binlog path: {logFilePath}"); _testOutput.WriteLine($"Binlog path: {logFilePath}"); sb.Append($" /bl:\"{logFilePath}\" /nologo"); - sb.Append($" /fl /flp:\"v:diag,LogFile={logFilePath}.log\" /v:{options.Verbosity ?? "minimal"}"); + sb.Append($" /v:{options.Verbosity ?? "minimal"}"); if (buildArgs.ExtraBuildArgs != null) sb.Append($" {buildArgs.ExtraBuildArgs} "); @@ -381,7 +381,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp // check that we are using the correct runtime pack! - if (options.ExpectSuccess) + if (options.ExpectSuccess && options.AssertAppBundle) { string bundleDir = Path.Combine(GetBinDir(config: buildArgs.Config, targetFramework: options.TargetFramework ?? DefaultTargetFramework), "AppBundle"); AssertBasicAppBundle(bundleDir, buildArgs.ProjectName, buildArgs.Config, options.MainJS ?? "test-main.js", options.HasV8Script, options.HasIcudt, options.DotnetWasmFromRuntimePack ?? !buildArgs.AOT); @@ -938,6 +938,7 @@ public record BuildProjectOptions bool HasIcudt = true, bool UseCache = true, bool ExpectSuccess = true, + bool AssertAppBundle = true, bool CreateProject = true, bool Publish = true, bool BuildOnlyAfterPublish = true, diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs index 791c211dfdf..616b0ecc1c3 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; -using System.Reflection; using Xunit; using Xunit.Abstractions; @@ -155,6 +154,120 @@ public static int Main() Assert.Contains("Main running", output); } + [ConditionalTheory(typeof(BuildTestBase), nameof(IsUsingWorkloads))] + [BuildAndRun(host: RunHost.None)] + public void IcallWithOverloadedParametersAndEnum(BuildArgs buildArgs, string id) + { + // Build a library containing icalls with overloaded parameters. + + string code = + """ + using System; + using System.Runtime.CompilerServices; + + public static class Interop + { + public enum Numbers { A, B, C, D } + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void Square(Numbers x); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern void Square(Numbers x, Numbers y); + + public static void Main() + { + // Noop + } + } + """; + + var libraryBuildArgs = ExpandBuildArgs( + buildArgs with { ProjectName = $"icall_enum_library_{buildArgs.Config}_{id}" } + ); + + (string libraryDir, string output) = BuildProject( + libraryBuildArgs, + id: id + "library", + new BuildProjectOptions( + InitProject: () => + { + File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), code); + }, + Publish: false, + DotnetWasmFromRuntimePack: false, + AssertAppBundle: false + ) + ); + + // Build a project with ManagedToNativeGenerator task reading icalls from the above library and runtime-icall-table.h bellow. + + string projectCode = + """ + + + + + pinvoke-table.h + wasm_m2n_invoke.g.h + runtime-icall-table.h + + + + + ###WasmPInvokeModule### + + + + + + + + """; + + string AddAssembly(string name) => $""; + + string icallTable = + """ + [ + { "klass":"Interop", "icalls": [{} ,{ "name": "Square(Numbers)", "func": "ves_abc", "handles": false } + ,{ "name": "Add(Numbers,Numbers)", "func": "ves_def", "handles": false } + ]} + ] + + """; + + projectCode = projectCode + .Replace("###WasmPInvokeModule###", AddAssembly("System.Private.CoreLib") + AddAssembly("System.Runtime") + AddAssembly(libraryBuildArgs.ProjectName)) + .Replace("###WasmAppBuilder###", Path.Combine(s_buildEnv.WorkloadPacksDir, "Microsoft.NET.Runtime.WebAssembly.Sdk", s_buildEnv.WorkloadPacksVersion, "tasks", DefaultTargetFramework, "WasmAppBuilder.dll")); + + buildArgs = buildArgs with { ProjectName = $"icall_enum_{buildArgs.Config}_{id}", ProjectFileContents = projectCode }; + + _projectDir = null; + + (_, output) = BuildProject( + buildArgs, + id: id + "tasks", + new BuildProjectOptions( + InitProject: () => + { + File.WriteAllText(Path.Combine(_projectDir!, "runtime-icall-table.h"), icallTable); + }, + Publish: buildArgs.AOT, + DotnetWasmFromRuntimePack: false, + UseCache: false, + AssertAppBundle: false + ) + ); + + Assert.DoesNotMatch(".*warning.*Numbers", output); + } + [Theory] [BuildAndRun(host: RunHost.Chrome, parameters: new object[] { "tr_TR.UTF-8" })] public void BuildNativeInNonEnglishCulture(BuildArgs buildArgs, string culture, RunHost host, string id) -- GitLab