Skip to content

Commit

Permalink
Make reading custom attributes in NativeLibrary avoidable (#80677)
Browse files Browse the repository at this point in the history
Contributes to #80165.

Unfortunately, the `NativeLibrary` APIs contain a pattern where one can skip providing a parameter to the API and then something expensive (custom attribute reading) will happen to compute the value. We have a `TryLoad` call in a hello world that does provide the value (in GlobalizationMode.cs). Make it possible to avoid the expensive thing internally.
  • Loading branch information
MichalStrehovsky committed Jan 16, 2023
1 parent 375ee0f commit bd84e67
Showing 1 changed file with 23 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,34 @@ namespace System.Runtime.InteropServices
{
public static partial class NativeLibrary
{
// Not a public API. We expose this so that it's possible to bypass the codepath that tries to read search path
// from custom attributes.
internal static bool TryLoad(string libraryName, Assembly assembly, DllImportSearchPath searchPath, out IntPtr handle)
{
handle = LoadLibraryByName(libraryName,
assembly,
searchPath,
throwOnError: false);
return handle != IntPtr.Zero;
}

internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError)
{
// First checks if a default dllImportSearchPathFlags was passed in, if so, use that value.
// Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute.
// If so, use that value.

int searchPathFlags;
bool searchAssemblyDirectory;
if (searchPath.HasValue)
{
searchPathFlags = (int)(searchPath.Value & ~DllImportSearchPath.AssemblyDirectory);
searchAssemblyDirectory = (searchPath.Value & DllImportSearchPath.AssemblyDirectory) != 0;
}
else
if (!searchPath.HasValue)
{
GetDllImportSearchPathFlags(assembly, out searchPathFlags, out searchAssemblyDirectory);
searchPath = GetDllImportSearchPath(assembly);
}
return LoadLibraryByName(libraryName, assembly, searchPath.Value, throwOnError);
}

internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath searchPath, bool throwOnError)
{
int searchPathFlags = (int)(searchPath & ~DllImportSearchPath.AssemblyDirectory);
bool searchAssemblyDirectory = (searchPath & DllImportSearchPath.AssemblyDirectory) != 0;

LoadLibErrorTracker errorTracker = default;
IntPtr ret = LoadBySearch(assembly, searchAssemblyDirectory, searchPathFlags, ref errorTracker, libraryName);
Expand All @@ -38,20 +49,17 @@ internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly,
return ret;
}

internal static void GetDllImportSearchPathFlags(Assembly callingAssembly, out int searchPathFlags, out bool searchAssemblyDirectory)
internal static DllImportSearchPath GetDllImportSearchPath(Assembly callingAssembly)
{
var searchPath = DllImportSearchPath.AssemblyDirectory;

foreach (CustomAttributeData cad in callingAssembly.CustomAttributes)
{
if (cad.AttributeType == typeof(DefaultDllImportSearchPathsAttribute))
{
searchPath = (DllImportSearchPath)cad.ConstructorArguments[0].Value!;
return (DllImportSearchPath)cad.ConstructorArguments[0].Value!;
}
}

searchPathFlags = (int)(searchPath & ~DllImportSearchPath.AssemblyDirectory);
searchAssemblyDirectory = (searchPath & DllImportSearchPath.AssemblyDirectory) != 0;
return DllImportSearchPath.AssemblyDirectory;
}

internal static IntPtr LoadBySearch(Assembly callingAssembly, bool searchAssemblyDirectory, int dllImportSearchPathFlags, ref LoadLibErrorTracker errorTracker, string libraryName)
Expand Down

0 comments on commit bd84e67

Please sign in to comment.