Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/mono/wasm/host/CommonConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal sealed class CommonConfiguration
public WasmHost Host { get; init; }
public HostConfig HostConfig { get; init; }
public WasmHostProperties HostProperties { get; init; }
public IEnumerable<string> HostArguments { get; init; }

private string? hostArg;
private string? _runtimeConfigPath;
Expand All @@ -30,11 +31,13 @@ internal sealed class CommonConfiguration

private CommonConfiguration(string[] args)
{
List<string> hostArgsList = new();
var options = new OptionSet
{
{ "debug|d", "Start debug server", _ => Debugging = true },
{ "host|h=", "Host config name", v => hostArg = v },
{ "runtime-config|r=", "runtimeconfig.json path for the app", v => _runtimeConfigPath = v }
{ "runtime-config|r=", "runtimeconfig.json path for the app", v => _runtimeConfigPath = v },
{ "extra-host-arg=", "Extra argument to be passed to the host", hostArgsList.Add },
};

RemainingArgs = options.Parse(args);
Expand Down Expand Up @@ -95,6 +98,9 @@ private CommonConfiguration(string[] args)
if (!Enum.TryParse(HostConfig.HostString, ignoreCase: true, out WasmHost wasmHost))
throw new CommandLineException($"Unknown host {HostConfig.HostString} in config named {HostConfig.Name}");
Host = wasmHost;

hostArgsList.AddRange(HostConfig.HostArguments);
HostArguments = hostArgsList;
}

public ProxyOptions ToProxyOptions()
Expand Down
5 changes: 2 additions & 3 deletions src/mono/wasm/host/JSEngineHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public static async Task<int> InvokeAsync(CommonConfiguration commonArgs,

private async Task<int> RunAsync()
{
string[] engineArgs = Array.Empty<string>();

string engineBinary = _args.Host switch
{
WasmHost.V8 => "v8",
Expand Down Expand Up @@ -79,9 +77,10 @@ private async Task<int> RunAsync()
args.Add("--expose_wasm");
}

args.AddRange(_args.CommonConfig.HostArguments);

args.Add(_args.JSPath!);

args.AddRange(engineArgs);
if (_args.Host is WasmHost.V8 or WasmHost.JavaScriptCore)
{
// v8/jsc want arguments to the script separated by "--", others don't
Expand Down
2 changes: 2 additions & 0 deletions src/mono/wasm/host/RuntimeConfigJson.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand Down Expand Up @@ -32,6 +33,7 @@ internal sealed record WasmHostProperties(

internal sealed record HostConfig(string? Name, [property: JsonPropertyName("host")] string? HostString)
{
[property: JsonPropertyName("host-args")] public string[] HostArguments { get; set; } = Array.Empty<string>();
// using an explicit property because the deserializer doesn't like
// extension data in the record constructor
[property: JsonExtensionData] public Dictionary<string, JsonElement>? Properties { get; set; }
Expand Down
8 changes: 6 additions & 2 deletions src/tasks/WasmAppBuilder/IcallTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@ public IEnumerable<string> Generate(string? runtimeIcallTableFile, string[] asse

var resolver = new PathAssemblyResolver(assemblies);
using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib");
foreach (var aname in assemblies)
foreach (var asmPath in assemblies)
{
var a = mlc.LoadFromAssemblyPath(aname);
if (!File.Exists(asmPath))
throw new LogAsErrorException($"Cannot find assembly {asmPath}");

Log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for icalls");
var a = mlc.LoadFromAssemblyPath(asmPath);
foreach (var type in a.GetTypes())
ProcessType(type);
}
Expand Down
50 changes: 47 additions & 3 deletions src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
// 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.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class ManagedToNativeGenerator : Task
{
[Required]
public string[]? Assemblies { get; set; }
public string[] Assemblies { get; set; } = Array.Empty<string>();

public string? RuntimeIcallTableFile { get; set; }

Expand Down Expand Up @@ -62,12 +65,14 @@ public override bool Execute()

private void ExecuteInternal()
{
string[] managedAssemblies = FilterOutUnmanagedBinaries(Assemblies);

var pinvoke = new PInvokeTableGenerator(FixupSymbolName, Log);
var icall = new IcallTableGenerator(FixupSymbolName, Log);

IEnumerable<string> cookies = Enumerable.Concat(
pinvoke.Generate(PInvokeModules, Assemblies!, PInvokeOutputPath!),
icall.Generate(RuntimeIcallTableFile, Assemblies!, IcallOutputPath)
pinvoke.Generate(PInvokeModules, managedAssemblies, PInvokeOutputPath!),
icall.Generate(RuntimeIcallTableFile, managedAssemblies, IcallOutputPath)
);

var m2n = new InterpToNativeGenerator(Log);
Expand Down Expand Up @@ -110,4 +115,43 @@ public string FixupSymbolName(string name)
_symbolNameFixups[name] = fixedName;
return fixedName;
}

private string[] FilterOutUnmanagedBinaries(string[] assemblies)
{
List<string> managedAssemblies = new(assemblies.Length);
foreach (string asmPath in Assemblies)
{
if (!File.Exists(asmPath))
throw new LogAsErrorException($"Cannot find assembly {asmPath}");

try
{
if (!IsManagedAssembly(asmPath))
{
Log.LogMessage(MessageImportance.Low, $"Skipping unmanaged {asmPath}.");
continue;
}
}
catch (Exception ex)
{
Log.LogMessage(MessageImportance.Low, $"Failed to read assembly {asmPath}: {ex}");
throw new LogAsErrorException($"Failed to read assembly {asmPath}: {ex.Message}");
}

managedAssemblies.Add(asmPath);
}

return managedAssemblies.ToArray();
}

private static bool IsManagedAssembly(string filePath)
{
if (!File.Exists(filePath))
return false;

using FileStream fileStream = File.OpenRead(filePath);
using PEReader reader = new(fileStream, PEStreamOptions.Default);
return reader.HasMetadata;
}

}
8 changes: 6 additions & 2 deletions src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ public IEnumerable<string> Generate(string[] pinvokeModules, string[] assemblies

var resolver = new PathAssemblyResolver(assemblies);
using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib");
foreach (var aname in assemblies)
foreach (var asmPath in assemblies)
{
var a = mlc.LoadFromAssemblyPath(aname);
if (!File.Exists(asmPath))
throw new LogAsErrorException($"Cannot find assembly {asmPath}");

Log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for pinvokes");
var a = mlc.LoadFromAssemblyPath(asmPath);
foreach (var type in a.GetTypes())
CollectPInvokes(pinvokes, callbacks, signatures, type);
}
Expand Down