Example #1
0
        /// <summary>
        /// Applies a temporary workaround for https://github.com/mono/mono/issues/19824
        /// </summary>
        private string?TransformAOTProfile()
        {
            var profilePath = AotProfile?.FirstOrDefault()?.GetMetadata("FullPath");

            if (profilePath != null)
            {
                var reader = new Mono.Profiler.Aot.ProfileReader();
                Mono.Profiler.Aot.ProfileData profile;
                using (FileStream stream = File.OpenRead(profilePath))
                {
                    profile = reader.ReadAllData(stream);
                }

                var excludedMethodsList = AOTProfileExcludedMethods
                                          .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                                          .ToList();

                var excludedAssemblies = MixedModeExcludedAssembly?.ToDictionary(i => i.ItemSpec, i => i.ItemSpec)
                                         ?? new Dictionary <string, string>();

                // LoadIntoBufferAsync uses exception filtering
                excludedMethodsList.AddRange(DefaultAOTProfileExcludedMethods);

                TryDumpProfileMethods(profile, "AOTProfileDump.Original.txt");

                var excludedMethods = excludedMethodsList.Select(e => new Regex(e)).ToList();

                var q = from m in profile.Methods
                        where !excludedMethods.Any(e => e.Match(m.Type.FullName + '.' + m.Name).Success) &&
                        !excludedAssemblies.ContainsKey(m.Type.Module.Name)
                        select m;

                profile.Methods = q.ToArray();

                TryDumpProfileMethods(profile, "AOTProfileDump.Filtered.txt");

                var writer = new Mono.Profiler.Aot.ProfileWriter();

                var outputFile = Path.Combine(IntermediateOutputPath, "aot-filtered.profile");
                using (var outStream = File.Create(outputFile))
                {
                    writer.WriteAllData(outStream, profile);
                }

                return(outputFile);
            }

            return(profilePath);
        }
