未验证 提交 75228aca 编写于 作者: M Marek Fišera 提交者: GitHub

[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: NAnkit Jain <radical@gmail.com>
上级 a2b6674f
...@@ -245,6 +245,10 @@ private void AppendType(StringBuilder sb, Type t) ...@@ -245,6 +245,10 @@ private void AppendType(StringBuilder sb, Type t)
AppendType(sb, t.GetElementType()!); AppendType(sb, t.GetElementType()!);
sb.Append('*'); sb.Append('*');
} }
else if (t.IsEnum)
{
AppendType(sb, Enum.GetUnderlyingType(t));
}
else else
{ {
sb.Append(t.Name switch sb.Append(t.Name switch
......
...@@ -15,6 +15,7 @@ public class BuildEnvironment ...@@ -15,6 +15,7 @@ public class BuildEnvironment
{ {
public string DotNet { get; init; } public string DotNet { get; init; }
public string RuntimePackDir { get; init; } public string RuntimePackDir { get; init; }
public string WorkloadPacksVersion { get; init; }
public bool IsWorkload { get; init; } public bool IsWorkload { get; init; }
public string DefaultBuildArgs { get; init; } public string DefaultBuildArgs { get; init; }
public IDictionary<string, string> EnvVars { get; init; } public IDictionary<string, string> EnvVars { get; init; }
...@@ -23,6 +24,8 @@ public class BuildEnvironment ...@@ -23,6 +24,8 @@ public class BuildEnvironment
public string RuntimeNativeDir { get; init; } public string RuntimeNativeDir { get; init; }
public string LogRootPath { get; init; } public string LogRootPath { get; init; }
public string WorkloadPacksDir { get; init; }
public static readonly string RelativeTestAssetsPath = @"..\testassets\"; public static readonly string RelativeTestAssetsPath = @"..\testassets\";
public static readonly string TestAssetsPath = Path.Combine(AppContext.BaseDirectory, "testassets"); public static readonly string TestAssetsPath = Path.Combine(AppContext.BaseDirectory, "testassets");
public static readonly string TestDataPath = Path.Combine(AppContext.BaseDirectory, "data"); public static readonly string TestDataPath = Path.Combine(AppContext.BaseDirectory, "data");
...@@ -57,6 +60,9 @@ public BuildEnvironment() ...@@ -57,6 +60,9 @@ public BuildEnvironment()
if (!Directory.Exists(sdkForWorkloadPath)) if (!Directory.Exists(sdkForWorkloadPath))
throw new Exception($"Could not find SDK_FOR_WORKLOAD_TESTING_PATH={sdkForWorkloadPath}"); throw new Exception($"Could not find SDK_FOR_WORKLOAD_TESTING_PATH={sdkForWorkloadPath}");
if (!Path.IsPathRooted(sdkForWorkloadPath))
sdkForWorkloadPath = Path.GetFullPath(sdkForWorkloadPath);
EnvVars = new Dictionary<string, string>(); EnvVars = new Dictionary<string, string>();
bool workloadInstalled = EnvironmentVariables.SdkHasWorkloadInstalled != null && EnvironmentVariables.SdkHasWorkloadInstalled == "true"; bool workloadInstalled = EnvironmentVariables.SdkHasWorkloadInstalled != null && EnvironmentVariables.SdkHasWorkloadInstalled == "true";
if (workloadInstalled) if (workloadInstalled)
...@@ -65,7 +71,10 @@ public BuildEnvironment() ...@@ -65,7 +71,10 @@ public BuildEnvironment()
if (string.IsNullOrEmpty(workloadPacksVersion)) if (string.IsNullOrEmpty(workloadPacksVersion))
throw new Exception($"Cannot test with workloads without WORKLOAD_PACKS_VER environment variable being set"); 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; DirectoryBuildPropsContents = s_directoryBuildPropsForWorkloads;
DirectoryBuildTargetsContents = s_directoryBuildTargetsForWorkloads; DirectoryBuildTargetsContents = s_directoryBuildTargetsForWorkloads;
...@@ -78,6 +87,8 @@ public BuildEnvironment() ...@@ -78,6 +87,8 @@ public BuildEnvironment()
} }
else 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"; RuntimePackDir = "/dont-check-runtime-pack-dir-for-no-workloads-case";
var appRefDir = EnvironmentVariables.AppRefDir; var appRefDir = EnvironmentVariables.AppRefDir;
if (string.IsNullOrEmpty(appRefDir)) if (string.IsNullOrEmpty(appRefDir))
......
...@@ -359,7 +359,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp ...@@ -359,7 +359,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp
_testOutput.WriteLine($"Binlog path: {logFilePath}"); _testOutput.WriteLine($"Binlog path: {logFilePath}");
_testOutput.WriteLine($"Binlog path: {logFilePath}"); _testOutput.WriteLine($"Binlog path: {logFilePath}");
sb.Append($" /bl:\"{logFilePath}\" /nologo"); 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) if (buildArgs.ExtraBuildArgs != null)
sb.Append($" {buildArgs.ExtraBuildArgs} "); sb.Append($" {buildArgs.ExtraBuildArgs} ");
...@@ -381,7 +381,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp ...@@ -381,7 +381,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp
// check that we are using the correct runtime pack! // 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"); 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); 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 ...@@ -938,6 +938,7 @@ public record BuildProjectOptions
bool HasIcudt = true, bool HasIcudt = true,
bool UseCache = true, bool UseCache = true,
bool ExpectSuccess = true, bool ExpectSuccess = true,
bool AssertAppBundle = true,
bool CreateProject = true, bool CreateProject = true,
bool Publish = true, bool Publish = true,
bool BuildOnlyAfterPublish = true, bool BuildOnlyAfterPublish = true,
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
...@@ -155,6 +154,120 @@ public static int Main() ...@@ -155,6 +154,120 @@ public static int Main()
Assert.Contains("Main running", output); 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 =
"""
<Project>
<UsingTask TaskName="ManagedToNativeGenerator" AssemblyFile="###WasmAppBuilder###" />
<Target Name="Build">
<PropertyGroup>
<WasmPInvokeTablePath>pinvoke-table.h</WasmPInvokeTablePath>
<WasmInterpToNativeTablePath>wasm_m2n_invoke.g.h</WasmInterpToNativeTablePath>
<WasmRuntimeICallTablePath>runtime-icall-table.h</WasmRuntimeICallTablePath>
</PropertyGroup>
<ItemGroup>
<WasmPInvokeModule Include="libSystem.Native" />
###WasmPInvokeModule###
</ItemGroup>
<ManagedToNativeGenerator
Assemblies="@(WasmPInvokeAssembly)"
PInvokeModules="@(WasmPInvokeModule)"
PInvokeOutputPath="$(WasmPInvokeTablePath)"
RuntimeIcallTableFile="$(WasmRuntimeICallTablePath)"
InterpToNativeOutputPath="$(WasmInterpToNativeTablePath)">
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</ManagedToNativeGenerator>
</Target>
</Project>
""";
string AddAssembly(string name) => $"<WasmPInvokeAssembly Include=\"{Path.Combine(libraryDir, "bin", buildArgs.Config, DefaultTargetFramework, "browser-wasm", name + ".dll")}\" />";
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] [Theory]
[BuildAndRun(host: RunHost.Chrome, parameters: new object[] { "tr_TR.UTF-8" })] [BuildAndRun(host: RunHost.Chrome, parameters: new object[] { "tr_TR.UTF-8" })]
public void BuildNativeInNonEnglishCulture(BuildArgs buildArgs, string culture, RunHost host, string id) public void BuildNativeInNonEnglishCulture(BuildArgs buildArgs, string culture, RunHost host, string id)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册