From 8848879425f2447ce37041f60fcc4e261dc98b26 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Mon, 14 Jun 2021 20:00:36 -0400
Subject: [PATCH 01/11] Utils.RunProcess: some refactoring

- this cleans up `Utils.RunProcess` a bit, but doesn't change the
  behavior for the existing non-wasm users (Apple, and Android build
  tasks)

- New overloads are added to support getting the output, and exit code,
  and throwing only when really needed
- And running shell commands, appropriately on windows, and unix.
---
 src/tasks/AotCompilerTask/MonoAOTCompiler.cs |  13 ++-
 src/tasks/Common/Utils.cs                    | 117 ++++++++++++++++---
 2 files changed, 110 insertions(+), 20 deletions(-)

diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
index 52d37fe900e0f8..cb3876cfc9c36f 100644
--- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
+++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
@@ -417,8 +417,17 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
         try
         {
             // run the AOT compiler
-            Utils.RunProcess(CompilerBinaryPath, string.Join(" ", processArgs), envVariables, assemblyDir, silent: false,
-                    outputMessageImportance: MessageImportance.Low, debugMessageImportance: MessageImportance.Low);
+            (int exitCode, string output) = Utils.TryRunProcess(CompilerBinaryPath,
+                                                                string.Join(" ", processArgs),
+                                                                envVariables,
+                                                                assemblyDir,
+                                                                silent: false,
+                                                                debugMessageImportance: MessageImportance.Low);
+            if (exitCode != 0)
+            {
+                Log.LogError($"Precompiling failed for {assembly}: {output}");
+                return false;
+            }
         }
         catch (Exception ex)
         {
diff --git a/src/tasks/Common/Utils.cs b/src/tasks/Common/Utils.cs
index 5cb001a633429d..1174d2dfdb322c 100644
--- a/src/tasks/Common/Utils.cs
+++ b/src/tasks/Common/Utils.cs
@@ -5,6 +5,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using System.Runtime.InteropServices;
 using System.Text;
 using Microsoft.Build.Framework;
 using Microsoft.Build.Utilities;
@@ -21,6 +22,49 @@ public static string GetEmbeddedResource(string file)
         return reader.ReadToEnd();
     }
 
