Make reading custom attributes in NativeLibrary avoidable (#80677)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Mon, 16 Jan 2023 09:17:28 +0000 (18:17 +0900)
committerGitHub <noreply@github.com>
Mon, 16 Jan 2023 09:17:28 +0000 (18:17 +0900)
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.

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.NativeAot.cs

index 3708b25..d79088a 100644 (file)
@@ -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);
@@ -38,20 +49,17 @@ namespace System.Runtime.InteropServices
             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)