Example #2
0
        private void RunPackager()
        {
            BuildReferencedAssembliesList();

            var workAotPath = Path.Combine(IntermediateOutputPath, "workAot");

            if (Directory.Exists(workAotPath))
            {
                Directory.Delete(workAotPath, true);
            }

            Directory.CreateDirectory(workAotPath);

            var    referencePathsParameter = string.Join(" ", _referencedAssemblies.Select(Path.GetDirectoryName).Distinct().Select(r => $"--search-path=\"{r}\""));
            var    debugOption             = RuntimeDebuggerEnabled ? "--debug" : "";
            string packagerBinPath         = string.IsNullOrWhiteSpace(PackagerBinPath) ? Path.Combine(MonoWasmSDKPath, "packager.exe") : PackagerBinPath;

            //
            // Run the packager to create the original layout. The AOT will optionally run over this pass.
            //
            int packagerResults = RunProcess(packagerBinPath, $"{debugOption} {referencePathsParameter} \"{Path.GetFullPath(Assembly)}\"", _distPath);

            if (packagerResults != 0)
            {
                throw new Exception("Failed to generate wasm layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
            }

            var runtimeExecutionMode = ParseRuntimeExecutionMode();

            if (runtimeExecutionMode == RuntimeExecutionMode.FullAOT || runtimeExecutionMode == RuntimeExecutionMode.InterpreterAndAOT)
            {
                var emsdkPath = Environment.GetEnvironmentVariable("EMSDK");
                if (string.IsNullOrEmpty(emsdkPath))
                {
                    throw new InvalidOperationException($"The EMSDK environment variable must be defined. See http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#installation-instructions");
                }

                var mixedModeExcluded = MixedModeExcludedAssembly
                                        ?.Select(a => a.ItemSpec)
                                        .ToArray() ?? Array.Empty <string>();

                var mixedModeAotAssembliesParam = mixedModeExcluded.Any() ? "--skip-aot-assemblies=" + string.Join(",", mixedModeExcluded) : "";

                var aotMode    = runtimeExecutionMode == RuntimeExecutionMode.InterpreterAndAOT ? $"--aot-interp {mixedModeAotAssembliesParam}" : "--aot";
                var aotOptions = $"{aotMode} --link-mode=all --emscripten-sdkdir=\"{emsdkPath}\" --builddir=\"{workAotPath}\"";

                var aotPackagerResult = RunProcess(packagerBinPath, $"{debugOption} {aotOptions} {referencePathsParameter} \"{Path.GetFullPath(Assembly)}\"", _distPath);

                if (aotPackagerResult != 0)
                {
                    throw new Exception("Failed to generate wasm layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
                }

                var ninjaResult = RunProcess("ninja", "", workAotPath);

                if (ninjaResult != 0)
                {
                    throw new Exception("Failed to generate AOT layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
                }
            }
            else
            {
                //
                // Run the IL Linker on the interpreter based output, as the packager does not yet do it.
                //
                if (
                    MonoILLinker &&
                    !string.IsNullOrEmpty(CustomLinkerPath)
                    )
                {
                    string linkerInput = Path.Combine(IntermediateOutputPath, "linker-in");
                    if (Directory.Exists(linkerInput))
                    {
                        Directory.Delete(linkerInput, true);
                    }

                    Directory.Move(_managedPath, linkerInput);
                    Directory.CreateDirectory(_managedPath);

                    var assemblyPath = Path.Combine(linkerInput, Path.GetFileName(Assembly));
                    var bindingsPath = Path.Combine(linkerInput, "WebAssembly.Bindings.dll");

                    var linkerPath = Path.Combine(Path.Combine(CustomLinkerPath, "linker"), "monolinker.exe");

                    int linkerResults = RunProcess(
                        linkerPath,
                        $"-out \"{_managedPath}\" --verbose -b true -l none --exclude-feature com --exclude-feature remoting -a \"{assemblyPath}\" -a \"{bindingsPath}\" -c link -p copy \"WebAssembly.Bindings\" -d \"{_managedPath}\"",
                        _managedPath
                        );

                    if (linkerResults != 0)
                    {
                        throw new Exception("Failed to execute the linker");
                    }

                    //
                    // The linker removes files after the mono-config.js file has been
                    // generated by the packager. Synchronize the list with the actual list.
                    //
                    var deletedFiles = Directory
                                       .GetFiles(linkerInput)
                                       .Select(Path.GetFileName)
                                       .Except(Directory
                                               .GetFiles(_managedPath)
                                               .Select(Path.GetFileName)
                                               );

                    string monoConfigFilePath = Path.Combine(_distPath, "mono-config.js");
                    var    monoConfig         = File.ReadAllText(monoConfigFilePath);

                    foreach (var deletedFile in deletedFiles)
                    {
                        Log.LogMessage($"Removing linker deleted file [{deletedFile}] from mono-config.js");
                        monoConfig = monoConfig
                                     .Replace($"\"{deletedFile}\",", "")
                                     .Replace($"\"{deletedFile}\"", "");
                    }

                    File.WriteAllText(monoConfigFilePath, monoConfig);
                }
            }
        }
Example #3
0
        private void RunPackager()
        {
            BuildReferencedAssembliesList();

            var workAotPath = Path.Combine(IntermediateOutputPath, "workAot");

            if (Directory.Exists(workAotPath))
            {
                Directory.Delete(workAotPath, true);
            }

            Directory.CreateDirectory(workAotPath);

            var    referencePathsParameter = string.Join(" ", _referencedAssemblies.Select(Path.GetDirectoryName).Distinct().Select(r => $"--search-path=\"{r}\""));
            var    debugOption             = RuntimeDebuggerEnabled ? "--debug" : "";
            string packagerBinPath         = string.IsNullOrWhiteSpace(PackagerBinPath) ? Path.Combine(MonoWasmSDKPath, "packager.exe") : PackagerBinPath;

            //
            // Run the packager to create the original layout. The AOT will optionally run over this pass.
            //
            int packagerResults = RunProcess(packagerBinPath, $"--runtime-config={RuntimeConfiguration} --zlib {debugOption} {referencePathsParameter} \"{Path.GetFullPath(Assembly)}\"", _distPath);

            if (packagerResults != 0)
            {
                throw new Exception("Failed to generate wasm layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
            }

            if (IsRuntimeAOT())
            {
                var emsdkPath = ValidateEmscripten();

                var mixedModeExcluded = MixedModeExcludedAssembly
                                        ?.Select(a => a.ItemSpec)
                                        .ToArray() ?? Array.Empty <string>();

                var mixedModeAotAssembliesParam = mixedModeExcluded.Any() ? "--skip-aot-assemblies=" + string.Join(",", mixedModeExcluded) : "";

                var dynamicLibraries     = GetDynamicLibrariesParams();
                var dynamicLibraryParams = dynamicLibraries.Any() ? "--pinvoke-libs=" + string.Join(",", dynamicLibraries) : "";

                var bitcodeFiles       = GetBitcodeFilesParams();
                var bitcodeFilesParams = dynamicLibraries.Any() ? string.Join(" ", bitcodeFiles.Select(f => $"\"--bc={f}\"")) : "";

                var aotMode    = _runtimeExecutionMode == RuntimeExecutionMode.InterpreterAndAOT ? $"--aot-interp {mixedModeAotAssembliesParam}" : "--aot";
                var aotOptions = $"{aotMode} --link-mode=all {dynamicLibraryParams} {bitcodeFilesParams} --emscripten-sdkdir=\"{emsdkPath}\" --builddir=\"{workAotPath}\"";

                var aotPackagerResult = RunProcess(packagerBinPath, $"{debugOption} --zlib --runtime-config={RuntimeConfiguration} {aotOptions} {referencePathsParameter} \"{Path.GetFullPath(Assembly)}\"", _distPath);

                if (aotPackagerResult != 0)
                {
                    throw new Exception("Failed to generate wasm layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
                }

                var ninjaResult = RunProcess("ninja", "", workAotPath);

                if (ninjaResult != 0)
                {
                    throw new Exception("Failed to generate AOT layout (More details are available in diagnostics mode or using the MSBuild /bl switch)");
                }
            }
            else
            {
                //
                // Run the IL Linker on the interpreter based output, as the packager does not yet do it.
                //
                if (
                    MonoILLinker &&
                    !string.IsNullOrEmpty(CustomLinkerPath)
                    )
                {
                    string linkerInput = Path.Combine(IntermediateOutputPath, "linker-in");
                    if (Directory.Exists(linkerInput))
                    {
                        Directory.Delete(linkerInput, true);
                    }

                    Directory.Move(_managedPath, linkerInput);
                    Directory.CreateDirectory(_managedPath);

                    var assemblyPath = Path.Combine(linkerInput, Path.GetFileName(Assembly));

                    var frameworkBindings = new[] {
                        "WebAssembly.Bindings.dll",
                        "WebAssembly.Net.Http.dll",
                        "WebAssembly.Net.WebSockets.dll",
                    };

                    var bindingsPath = string.Join(" ", frameworkBindings.Select(a => $"-a \"{Path.Combine(linkerInput, a)}\""));

                    var linkerPath = Path.Combine(Path.Combine(CustomLinkerPath, "linker"), "monolinker.exe");

                    int linkerResults = RunProcess(
                        linkerPath,
                        $"-out \"{_managedPath}\" --verbose -b true -l none --exclude-feature com --exclude-feature remoting -a \"{assemblyPath}\" {bindingsPath} -c link -p copy \"WebAssembly.Bindings\" -d \"{_managedPath}\"",
                        _managedPath
                        );

                    if (linkerResults != 0)
                    {
                        throw new Exception("Failed to execute the linker");
                    }

                    //
                    // The linker removes files after the mono-config.js file has been
                    // generated by the packager. Synchronize the list with the actual list.
                    //
                    var deletedFiles = Directory
                                       .GetFiles(linkerInput)
                                       .Select(Path.GetFileName)
                                       .Except(Directory
                                               .GetFiles(_managedPath)
                                               .Select(Path.GetFileName)
                                               );

                    string monoConfigFilePath = Path.Combine(_distPath, "mono-config.js");
                    var    monoConfig         = File.ReadAllText(monoConfigFilePath);

                    foreach (var deletedFile in deletedFiles)
                    {
                        Log.LogMessage($"Removing linker deleted file [{deletedFile}] from mono-config.js");
                        monoConfig = monoConfig
                                     .Replace($"\"{deletedFile}\",", "")
                                     .Replace($"\"{deletedFile}\"", "");
                    }

                    File.WriteAllText(monoConfigFilePath, monoConfig);
                }
            }
        }