Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
11 changes: 8 additions & 3 deletions src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -961,13 +961,18 @@ elseif(CLR_CMAKE_TARGET_ARCH_WASM)
${ARCH_SOURCES_DIR}/browserprofiler.cpp
)
endif(CLR_CMAKE_TARGET_BROWSER)
if(CLR_CMAKE_TARGET_WASI)
set(WASM_THUNK_SUBDIR wasi)
else()
set(WASM_THUNK_SUBDIR browser)
endif()
set(VM_SOURCES_WKS_GEN
${ARCH_SOURCES_DIR}/callhelpers-interp-to-managed.cpp
${ARCH_SOURCES_DIR}/callhelpers-reverse.cpp
${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-interp-to-managed.cpp
${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-reverse.cpp
)
if (GEN_PINVOKE)
list(APPEND VM_SOURCES_WKS_GEN
${ARCH_SOURCES_DIR}/callhelpers-pinvoke.cpp
${ARCH_SOURCES_DIR}/${WASM_THUNK_SUBDIR}/callhelpers-pinvoke.cpp
)
endif(GEN_PINVOKE)
endif()
Expand Down
791 changes: 791 additions & 0 deletions src/coreclr/vm/wasm/wasi/callhelpers-interp-to-managed.cpp

Large diffs are not rendered by default.

444 changes: 444 additions & 0 deletions src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp

Large diffs are not rendered by default.

1,137 changes: 1,137 additions & 0 deletions src/coreclr/vm/wasm/wasi/callhelpers-reverse.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@
ReversePInvokeOutputPath="$(_WasmReversePInvokeTablePath)"
InterpToNativeOutputPath="$(_WasmInterpToNativeTablePath)"
CacheFilePath="$(_WasmM2NCachePath)"
TargetOS="browser"
IsLibraryMode="$(_IsLibraryMode)">
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</ManagedToNativeGenerator>
Expand Down
19 changes: 18 additions & 1 deletion src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public class ManagedToNativeGenerator : Task

public bool IsLibraryMode { get; set; }

public string TargetOS { get; set; } = "browser";

private static readonly string[] s_knownTargetOSes = new[] { "browser", "wasi" };

[Output]
public string[]? FileWrites { get; private set; }

Comment thread
lewing marked this conversation as resolved.
Expand All @@ -52,6 +56,19 @@ public override bool Execute()
return false;
}

if (string.IsNullOrWhiteSpace(TargetOS))
{
Log.LogError($"{nameof(ManagedToNativeGenerator)}.{nameof(TargetOS)} cannot be empty; expected one of: {string.Join(", ", s_knownTargetOSes)}");
return false;
}

TargetOS = TargetOS.Trim().ToLowerInvariant();
if (Array.IndexOf(s_knownTargetOSes, TargetOS) < 0)
{
Log.LogError($"{nameof(ManagedToNativeGenerator)}.{nameof(TargetOS)} '{TargetOS}' is not recognized; expected one of: {string.Join(", ", s_knownTargetOSes)}");
return false;
}

try
{
var logAdapter = new LogAdapter(Log);
Expand All @@ -69,7 +86,7 @@ private void ExecuteInternal(LogAdapter log)
{
Dictionary<string, string> _symbolNameFixups = new();
List<string> managedAssemblies = FilterOutUnmanagedBinaries(Assemblies);
var pinvoke = new PInvokeTableGenerator(FixupSymbolName, log, IsLibraryMode);
var pinvoke = new PInvokeTableGenerator(FixupSymbolName, log, IsLibraryMode, TargetOS);
var internalCallCollector = new InternalCallSignatureCollector(log);

var resolver = new PathAssemblyResolver(managedAssemblies);
Expand Down
120 changes: 89 additions & 31 deletions src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@ public int GetHashCode(PInvoke pinvoke)

internal sealed class PInvokeCollector {
private readonly Dictionary<Assembly, bool> _assemblyDisableRuntimeMarshallingAttributeCache = new();
private readonly Dictionary<Type, bool> _typeUnsupportedOnBrowserCache = new();
private readonly Dictionary<Type, bool> _typeUnsupportedOnPlatformCache = new();
private readonly Dictionary<Assembly, bool> _assemblyUnsupportedOnPlatformCache = new();
private readonly string _targetOS;
private LogAdapter Log { get; init; }

public PInvokeCollector(LogAdapter log)
public PInvokeCollector(LogAdapter log, string targetOS)
{
Log = log;
_targetOS = targetOS;
}

public void CollectPInvokes(List<PInvoke> pinvokes, List<PInvokeCallback> callbacks, HashSet<string> signatures, Type type)
Expand Down Expand Up @@ -104,6 +107,9 @@ void CollectPInvokesForMethod(MethodInfo method)
{
if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0)
{
if (IsUnsupportedOnPlatform(method))
return;

var dllimport = method.CustomAttributes.First(attr => attr.AttributeType.Name == "DllImportAttribute");
var wasmLinkage = method.CustomAttributes.Any(attr => attr.AttributeType.Name == "WasmImportLinkageAttribute");
var module = (string)dllimport.ConstructorArguments[0].Value!;
Expand All @@ -126,7 +132,7 @@ bool DoesMethodHaveCallbacks(MethodInfo method, LogAdapter log)
if (!MethodHasCallbackAttributes(method))
return false;

if (IsUnsupportedOnBrowser(method.DeclaringType))
if (IsUnsupportedOnPlatform(method))
return false;

if (TryIsMethodGetParametersUnsupported(method, out string? reason))
Expand Down Expand Up @@ -213,48 +219,100 @@ private bool HasAssemblyDisableRuntimeMarshallingAttribute(Assembly assembly)
return value;
}

private bool IsUnsupportedOnBrowser(Type? type)
private bool IsUnsupportedOnPlatform(MethodInfo method)
{
PlatformSupport methodResult = EvaluatePlatformAttributes(CustomAttributeData.GetCustomAttributes(method));
if (methodResult == PlatformSupport.Unsupported)
return true;
if (methodResult == PlatformSupport.Supported)
return false;

return IsUnsupportedOnPlatform(method.DeclaringType);
}

private bool IsUnsupportedOnPlatform(Type? type)
{
if (type is null)
return false;

if (!_typeUnsupportedOnBrowserCache.TryGetValue(type, out bool value))
if (_typeUnsupportedOnPlatformCache.TryGetValue(type, out bool cached))
return cached;

bool value;
PlatformSupport typeResult = EvaluatePlatformAttributes(CustomAttributeData.GetCustomAttributes(type));
if (typeResult == PlatformSupport.Unsupported)
{
value = true;
}
else if (typeResult == PlatformSupport.Supported)
{
value = false;
bool hasSupportedOSPlatform = false;
bool hasSupportedBrowser = false;
foreach (CustomAttributeData cattr in CustomAttributeData.GetCustomAttributes(type))
}
else if (type.DeclaringType is not null)
{
value = IsUnsupportedOnPlatform(type.DeclaringType);
}
else
{
value = IsAssemblyUnsupportedOnPlatform(type.Assembly);
}

_typeUnsupportedOnPlatformCache[type] = value;
return value;
}

private bool IsAssemblyUnsupportedOnPlatform(Assembly assembly)
{
if (!_assemblyUnsupportedOnPlatformCache.TryGetValue(assembly, out bool value))
{
PlatformSupport asmResult = EvaluatePlatformAttributes(assembly.GetCustomAttributesData());
value = asmResult == PlatformSupport.Unsupported;
_assemblyUnsupportedOnPlatformCache[assembly] = value;
}

return value;
}

private enum PlatformSupport
{
Unknown, // No platform attributes were observed at this scope
Supported, // Explicitly supported here (target appears in a SupportedOSPlatform list)
Unsupported, // Explicitly unsupported here (target matches UnsupportedOSPlatform, or
// SupportedOSPlatform is present and does not list the target)
}

private PlatformSupport EvaluatePlatformAttributes(IList<CustomAttributeData> attrs)
{
bool hasSupportedOSPlatform = false;
bool hasSupportedTarget = false;
foreach (CustomAttributeData cattr in attrs)
{
try
{
try
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.UnsupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0 &&
cattr.ConstructorArguments[0].Value?.ToString() == _targetOS)
{
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.UnsupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0 &&
cattr.ConstructorArguments[0].Value?.ToString() == "browser")
{
value = true;
break;
}
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.SupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0)
{
hasSupportedOSPlatform = true;
if (cattr.ConstructorArguments[0].Value?.ToString() == "browser")
hasSupportedBrowser = true;
}
return PlatformSupport.Unsupported;
}
catch
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.SupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0)
{
// Assembly not found, ignore
hasSupportedOSPlatform = true;
if (cattr.ConstructorArguments[0].Value?.ToString() == _targetOS)
hasSupportedTarget = true;
}
}

if (!value && hasSupportedOSPlatform && !hasSupportedBrowser)
value = true;

_typeUnsupportedOnBrowserCache[type] = value;
catch
{
// Assembly not found, ignore
}
}

return value;
if (hasSupportedOSPlatform)
return hasSupportedTarget ? PlatformSupport.Supported : PlatformSupport.Unsupported;

return PlatformSupport.Unknown;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ internal sealed class PInvokeTableGenerator
private readonly PInvokeCollector _pinvokeCollector;
private readonly bool _isLibraryMode;

public PInvokeTableGenerator(Func<string, string> fixupSymbolName, LogAdapter log, bool isLibraryMode = false)
public PInvokeTableGenerator(Func<string, string> fixupSymbolName, LogAdapter log, bool isLibraryMode, string targetOS)
{
Log = log;
_fixupSymbolName = fixupSymbolName;
_pinvokeCollector = new(log);
_pinvokeCollector = new(log, targetOS);
_isLibraryMode = isLibraryMode;
}

Expand Down
Loading