Skip to content

Commit

Permalink
[browser] Enable threads in Wasm SDK (#85109)
Browse files Browse the repository at this point in the history
Co-authored-by: Aleksey Kliger (λgeek) <akliger@gmail.com>
  • Loading branch information
maraf and lambdageek authored Apr 24, 2023
1 parent 6848447 commit 46f8f1e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ Copyright (c) .NET Foundation. All rights reserved.
<_WasmInvariantGlobalization Condition="'$(_WasmInvariantGlobalization)' == ''">true</_WasmInvariantGlobalization>
<_WasmCopyOutputSymbolsToOutputDirectory>$(CopyOutputSymbolsToOutputDirectory)</_WasmCopyOutputSymbolsToOutputDirectory>
<_WasmCopyOutputSymbolsToOutputDirectory Condition="'$(_WasmCopyOutputSymbolsToOutputDirectory)'==''">true</_WasmCopyOutputSymbolsToOutputDirectory>
<_WasmEnableThreads>$(WasmEnableThreads)</_WasmEnableThreads>
<_WasmEnableThreads Condition="'$(_WasmEnableThreads)' == ''">false</_WasmEnableThreads>
<_WasmEnableWebcil>$(WasmEnableWebcil)</_WasmEnableWebcil>
<_WasmEnableWebcil Condition="'$(_WasmEnableWebcil)' == ''">false</_WasmEnableWebcil>
<_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache)</_BlazorWebAssemblyStartupMemoryCache>
Expand Down Expand Up @@ -203,6 +205,7 @@ Copyright (c) .NET Foundation. All rights reserved.
CopySymbols="$(_WasmCopyOutputSymbolsToOutputDirectory)"
OutputPath="$(OutputPath)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
>
<Output TaskParameter="AssetCandidates" ItemName="_BuildAssetsCandidates" />
<Output TaskParameter="FilesToRemove" ItemName="_WasmBuildFilesToRemove" />
Expand Down Expand Up @@ -374,6 +377,7 @@ Copyright (c) .NET Foundation. All rights reserved.
ExistingAssets="@(_WasmPublishPrefilteredAssets)"
DotNetJsVersion="$(_DotNetJsVersion)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
IsWebCilEnabled="$(_WasmEnableWebcil)"
>
<Output TaskParameter="NewCandidates" ItemName="_NewWasmPublishStaticWebAssets" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,26 @@ namespace Microsoft.NET.Sdk.WebAssembly;

