| File: ConfigurablePInvokePolicy.cs | Web Access |
| Project: ILCompiler_inbuild.csproj (ilc) |
// 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.IO; using System.Runtime.InteropServices; using Internal.IL; using Internal.IL.Stubs; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Interop; namespace ILCompiler { internal sealed class ConfigurablePInvokePolicy : PInvokeILEmitterConfiguration { private readonly TargetDetails _target; private readonly Dictionary<string, HashSet<string>> _directPInvokes; public ConfigurablePInvokePolicy(TargetDetails target, IReadOnlyList<string> directPInvokes, IReadOnlyList<string> directPInvokeLists) { _directPInvokes = new Dictionary<string, HashSet<string>>(target.IsWindows ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); // * is always a direct call _directPInvokes.Add("*", null); foreach (var file in directPInvokeLists) { foreach (var entry in File.ReadLines(file)) { AddDirectPInvoke(entry); } } foreach (var entry in directPInvokes) { AddDirectPInvoke(entry); } _target = target; } private void AddDirectPInvoke(string entry) { // Ignore comments if (entry.StartsWith('#')) return; entry = entry.Trim(); // Ignore empty entries if (string.IsNullOrEmpty(entry)) return; int separator = entry.IndexOf('!'); if (separator != -1) { string libraryName = entry.Substring(0, separator); string entrypointName = entry.Substring(separator + 1); if (_directPInvokes.TryGetValue(libraryName, out HashSet<string> entrypointSet)) { // All entrypoints from the library are direct if (entrypointSet == null) return; } else { _directPInvokes.Add(libraryName, entrypointSet = new HashSet<string>()); } entrypointSet.Add(entrypointName); } else { // All entrypoints from the library are direct _directPInvokes[entry] = null; } } private IEnumerable<string> EntryPointNameVariations(string name, PInvokeFlags flags) { if (_target.IsWindows && !flags.ExactSpelling) { // Mirror CharSet normalization from Marshaller.CreateMarshaller bool isAnsi = flags.CharSet switch { CharSet.Ansi => true, CharSet.Unicode => false, CharSet.Auto => false, _ => true }; if (isAnsi) { // For ANSI, look for the user-provided entry point name first. // If that does not exist, try the charset suffix. yield return name; yield return name + "A"; } else { // For Unicode, look for the entry point name with the charset suffix first. // The 'W' API takes precedence over the undecorated one. yield return name + "W"; yield return name; } } else { yield return name; } } public override LinkageMetadata GetLinkageMetadata(MethodDesc method) { var pInvokeMetadata = method.GetPInvokeMethodMetadata(); MethodDesc target = method is PInvokeTargetNativeMethod nativeMethod ? nativeMethod.Target : method; if (_target.IsWasm && target.HasCustomAttribute("System.Runtime.InteropServices", "WasmImportLinkageAttribute")) { Utf8String importName = pInvokeMetadata.Name is null ? new Utf8String(method.Name.AsSpan()) : new Utf8String(pInvokeMetadata.Name); return new WasmLinkageMetadata(importName, new Utf8String(pInvokeMetadata.Module)); } foreach (var moduleName in MarshalHelpers.GetPInvokeModuleNameVariations(_target, pInvokeMetadata.Module)) { if (_directPInvokes.TryGetValue(moduleName, out HashSet<string> entrypoints)) { string entryPointMetadataName = pInvokeMetadata.Name ?? method.GetName(); if (entrypoints == null) { return new LinkageMetadata(new Utf8String(entryPointMetadataName)); } foreach (var entryPointName in EntryPointNameVariations(entryPointMetadataName, pInvokeMetadata.Flags)) { if (entrypoints.Contains(entryPointName)) { return new LinkageMetadata(new Utf8String(entryPointName)); } } } } return null; } } }