+    public static (int exitCode, string output) RunShellCommand(string command,
+                                        IDictionary<string, string> envVars,
+                                        string workingDir,
+                                        MessageImportance debugMessageImportance=MessageImportance.Low)
+    {
+        string scriptFileName = CreateTemporaryBatchFile(command);
+        (string shell, string args) = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+                                                    ? ("cmd", $"/c \"{scriptFileName}\"")
+                                                    : ("/bin/sh", $"\"{scriptFileName}\"");
+
+        Logger?.LogMessage(debugMessageImportance, $"Running {command} via script {scriptFileName}:");
+        Logger?.LogMessage(debugMessageImportance, File.ReadAllText(scriptFileName));
+
+        return TryRunProcess(shell,
+                             args,
+                             envVars,
+                             workingDir,
+                             silent: false,
+                             debugMessageImportance);
+
+        static string CreateTemporaryBatchFile(string command)
+        {
+            string extn = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".cmd" : ".sh";
+            string file = Path.Combine(Path.GetTempPath(), $"tmp{Guid.NewGuid():N}{extn}");
+
+            using StreamWriter sw = new(file);
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                sw.WriteLine("setlocal");
+                sw.WriteLine("set errorlevel=dummy");
+                sw.WriteLine("set errorlevel=");
+            }
+            else
+            {
+                // Use sh rather than bash, as not all 'nix systems necessarily have Bash installed
+                sw.WriteLine("#!/bin/sh");
+            }
+
+            sw.WriteLine(command);
+            return file;
+        }
+    }
+
     public static string RunProcess(
         string path,
         string args = "",
@@ -28,12 +72,32 @@ public static string RunProcess(
         string? workingDir = null,
         bool ignoreErrors = false,
         bool silent = true,
-        MessageImportance outputMessageImportance=MessageImportance.High,
         MessageImportance debugMessageImportance=MessageImportance.High)
     {
-        LogInfo($"Running: {path} {args}", debugMessageImportance);
+        (int exitCode, string output) = TryRunProcess(
+                                            path,
+                                            args,
+                                            envVars,
+                                            workingDir,
+                                            silent,
+                                            debugMessageImportance);
+
+        if (exitCode != 0 && !ignoreErrors)
+            throw new Exception("Error: Process returned non-zero exit code: " + output);
+
+        return output;
+    }
+
+    public static (int, string) TryRunProcess(
+        string path,
+        string args = "",
+        IDictionary<string, string>? envVars = null,
+        string? workingDir = null,
+        bool silent = true,
+        MessageImportance debugMessageImportance=MessageImportance.High)
+    {
+        Logger?.LogMessage(debugMessageImportance, $"Running: {path} {args}");
         var outputBuilder = new StringBuilder();
-        var errorBuilder = new StringBuilder();
         var processStartInfo = new ProcessStartInfo
         {
             FileName = path,
@@ -47,7 +111,7 @@ public static string RunProcess(
         if (workingDir != null)
             processStartInfo.WorkingDirectory = workingDir;
 
-        LogInfo($"Using working directory: {workingDir ?? Environment.CurrentDirectory}", debugMessageImportance);
+        Logger?.LogMessage(debugMessageImportance, $"Using working directory: {workingDir ?? Environment.CurrentDirectory}");
 
         if (envVars != null)
         {
@@ -69,39 +133,56 @@ public static string RunProcess(
         {
             lock (s_SyncObj)
             {
+                if (string.IsNullOrEmpty(e.Data))
+                    return;
+
                 if (!silent)
-                {
                     LogWarning(e.Data);
-                    outputBuilder.AppendLine(e.Data);
-                }
-                errorBuilder.AppendLine(e.Data);
+                outputBuilder.AppendLine(e.Data);
             }
         };
         process.OutputDataReceived += (sender, e) =>
         {
             lock (s_SyncObj)
             {
+                if (string.IsNullOrEmpty(e.Data))
+                    return;
+
                 if (!silent)
-                {
-                    LogInfo(e.Data, outputMessageImportance);
-                    outputBuilder.AppendLine(e.Data);
-                }
+                    Logger?.LogMessage(debugMessageImportance, e.Data);
+                outputBuilder.AppendLine(e.Data);
             }
         };
         process.BeginOutputReadLine();
         process.BeginErrorReadLine();
         process.WaitForExit();
 
-        if (process.ExitCode != 0)
+        Logger?.LogMessage(MessageImportance.High, $"Exit code: {process.ExitCode}");
+        return (process.ExitCode, outputBuilder.ToString().Trim('\r', '\n'));
+    }
+
+    internal static string CreateTemporaryBatchFile(string command)
+    {
+        string extn = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".cmd" : ".sh";
+        string file = Path.Combine(Path.GetTempPath(), $"tmp{Guid.NewGuid():N}{extn}");
+
+        using StreamWriter sw = new(file);
+        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
         {
-            Logger?.LogMessage(MessageImportance.High, $"Exit code: {process.ExitCode}");
-            if (!ignoreErrors)
-                throw new Exception("Error: Process returned non-zero exit code: " + errorBuilder);
+                sw.WriteLine("setlocal");
+                sw.WriteLine("set errorlevel=dummy");
+                sw.WriteLine("set errorlevel=");
+        }
+        else
+        {
+            // Use sh rather than bash, as not all 'nix systems necessarily have Bash installed
+            sw.WriteLine("#!/bin/sh");
         }
 
-        return outputBuilder.ToString().Trim('\r', '\n');
-    }
+        sw.WriteLine(command);
 
+        return file;
+    }
 #if NETCOREAPP
     public static void DirectoryCopy(string sourceDir, string destDir, Func<string, bool> predicate)
     {

From aefb1155e0d46bac86858449985faa579aacc897 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Mon, 14 Jun 2021 20:01:33 -0400
Subject: [PATCH 02/11] [wasm] Compile .bc -> .o files, in parallel

Currently, we use `mono-aot-cross` to compile the managed assemblies
into bitcode files. Then we pass the `.bc` files to `emcc` for linking.
We can save some amount of work, if precompile `.bc` files to `.o`
files, and pass them for linking.

This would also allow us to rebuild the `.o` files only when needed,
thus improving incremental builds.
Also, emscripten has recently removed some amount of parallelization, so
this allows us to do some pre-linking work in parallel, and speed up the
builds a little bit.

This is implemented via a new `EmccCompile` task, that is meant *only*
for compiling, and not as a general purpose `emcc` invocation task.
---
 src/mono/wasm/build/WasmApp.Native.targets    |  75 +++++----
 src/tasks/WasmAppBuilder/EmccCompile.cs       | 146 ++++++++++++++++++
 src/tasks/WasmAppBuilder/WasmAppBuilder.cs    |   5 -
 .../WasmAppBuilder/WasmAppBuilder.csproj      |   2 +
 4 files changed, 193 insertions(+), 35 deletions(-)
 create mode 100644 src/tasks/WasmAppBuilder/EmccCompile.cs

diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets
index b16195a618af12..1baa21c5501d56 100644
--- a/src/mono/wasm/build/WasmApp.Native.targets
+++ b/src/mono/wasm/build/WasmApp.Native.targets
@@ -3,6 +3,7 @@
 
   <UsingTask TaskName="PInvokeTableGenerator" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
   <UsingTask TaskName="IcallTableGenerator" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
+  <UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmccCompile" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
 
   <PropertyGroup>
     <_WasmBuildNativeCoreDependsOn>
@@ -165,7 +166,7 @@
       <_EmccOptimizationFlagDefault Condition="'$(_EmccOptimizationFlagDefault)' == ''">-Oz</_EmccOptimizationFlagDefault>
 
       <EmccCompileOptimizationFlag Condition="'$(EmccCompileOptimizationFlag)' == ''">$(_EmccOptimizationFlagDefault)</EmccCompileOptimizationFlag>
-      <EmccLinkOptimizationFlag    Condition="'$(EmccLinkOptimizationFlag)' == ''"   >$(_EmccOptimizationFlagDefault)</EmccLinkOptimizationFlag>
+      <EmccLinkOptimizationFlag    Condition="'$(EmccLinkOptimizationFlag)' == ''"   >-O0</EmccLinkOptimizationFlag>
     </PropertyGroup>
 
     <ItemGroup>
@@ -173,10 +174,6 @@
       <_EmccCommonFlags Include="$(EmccFlags)" />
       <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" />
       <_EmccCommonFlags Include="-g"                                Condition="'$(WasmNativeStrip)' == 'false'" />
-      <_EmccCommonFlags Include="-DENABLE_AOT=1"                    Condition="'$(RunAOTCompilation)' == 'true'" />
-      <_EmccCommonFlags Include="-DDRIVER_GEN=1"                    Condition="'$(RunAOTCompilation)' == 'true'" />
-      <_EmccCommonFlags Include="-DINVARIANT_GLOBALIZATION=1"       Condition="'$(InvariantGlobalization)' == 'true'" />
-      <_EmccCommonFlags Include="-DLINK_ICALLS=1"                   Condition="'$(WasmLinkIcalls)' == 'true'" />
       <_EmccCommonFlags Include="-v"                                Condition="'$(EmccVerbose)' != 'false'" />
     </ItemGroup>
 
@@ -186,11 +183,7 @@
    </PropertyGroup>
 
    <ItemGroup>
-     <_WasmObjectsToBuild Include="$(_WasmRuntimePackSrcDir)\*.c" />
-     <_WasmObjectsToBuild OutputPath="$(_WasmIntermediateOutputPath)%(FileName).o" />
-
      <_DotnetJSSrcFile Include="$(_WasmRuntimePackSrcDir)\*.js" />
-     <_WasmPInvokeModules Include="%(_WasmNativeFileForLinking.FileName)" />
    </ItemGroup>
   </Target>
 
@@ -227,54 +220,80 @@
       <!-- Adding optimization flag at the top, so it gets precedence -->
       <_EmccCFlags Include="$(EmccCompileOptimizationFlag)" />
       <_EmccCFlags Include="@(_EmccCommonFlags)" />
+
+      <_EmccCFlags Include="-DENABLE_AOT=1"                    Condition="'$(RunAOTCompilation)' == 'true'" />
+      <_EmccCFlags Include="-DDRIVER_GEN=1"                    Condition="'$(RunAOTCompilation)' == 'true'" />
+      <_EmccCFlags Include="-DINVARIANT_GLOBALIZATION=1"       Condition="'$(InvariantGlobalization)' == 'true'" />
+      <_EmccCFlags Include="-DLINK_ICALLS=1"                   Condition="'$(WasmLinkIcalls)' == 'true'" />
       <_EmccCFlags Include="-DCORE_BINDINGS" />
       <_EmccCFlags Include="-DGEN_PINVOKE=1" />
+
       <_EmccCFlags Include="&quot;-I%(_EmccIncludePaths.Identity)&quot;" />
       <_EmccCFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" />
       <_EmccCFlags Include="-s EXPORTED_FUNCTIONS='[@(_ExportedFunctions->'&quot;%(Identity)&quot;', ',')]'" Condition="@(_ExportedFunctions->Count()) > 0" />
 
       <_EmccCFlags Include="$(EmccExtraCFlags)" />
+
+      <_WasmRuntimePackSrcFile Remove="@(_WasmRuntimePackSrcFile)" />
+      <_WasmRuntimePackSrcFile Include="$(_WasmRuntimePackSrcDir)\*.c" />
+      <_WasmRuntimePackSrcFile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" />
+      <_WasmSourceFileToCompile Include="@(_WasmRuntimePackSrcFile)" />
     </ItemGroup>
 
     <PropertyGroup>
+      <_EmBuilder Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">embuilder.bat</_EmBuilder>
+      <_EmBuilder Condition="!$([MSBuild]::IsOSPlatform('WINDOWS'))">embuilder.py</_EmBuilder>
       <_EmccCompileRsp>$(_WasmIntermediateOutputPath)emcc-compile.rsp</_EmccCompileRsp>
     </PropertyGroup>
 
     <WriteLinesToFile Lines="@(_EmccCFlags)" File="$(_EmccCompileRsp)" Overwrite="true" WriteOnlyWhenDifferent="true" />
 
+    <!-- warm up the cache -->
+    <Exec Command="$(_EmBuilder) build MINIMAL" EnvironmentVariables="@(EmscriptenEnvVars)" />
+
     <Message Text="Compiling native assets with emcc. This may take a while ..." Importance="High" />
-    <Exec Command='emcc "@$(_EmccDefaultFlagsRsp)" "@$(_EmccCompileRsp)" "%(_WasmObjectsToBuild.Identity)" -c -o "%(_WasmObjectsToBuild.OutputPath)"' EnvironmentVariables="@(EmscriptenEnvVars)" />
+    <EmccCompile SourceFiles="@(_WasmSourceFileToCompile)" Arguments='"@$(_EmccDefaultFlagsRsp)" "@$(_EmccCompileRsp)"' EnvironmentVariables="@(EmscriptenEnvVars)" />
   </Target>
 
   <Target Name="_WasmLinkDotNet">
     <ItemGroup>
-      <_WasmRuntimePackNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)\*.a" />
-      <_WasmObjects Include="@(_WasmRuntimePackNativeLibs)" />
-      <_WasmObjects Include="@(_WasmObjectsToBuild->'%(OutputPath)')" />
-
       <!-- Adding optimization flag at the top, so it gets precedence -->
       <_EmccLDFlags Include="$(EmccLinkOptimizationFlag)" />
       <_EmccLDFlags Include="@(_EmccCommonFlags)" />
+
       <_EmccLDFlags Include="-s TOTAL_MEMORY=536870912" />
       <_EmccLDFlags Include="$(EmccExtraLDFlags)" />
+    </ItemGroup>
 
-      <_EmccLDFlags Include="--js-library &quot;%(_DotnetJSSrcFile.Identity)&quot;" />
-      <_EmccLDFlags Include="--js-library &quot;%(_WasmExtraJSFile.Identity)&quot;" Condition="'%(_WasmExtraJSFile.Kind)' == 'js-library'" />
+    <EmccCompile SourceFiles="@(_BitCodeFile)" Arguments="&quot;@$(_EmccDefaultFlagsRsp)&quot; @(_EmccLDFlags->'%(Identity)', ' ')" EnvironmentVariables="@(EmscriptenEnvVars)" />
 
-      <_EmccLDFlags Include="--pre-js &quot;%(_WasmExtraJSFile.Identity)&quot;"     Condition="'%(_WasmExtraJSFile.Kind)' == 'pre-js'" />
-      <_EmccLDFlags Include="--post-js &quot;%(_WasmExtraJSFile.Identity)&quot;"    Condition="'%(_WasmExtraJSFile.Kind)' == 'post-js'" />
+    <ItemGroup>
+      <!-- order seems to matter -->
+      <_WasmNativeFileForLinking Include="%(_BitcodeFile.ObjectFile)" />
+      <_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompile.ObjectFile)" />
+
+      <!-- libmono* needs to be at the end, since it is used to resolve references the previous .o files -->
+      <_WasmNativeFileForLinking Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)\*.a" />
+
+      <_EmccLinkStepArgs Include="@(_EmccLDFlags)" />
+      <_EmccLinkStepArgs Include="--js-library &quot;%(_DotnetJSSrcFile.Identity)&quot;" />
+      <_EmccLinkStepArgs Include="--js-library &quot;%(_WasmExtraJSFile.Identity)&quot;" Condition="'%(_WasmExtraJSFile.Kind)' == 'js-library'" />
+
+      <_EmccLinkStepArgs Include="--pre-js &quot;%(_WasmExtraJSFile.Identity)&quot;"     Condition="'%(_WasmExtraJSFile.Kind)' == 'pre-js'" />
+      <_EmccLinkStepArgs Include="--post-js &quot;%(_WasmExtraJSFile.Identity)&quot;"    Condition="'%(_WasmExtraJSFile.Kind)' == 'post-js'" />
 
-      <_EmccLDFlags Include="&quot;%(_WasmNativeFileForLinking.Identity)&quot;" />
-      <_EmccLDFlags Include="&quot;%(_WasmObjects.Identity)&quot;" />
-      <_EmccLDFlags Include="-o &quot;$(_WasmIntermediateOutputPath)dotnet.js&quot;" />
+      <_EmccLinkStepArgs Include="&quot;%(_WasmNativeFileForLinking.Identity)&quot;" />
+      <_EmccLinkStepArgs Include="-o &quot;$(_WasmIntermediateOutputPath)dotnet.js&quot;" />
     </ItemGroup>
 
     <PropertyGroup>
       <_EmccLinkRsp>$(_WasmIntermediateOutputPath)emcc-link.rsp</_EmccLinkRsp>
     </PropertyGroup>
 
-    <WriteLinesToFile Lines="@(_EmccLDFlags)" File="$(_EmccLinkRsp)" Overwrite="true" WriteOnlyWhenDifferent="true" />
-    <Message Text="Running emcc with @(_EmccLDFlags->'%(Identity)', ' ')" Importance="Low" />
+    <WriteLinesToFile Lines="@(_EmccLinkStepArgs)" File="$(_EmccLinkRsp)" Overwrite="true" WriteOnlyWhenDifferent="true" />
+
+    <Message Text="Linking with emcc. This may take a while ..." Importance="High" />
+    <Message Text="Running emcc with @(_EmccLinkStepArgs->'%(Identity)', ' ')" Importance="Low" />
     <Exec Command='emcc "@$(_EmccDefaultFlagsRsp)" "@$(_EmccLinkRsp)"' EnvironmentVariables="@(EmscriptenEnvVars)" />
 
     <Exec Command='wasm-opt$(_ExeExt) --strip-dwarf "$(_WasmIntermediateOutputPath)dotnet.wasm" -o "$(_WasmIntermediateOutputPath)dotnet.wasm"' Condition="'$(WasmNativeStrip)' == 'true'" IgnoreStandardErrorWarningFormat="true" EnvironmentVariables="@(EmscriptenEnvVars)" />
@@ -289,7 +308,7 @@
 
   <Target Name="_GenerateDriverGenC" Condition="'$(RunAOTCompilation)' != 'true' and '$(WasmProfilers)' != ''">
     <PropertyGroup>
-      <EmccFlags>$(EmccFlags) -DDRIVER_GEN=1</EmccFlags>
+      <EmccExtraCFlags>$(EmccExtraCFlags) -DDRIVER_GEN=1</EmccExtraCFlags>
       <InitAotProfilerCmd>
 void mono_profiler_init_aot (const char *desc)%3B
 EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_profiler_init_aot (desc)%3B }
@@ -404,7 +423,7 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_
       Profilers="$(WasmProfilers)"
       AotModulesTablePath="$(_WasmIntermediateOutputPath)driver-gen.c"
       UseLLVM="true"
-      DisableParallelAot="true"
+      DisableParallelAot="$(DisableParallelAot)"
       DedupAssembly="$(_WasmDedupAssembly)"
       LLVMDebug="dwarfdebug"
       LLVMPath="$(EmscriptenUpstreamBinPath)" >
@@ -419,12 +438,8 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_
 
       <_AOTAssemblies Include="@(_WasmAssembliesInternal)" Condition="'%(_WasmAssembliesInternal._InternalForceInterpret)' != 'true'" />
       <_BitcodeFile Include="%(_WasmAssembliesInternal.LlvmBitcodeFile)" />
-
-      <_WasmNativeFileForLinking Include="@(_BitcodeFile)" />
+      <_BitcodeFile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" />
     </ItemGroup>
-
-    <Error Condition="@(_BitcodeFile->Count()) != @(_AOTAssemblies->Count())"
-           Text="Bug: Number of aot assemblies doesn't match the number of generated bitcode files. BitcodeFiles: @(_BitcodeFile->Count()) vs Assemblies: @(_AOTAssemblies->Count())" />
   </Target>
 
   <!-- '$(ArchiveTests)' != 'true' is to skip on CI for now -->
diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs
new file mode 100644
index 00000000000000..15aabfb28dabe9
--- /dev/null
+++ b/src/tasks/WasmAppBuilder/EmccCompile.cs
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+#nullable enable
+
+namespace Microsoft.WebAssembly.Build.Tasks
+{
+    /// <summary>
+    /// This is meant to *compile* source files only. It is *not* a general purpose
+    /// `emcc` invocation task.
+    ///
+    /// It runs `emcc` for each source file, and with output to `%(SourceFiles.ObjectFile)`
+    ///
+    /// </summary>
+    public class EmccCompile : Microsoft.Build.Utilities.Task
+    {
+        [NotNull]
+        [Required]
+        public ITaskItem[]? SourceFiles            { get; set; }
+
+        public ITaskItem[]? EnvironmentVariables   { get; set; }
+        public bool         DisableParallelCompile { get; set; }
+        public string       Arguments              { get; set; } = string.Empty;
+        public string?      WorkingDirectory       { get; set; }
+
+        [Output]
+        public ITaskItem[]? OutputFiles { get; set; }
+
+        private string? _tempPath;
+
+        public override bool Execute()
+        {
+            ITaskItem? badItem = SourceFiles.FirstOrDefault(sf => string.IsNullOrEmpty(sf.GetMetadata("ObjectFile")));
+            if (badItem != null)
+            {
+                Log.LogError($"Source file {badItem.ItemSpec} is missing ObjectFile metadata.");
+                return false;
+            }
+
+            IDictionary<string, string> envVarsDict = GetEnvironmentVariablesDict();
+            ConcurrentBag<ITaskItem> outputItems = new();
+            try
+            {
+                Log.LogMessage(MessageImportance.Low, "Using environment variables:");
+                foreach (var kvp in envVarsDict)
+                    Log.LogMessage(MessageImportance.Low, $"\t{kvp.Key} = {kvp.Value}");
+
+                string workingDir = Environment.CurrentDirectory;
+                Log.LogMessage(MessageImportance.Low, $"Using working directory: {workingDir}");
+
+                _tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+                Directory.CreateDirectory(_tempPath);
+
+                if (DisableParallelCompile)
+                {
+                    foreach (ITaskItem srcItem in SourceFiles)
+                    {
+                        if (!ProcessSourceFile(srcItem))
+                            return false;
+                    }
+                }
+                else
+                {
+                    ParallelLoopResult result = Parallel.ForEach(SourceFiles,
+                                                    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
+                                                    (srcItem, state) =>
+                    {
+                        if (!ProcessSourceFile(srcItem))
+                            state.Stop();
+                    });
+
+                    if (!result.IsCompleted && !Log.HasLoggedErrors)
+                        Log.LogError("Unknown failed occured while compiling");
+                }
+            }
+            finally
+            {
+                if (!string.IsNullOrEmpty(_tempPath))
+                    Directory.Delete(_tempPath, true);
+            }
+
+            OutputFiles = outputItems.ToArray();
+            return !Log.HasLoggedErrors;
+
+            bool ProcessSourceFile(ITaskItem srcItem)
+            {
+                string srcFile = srcItem.ItemSpec;
+                string objFile = srcItem.GetMetadata("ObjectFile");
+
+                try
+                {
+                    string command = $"emcc {Arguments} -c -o {objFile} {srcFile}";
+                    (int exitCode, string output) = Utils.RunShellCommand(command, envVarsDict, workingDir: Environment.CurrentDirectory);
+
+                    if (exitCode != 0)
+                    {
+                        Log.LogError($"Failed to compile {srcFile} -> {objFile}: {output}");
+                        return false;
+                    }
+
+                    ITaskItem newItem = new TaskItem(objFile);
+                    newItem.SetMetadata("SourceFile", srcFile);
+                    outputItems.Add(newItem);
+
+                    return true;
+                }
+                catch (Exception ex)
+                {
+                    Log.LogError($"Failed to compile {srcFile} -> {objFile}: {ex.Message}");
+                    return false;
+                }
+            }
+        }
+
+        private IDictionary<string, string> GetEnvironmentVariablesDict()
+        {
+            Dictionary<string, string> envVarsDict = new();
+            if (EnvironmentVariables == null)
+                return envVarsDict;
+
+            foreach (var item in EnvironmentVariables)
+            {
+                var parts = item.ItemSpec.Split(new char[] {'='}, 2, StringSplitOptions.None);
+                if (parts.Length == 0)
+                    continue;
+
+                string key = parts[0];
+                string value = parts.Length > 1 ? parts[1] : string.Empty;
+
+                envVarsDict[key] = value;
+            }
+
+            return envVarsDict;
+        }
+    }
+}
diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
index 9ef7679c292b66..22e734e0d01122 100644
--- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
+++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
@@ -3,16 +3,11 @@
 
 using System;
 using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
-using System.Text;
-using System.Text.Encodings.Web;
 using System.Text.Json;
 using System.Text.Json.Serialization;
-using System.Reflection;
 using Microsoft.Build.Framework;
 using Microsoft.Build.Utilities;
 
diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
index 23074621b89730..b27176e2774006 100644
--- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
+++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
@@ -14,6 +14,8 @@
   </ItemGroup>
 
   <ItemGroup>
+    <Compile Include="..\Common\Utils.cs" />
+
     <PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
     <PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
     <PackageReference Include="Microsoft.Build.Tasks.Core" Version="$(RefOnlyMicrosoftBuildTasksCoreVersion)" />

From 1909fcc245fecb364459caa2e988a8ef3519a3b4 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Mon, 14 Jun 2021 20:19:22 -0400
Subject: [PATCH 03/11] Disable failing tests

`System.IO.MemoryMappedFiles.Tests` - Issue: https://github.com/dotnet/runtime/issues/54194
---
 src/libraries/tests.proj | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index 0d004b2dfd3c5b..7e9c5d88d47854 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -293,6 +293,9 @@
 
     <!-- Issue: https://github.com/dotnet/runtime/issues/50959 -->
     <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.IO.Pipelines\tests\System.IO.Pipelines.Tests.csproj" />
+
+    <!-- Issue: https://github.com/dotnet/runtime/issues/54194 -->
+    <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.IO.MemoryMappedFiles\tests\System.IO.MemoryMappedFiles.Tests.csproj" />
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(BuildAOTTestsOnHelix)' == 'true' and '$(RunDisabledWasmTests)' != 'true'">

From e7b638c36091d27182ef192f86c516f6ddf041f4 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 15 Jun 2021 17:54:30 -0400
Subject: [PATCH 04/11] [wasm] EmccCompile task: Use msbuild's new resource
 management API

- `IBuildEngine9.RequestCores`
- This is available only in 16.10+, so bump msbuild used for building
  the tests
---
 eng/Versions.props                      | 2 +-
 src/tasks/WasmAppBuilder/EmccCompile.cs | 8 ++++++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/eng/Versions.props b/eng/Versions.props
index 21bf781867ee1d..274263509a8b21 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -138,7 +138,7 @@
       These are used as reference assemblies only, so they must not take a ProdCon/source-build
       version. Insert "RefOnly" to avoid assignment via PVP.
     -->
-    <RefOnlyMicrosoftBuildVersion>16.8.0</RefOnlyMicrosoftBuildVersion>
+    <RefOnlyMicrosoftBuildVersion>16.10.0</RefOnlyMicrosoftBuildVersion>
     <RefOnlyMicrosoftBuildFrameworkVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildFrameworkVersion>
     <RefOnlyMicrosoftBuildTasksCoreVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildTasksCoreVersion>
     <RefOnlyMicrosoftBuildUtilitiesCoreVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildUtilitiesCoreVersion>
diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs
index 15aabfb28dabe9..fdab2f938c7f17 100644
--- a/src/tasks/WasmAppBuilder/EmccCompile.cs
+++ b/src/tasks/WasmAppBuilder/EmccCompile.cs
@@ -61,7 +61,11 @@ public override bool Execute()
                 _tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                 Directory.CreateDirectory(_tempPath);
 
-                if (DisableParallelCompile)
+                int allowedParallelism = Math.Min(SourceFiles.Length, Environment.ProcessorCount);
+                if (BuildEngine is IBuildEngine9 be9)
+                    allowedParallelism = be9.RequestCores(allowedParallelism);
+
+                if (DisableParallelCompile || allowedParallelism == 1)
                 {
                     foreach (ITaskItem srcItem in SourceFiles)
                     {
@@ -72,7 +76,7 @@ public override bool Execute()
                 else
                 {
                     ParallelLoopResult result = Parallel.ForEach(SourceFiles,
-                                                    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
+                                                    new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism },
                                                     (srcItem, state) =>
                     {
                         if (!ProcessSourceFile(srcItem))

From 9f23826a1e44c4ef28a83e5fd977239e985a1b38 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 15 Jun 2021 17:55:28 -0400
Subject: [PATCH 05/11] cleanup

---
 src/mono/wasm/build/WasmApp.Native.targets | 2 +-
 src/tasks/Common/Utils.cs                  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets
index 1baa21c5501d56..defac1c34e437f 100644
--- a/src/mono/wasm/build/WasmApp.Native.targets
+++ b/src/mono/wasm/build/WasmApp.Native.targets
@@ -249,7 +249,7 @@
     <WriteLinesToFile Lines="@(_EmccCFlags)" File="$(_EmccCompileRsp)" Overwrite="true" WriteOnlyWhenDifferent="true" />
 
     <!-- warm up the cache -->
-    <Exec Command="$(_EmBuilder) build MINIMAL" EnvironmentVariables="@(EmscriptenEnvVars)" />
+    <Exec Command="$(_EmBuilder) build MINIMAL" EnvironmentVariables="@(EmscriptenEnvVars)" StandardOutputImportance="Low" StandardErrorImportance="Low" />
 
     <Message Text="Compiling native assets with emcc. This may take a while ..." Importance="High" />
     <EmccCompile SourceFiles="@(_WasmSourceFileToCompile)" Arguments='"@$(_EmccDefaultFlagsRsp)" "@$(_EmccCompileRsp)"' EnvironmentVariables="@(EmscriptenEnvVars)" />
diff --git a/src/tasks/Common/Utils.cs b/src/tasks/Common/Utils.cs
index 3fc98d845cbffb..ea2aba607dd8e0 100644
--- a/src/tasks/Common/Utils.cs
+++ b/src/tasks/Common/Utils.cs
@@ -157,7 +157,7 @@ public static (int, string) TryRunProcess(
         process.BeginErrorReadLine();
         process.WaitForExit();
 
-        Logger?.LogMessage(MessageImportance.High, $"Exit code: {process.ExitCode}");
+        Logger?.LogMessage(debugMessageImportance, $"Exit code: {process.ExitCode}");
         return (process.ExitCode, outputBuilder.ToString().Trim('\r', '\n'));
     }
 

From f87f705d334657b4ccba1a18ce3fb1a7d0db1769 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Wed, 16 Jun 2021 00:12:15 -0400
Subject: [PATCH 06/11] Correctly handle non-aot native case

---
 src/mono/wasm/build/WasmApp.Native.targets | 6 +++++-
 src/tasks/WasmAppBuilder/EmccCompile.cs    | 8 +++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets
index defac1c34e437f..70c0cb48eaddda 100644
--- a/src/mono/wasm/build/WasmApp.Native.targets
+++ b/src/mono/wasm/build/WasmApp.Native.targets
@@ -265,7 +265,11 @@
       <_EmccLDFlags Include="$(EmccExtraLDFlags)" />
     </ItemGroup>
 
-    <EmccCompile SourceFiles="@(_BitCodeFile)" Arguments="&quot;@$(_EmccDefaultFlagsRsp)&quot; @(_EmccLDFlags->'%(Identity)', ' ')" EnvironmentVariables="@(EmscriptenEnvVars)" />
+    <EmccCompile
+          Condition="@(_BitCodeFile->Count()) > 0"
+          SourceFiles="@(_BitCodeFile)"
+          Arguments="&quot;@$(_EmccDefaultFlagsRsp)&quot; @(_EmccLDFlags->'%(Identity)', ' ')"
+          EnvironmentVariables="@(EmscriptenEnvVars)" />
 
     <ItemGroup>
       <!-- order seems to matter -->
diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs
index fdab2f938c7f17..c07a934c1851ca 100644
--- a/src/tasks/WasmAppBuilder/EmccCompile.cs
+++ b/src/tasks/WasmAppBuilder/EmccCompile.cs
@@ -34,12 +34,18 @@ public class EmccCompile : Microsoft.Build.Utilities.Task
         public string?      WorkingDirectory       { get; set; }
 
         [Output]
-        public ITaskItem[]? OutputFiles { get; set; }
+        public ITaskItem[]? OutputFiles            { get; private set; }
 
         private string? _tempPath;
 
         public override bool Execute()
         {
+            if (SourceFiles.Length == 0)
+            {
+                Log.LogError($"No SourceFiles to compile");
+                return false;
+            }
+
             ITaskItem? badItem = SourceFiles.FirstOrDefault(sf => string.IsNullOrEmpty(sf.GetMetadata("ObjectFile")));
             if (badItem != null)
             {

From 1be69d63358fecda6056a5dea84f9b55bbc39c34 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 22 Jun 2021 00:23:34 -0400
Subject: [PATCH 07/11] Disable Microsoft.NETCore.Platforms.Tests on wasm, for
 local builds too

- This is meant to be disabled for CI (it has `IgnoreForCI=true` in the
  csproj)
---
 src/libraries/tests.proj | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index b1ca6c3a1ddba5..565b9b4e8487bf 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -255,6 +255,8 @@
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(RunDisabledWasmTests)' != 'true'">
+    <ProjectExclusions Include="$(MSBuildThisFileDirectory)Microsoft.NETCore.Platforms\tests\Microsoft.NETCore.Platform.Tests.csproj" />
+
     <!-- Mono-Browser ignores runtimeconfig.template.json (e.g. for this it has "System.Globalization.EnforceJapaneseEraYearRanges": true) -->
     <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Globalization.Calendars\tests\CalendarTestWithConfigSwitch\System.Globalization.CalendarsWithConfigSwitch.Tests.csproj" />
 

From 569464428ea14f1e80a0202099c9d37bad682c28 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 22 Jun 2021 12:23:46 -0400
Subject: [PATCH 08/11] Undo 16.10.0 msbuild bump

.. because we keep running into the following on browser, and other
platforms:

```
/__w/1/s/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj : error NU1201: Project System.Security.AccessControl is not compatible with net472 (.NETFramework,Version=v4.7.2). Project System.Security.AccessControl supports: net6.0 (.NETCoreApp,Version=v6.0) [/__w/1/s/Build.proj]
\#\#[error]src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj(0,0): error NU1201: (NETCORE_ENGINEERING_TELEMETRY=Restore) Project System.Security.AccessControl is not compatible with net472 (.NETFramework,Version=v4.7.2). Project System.Security.AccessControl supports: net6.0 (.NETCoreApp,Version=v6.0)
```
---
 eng/Versions.props                      | 2 +-
 src/tasks/WasmAppBuilder/EmccCompile.cs | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/eng/Versions.props b/eng/Versions.props
index 6610ca053c02a6..7e0f2c257ced4a 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -139,7 +139,7 @@
       These are used as reference assemblies only, so they must not take a ProdCon/source-build
       version. Insert "RefOnly" to avoid assignment via PVP.
     -->
-    <RefOnlyMicrosoftBuildVersion>16.10.0</RefOnlyMicrosoftBuildVersion>
+    <RefOnlyMicrosoftBuildVersion>16.9.0</RefOnlyMicrosoftBuildVersion>
     <RefOnlyMicrosoftBuildFrameworkVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildFrameworkVersion>
     <RefOnlyMicrosoftBuildTasksCoreVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildTasksCoreVersion>
     <RefOnlyMicrosoftBuildUtilitiesCoreVersion>$(RefOnlyMicrosoftBuildVersion)</RefOnlyMicrosoftBuildUtilitiesCoreVersion>
diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs
index c07a934c1851ca..b175c62c2ee11f 100644
--- a/src/tasks/WasmAppBuilder/EmccCompile.cs
+++ b/src/tasks/WasmAppBuilder/EmccCompile.cs
@@ -68,8 +68,10 @@ public override bool Execute()
                 Directory.CreateDirectory(_tempPath);
 
                 int allowedParallelism = Math.Min(SourceFiles.Length, Environment.ProcessorCount);
+#if false // Enable this when we bump msbuild to 16.1.0
                 if (BuildEngine is IBuildEngine9 be9)
                     allowedParallelism = be9.RequestCores(allowedParallelism);
+#endif
 
                 if (DisableParallelCompile || allowedParallelism == 1)
                 {

From b7f52e46d1f6d2597dfc428eab95bf3a951fd206 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 22 Jun 2021 12:36:51 -0400
Subject: [PATCH 09/11] undo test exclusion change related to the 16.10.0 bump

---
 src/libraries/tests.proj | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index 565b9b4e8487bf..b1ca6c3a1ddba5 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -255,8 +255,6 @@
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(RunDisabledWasmTests)' != 'true'">
-    <ProjectExclusions Include="$(MSBuildThisFileDirectory)Microsoft.NETCore.Platforms\tests\Microsoft.NETCore.Platform.Tests.csproj" />
-
     <!-- Mono-Browser ignores runtimeconfig.template.json (e.g. for this it has "System.Globalization.EnforceJapaneseEraYearRanges": true) -->
     <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Globalization.Calendars\tests\CalendarTestWithConfigSwitch\System.Globalization.CalendarsWithConfigSwitch.Tests.csproj" />
 

From f3a45d753105510ccf6a1478654891c1feff27c5 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 22 Jun 2021 14:36:50 -0400
Subject: [PATCH 10/11] disable Microsoft.NETCore.Platforms.Tests on wasm

This is already not being sent to CI with `IgnoreForCI=true`.
It fails on CI with:

```
/_/src/Shared/NativeMethodsShared.cs(855,29): error IL1005: Microsoft.Build.Shared.NativeMethodsShared.SystemInformation.get: Error processing method 'Microsoft.Build.Shared.NativeMethodsShared.SystemInformationData.SystemInformationData()' in assembly 'Microsoft.Build.Utilities.Core.dll' [/__w/1/s/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj]
\##[error]/_/src/Shared/NativeMethodsShared.cs(855,29): error IL1005: (NETCORE_ENGINEERING_TELEMETRY=Build) Microsoft.Build.Shared.NativeMethodsShared.SystemInformation.get: Error processing method 'Microsoft.Build.Shared.NativeMethodsShared.SystemInformationData.SystemInformationData()' in assembly 'Microsoft.Build.Utilities.Core.dll'
  Mono.Linker.LinkerFatalErrorException: /_/src/Shared/NativeMethodsShared.cs(855,29): error IL1005: Microsoft.Build.Shared.NativeMethodsShared.SystemInformation.get: Error processing method 'Microsoft.Build.Shared.NativeMethodsShared.SystemInformationData.SystemInformationData()' in assembly 'Microsoft.Build.Utilities.Core.dll'
   ---> System.NotImplementedException: switch
     at Mono.Linker.Steps.UnreachableBlocksOptimizer.BodyReducer.IsConstantBranch(OpCode opCode, Int32 operand) in illink.dll:token 0x6000770+0x41
     at Mono.Linker.Steps.UnreachableBlocksOptimizer.BodyReducer.RemoveConditions() in illink.dll:token 0x6000768+0x22a
     at Mono.Linker.Steps.UnreachableBlocksOptimizer.BodyReducer.RewriteBody() in illink.dll:token 0x6000766+0xa
     at Mono.Linker.Steps.UnreachableBlocksOptimizer.ProcessStack() in illink.dll:token 0x60004e9+0x102
     at Mono.Linker.Steps.UnreachableBlocksOptimizer.ProcessMethod(MethodDefinition method) in illink.dll:token 0x60004e5+0x44
     at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method, DependencyInfo& reason, Scope& scope) in illink.dll:token 0x600040e+0x9b
     at Mono.Linker.Steps.MarkStep.ProcessQueue() in illink.dll:token 0x6000399+0x24
     --- End of inner exception stack trace ---
     at Mono.Linker.Steps.MarkStep.ProcessQueue() in illink.dll:token 0x6000399+0xaa
     at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue() in illink.dll:token 0x6000396+0xa
     at Mono.Linker.Steps.MarkStep.Process() in illink.dll:token 0x6000393+0x0
     at Mono.Linker.Steps.MarkStep.Process(LinkContext context) in illink.dll:token 0x600038a+0x41
     at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step) in illink.dll:token 0x6000264+0x0
     at Mono.Linker.Pipeline.Process(LinkContext context) in illink.dll:token 0x6000263+0xf
     at Mono.Linker.Driver.Run(ILogger customLogger) in illink.dll:token 0x60000fd+0x20
  Optimizing assemblies for size, which may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
/__w/1/s/.dotnet/sdk/6.0.100-preview.4.21255.9/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.ILLink.targets(80,5): error NETSDK1144: Optimizing assemblies for size failed. Optimization can be disabled by setting the PublishTrimmed property to false. [/__w/1/s/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj]
\##[error].dotnet/sdk/6.0.100-preview.4.21255.9/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.ILLink.targets(80,5): error NETSDK1144: (NETCORE_ENGINEERING_TELEMETRY=Build) Optimizing assemblies for size failed. Optimization can be disabled by setting the PublishTrimmed property to false.
```
---
 src/libraries/tests.proj | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index b1ca6c3a1ddba5..bed4f602e98b45 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -255,6 +255,8 @@
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(RunDisabledWasmTests)' != 'true'">
+    <ProjectExclusions Include="$(MSBuildThisFileDirectory)Microsoft.NETCore.Platforms\tests\Microsoft.NETCore.Platforms.Tests.csproj" />
+
     <!-- Mono-Browser ignores runtimeconfig.template.json (e.g. for this it has "System.Globalization.EnforceJapaneseEraYearRanges": true) -->
     <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Globalization.Calendars\tests\CalendarTestWithConfigSwitch\System.Globalization.CalendarsWithConfigSwitch.Tests.csproj" />
 

From 38e4fb83b57d8920487a01c35c9fa2ca606facc5 Mon Sep 17 00:00:00 2001
From: Ankit Jain <radical@gmail.com>
Date: Tue, 22 Jun 2021 17:30:52 -0400
Subject: [PATCH 11/11] [wasm] Disable System.IO.MemoryMappedFiles.Tests

Issue: https://github.com/dotnet/runtime/issues/54194
---
 src/libraries/tests.proj | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index bed4f602e98b45..5cad3c540880b1 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -278,6 +278,9 @@
   </ItemGroup>
 
   <ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(BuildAOTTestsOnHelix)' == 'true' and '$(RunDisabledWasmTests)' != 'true' and '$(RunAOTCompilation)' == 'true'">
+    <!-- Issue: https://github.com/dotnet/runtime/issues/54194 -->
+    <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.IO.MemoryMappedFiles/tests/System.IO.MemoryMappedFiles.Tests.csproj" />
+
     <!-- Issue: https://github.com/dotnet/runtime/issues/52393 -->
     <ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime/tests/System.Runtime.Tests.csproj" />
 