public class AssetsComputingHelper
{
private static readonly string[] monoPackageIds = new[]
{
"Microsoft.NETCore.App.Runtime.Mono.browser-wasm",
"Microsoft.NETCore.App.Runtime.Mono.multithread.browser-wasm",
"Microsoft.NETCore.App.Runtime.Mono.perftrace.browser-wasm",
};

public static bool ShouldFilterCandidate(
ITaskItem candidate,
bool timezoneSupport,
bool invariantGlobalization,
bool copySymbols,
string customIcuCandidateFilename,
bool enableThreads,
out string reason)
{
var extension = candidate.GetMetadata("Extension");
var fileName = candidate.GetMetadata("FileName");
var assetType = candidate.GetMetadata("AssetType");
var fromMonoPackage = string.Equals(
candidate.GetMetadata("NuGetPackageId"),
"Microsoft.NETCore.App.Runtime.Mono.browser-wasm",
StringComparison.Ordinal);
bool fromMonoPackage = IsFromMonoPackage(candidate);

reason = extension switch
{
Expand All @@ -45,7 +50,7 @@ public static bool ShouldFilterCandidate(
".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor",
".js" when assetType == "native" && fileName != "dotnet" => $"{fileName}{extension} is not used by Blazor",
".js" when assetType == "native" && !(fileName == "dotnet" || enableThreads && fileName == "dotnet.worker") => $"{fileName}{extension} is not used by Blazor",
".pdb" when !copySymbols => "copying symbols is disabled",
".symbols" when fromMonoPackage => "extension .symbols is not required.",
_ => null
Expand All @@ -54,6 +59,12 @@ public static bool ShouldFilterCandidate(
return reason != null;
}

private static bool IsFromMonoPackage(ITaskItem candidate)
{
string packageId = candidate.GetMetadata("NuGetPackageId");
return monoPackageIds.Contains(packageId, StringComparer.Ordinal);
}

public static string GetCandidateRelativePath(ITaskItem candidate)
{
var destinationSubPath = candidate.GetMetadata("DestinationSubPath");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class ComputeWasmBuildAssets : Task

public bool FingerprintDotNetJs { get; set; }

public bool EnableThreads { get; set; }

[Output]
public ITaskItem[] AssetCandidates { get; set; }

Expand Down Expand Up @@ -79,7 +81,7 @@ public override bool Execute()
for (int i = 0; i < Candidates.Length; i++)
{
var candidate = Candidates[i];
if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason))
if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
filesToRemove.Add(candidate);
Expand All @@ -104,14 +106,15 @@ public override bool Execute()
continue;
}

if (candidate.GetMetadata("FileName") == "dotnet" && candidate.GetMetadata("Extension") == ".js")
string candidateFileName = candidate.GetMetadata("FileName");
if ((candidateFileName == "dotnet" || candidateFileName == "dotnet.worker") && candidate.GetMetadata("Extension") == ".js")
{
string newDotnetJSFileName = null;
string newDotNetJSFullPath = null;
if (FingerprintDotNetJs)
{
var itemHash = FileHasher.GetFileHash(candidate.ItemSpec);
newDotnetJSFileName = $"dotnet.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js";
newDotnetJSFileName = $"{candidateFileName}.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js";

var originalFileFullPath = Path.GetFullPath(candidate.ItemSpec);
var originalFileDirectory = Path.GetDirectoryName(originalFileFullPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public class ComputeWasmPublishAssets : Task

public bool FingerprintDotNetJs { get; set; }

public bool EnableThreads { get; set; }

public bool IsWebCilEnabled { get; set; }

[Output]
Expand Down Expand Up @@ -163,8 +165,10 @@ private List<ITaskItem> ProcessNativeAssets(
var key = kvp.Key;
var asset = kvp.Value;
var isDotNetJs = IsDotNetJs(key);
var isDotNetWorkerJs = IsDotNetWorkerJs(key);
var isDotNetWasm = IsDotNetWasm(key);
if (!isDotNetJs && !isDotNetWasm)

if (!isDotNetJs && !isDotNetWasm && !isDotNetWorkerJs)
{
if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing))
{
Expand Down Expand Up @@ -197,11 +201,16 @@ private List<ITaskItem> ProcessNativeAssets(
{
var aotDotNetJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.js");
ITaskItem newDotNetJs = null;
if (aotDotNetJs != null && FingerprintDotNetJs)
if (aotDotNetJs != null)
{
newDotNetJs = new TaskItem(Path.GetFullPath(aotDotNetJs.ItemSpec), asset.CloneCustomMetadata());
newDotNetJs.SetMetadata("OriginalItemSpec", aotDotNetJs.ItemSpec);
newDotNetJs.SetMetadata("RelativePath", $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}");

string relativePath = FingerprintDotNetJs
? $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}"
: "_framework/dotnet.js";

newDotNetJs.SetMetadata("RelativePath", relativePath);

updateMap.Add(asset.ItemSpec, newDotNetJs);
Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetJs.ItemSpec);
Expand All @@ -221,6 +230,35 @@ private List<ITaskItem> ProcessNativeAssets(
continue;
}

if (isDotNetWorkerJs)
{
var aotDotNetWorkerJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.worker.js");
ITaskItem newDotNetWorkerJs = null;
if (aotDotNetWorkerJs != null)
{
newDotNetWorkerJs = new TaskItem(Path.GetFullPath(aotDotNetWorkerJs.ItemSpec), asset.CloneCustomMetadata());
newDotNetWorkerJs.SetMetadata("OriginalItemSpec", aotDotNetWorkerJs.ItemSpec);
newDotNetWorkerJs.SetMetadata("RelativePath", "_framework/dotnet.worker.js");

updateMap.Add(asset.ItemSpec, newDotNetWorkerJs);
Log.LogMessage(MessageImportance.High, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetWorkerJs.ItemSpec);
}
else
{
newDotNetWorkerJs = new TaskItem(asset);
newDotNetWorkerJs.SetMetadata("RelativePath", "_framework/dotnet.worker.js");
Log.LogMessage(MessageImportance.High, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec);
}

ApplyPublishProperties(newDotNetWorkerJs);
nativeStaticWebAssets.Add(newDotNetWorkerJs);
if (resolvedNativeAssetToPublish.TryGetValue("dotnet.worker.js", out var resolved))
{
filesToRemove.Add(resolved);
}
continue;
}

if (isDotNetWasm)
{
var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm");
Expand Down Expand Up @@ -262,6 +300,8 @@ static bool IsDotNetJs(string key)
return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker");
}

static bool IsDotNetWorkerJs(string key) => string.Equals("dotnet.worker.js", Path.GetFileName(key), StringComparison.Ordinal);

static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal);
}

Expand Down Expand Up @@ -540,7 +580,7 @@ private void GroupResolvedFilesToPublish(

foreach (var candidate in resolvedFilesToPublish)
{
if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason))
if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec))
Expand Down

0 comments on commit 46f8f1e

Please sign in to comment.