diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index a37abf7a0c116..45ab475cb90a6 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -215,7 +215,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -334,4 +346,4 @@
-
+
\ No newline at end of file
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
index c95e1630a04a1..939b0fe26afac 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/MdImport.cs
@@ -312,6 +312,12 @@ internal MetadataImport(RuntimeModule module)
// since the instance can be replaced during HotReload and EnC scenarios.
m_metadataImport2 = GetMetadataImport(module);
}
+
+ internal MetadataImport(IntPtr pIMetaDataAssemblyImport2)
+ {
+ ArgumentNullException.ThrowIfNull(pIMetaDataAssemblyImport2);
+ m_metadataImport2 = pIMetaDataAssemblyImport2;
+ }
#endregion
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MetadataImport_Enum")]
@@ -610,6 +616,38 @@ public bool IsValidToken(int token)
{
return IsValidToken(m_metadataImport2, token);
}
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern int GetAssemblyFromScope(IntPtr scope, out uint tkAssembly);
+ public uint GetAssemblyFromScope()
+ {
+ ThrowBadImageExceptionForHR(GetAssemblyFromScope(m_metadataImport2, out uint tkAssembly));
+ return tkAssembly;
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern unsafe int GetAssemblyProps(
+ IntPtr scope,
+ uint mda,
+ out byte* ppbPublicKey,
+ out uint pcbPublicKey,
+ out uint pulHashAlgId,
+ void** pszName,
+ void* pMetadata,
+ out uint pdwAsselblyFlags);
+ public unsafe void GetAssemblyProps(
+ uint assemblyToken,
+ out byte* publicKey,
+ out uint publicKeyLength,
+ out uint hashAlgId,
+ out string assemblyName,
+ void* pMetadata,
+ out uint asselblyFlags)
+ {
+ void* _name;
+ ThrowBadImageExceptionForHR(GetAssemblyProps(m_metadataImport2, assemblyToken, out publicKey, out publicKeyLength, out hashAlgId, &_name, pMetadata, out asselblyFlags));
+ assemblyName = new MdUtf8String(_name).ToString();
+ }
#endregion
private static void ThrowBadImageExceptionForHR(int hr)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/ApplicationContext.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/ApplicationContext.cs
new file mode 100644
index 0000000000000..ecb621eeeae72
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/ApplicationContext.cs
@@ -0,0 +1,301 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+
+namespace System.Runtime.Loader
+{
+ internal sealed class TPAEntry
+ {
+ public string? ILFileName;
+ public string? NIFileName;
+ }
+
+ internal sealed class FailureCacheKey : IEquatable
+ {
+ public readonly string SimpleName;
+ public readonly AssemblyVersion AssemblyVersion;
+
+ public FailureCacheKey(string simpleName, AssemblyVersion AssemblyVersion)
+ {
+ SimpleName = simpleName;
+ this.AssemblyVersion = AssemblyVersion;
+ }
+
+ public override bool Equals(object? obj) => obj is FailureCacheKey other && Equals(other);
+
+ public bool Equals(FailureCacheKey? other) => other != null && SimpleName == other.SimpleName && AssemblyVersion.Equals(other.AssemblyVersion);
+
+ public override int GetHashCode() => HashCode.Combine(SimpleName, AssemblyVersion.Major, AssemblyVersion.Minor, AssemblyVersion.Build, AssemblyVersion.Revision);
+ }
+
+ internal sealed class ApplicationContext
+ {
+ private volatile int _version;
+
+ public int Version => _version;
+
+ public Dictionary ExecutionContext { get; } = new Dictionary();
+
+ public Dictionary FailureCache { get; } = new Dictionary();
+
+ public object ContextCriticalSection { get; } = new object();
+
+ public List PlatformResourceRoots { get; } = new List();
+
+ public List AppPaths { get; } = new List();
+
+ public Dictionary? TrustedPlatformAssemblyMap { get; private set; }
+
+ public void IncrementVersion() => Interlocked.Increment(ref _version);
+
+ private static bool GetNextPath(string paths, ref int startPos, out string outPath)
+ {
+ bool wrappedWithQuotes = false;
+
+ // Skip any leading spaces or path separators
+ while (startPos < paths.Length && paths[startPos] is ' ' or PathInternal.PathSeparator)
+ startPos++;
+
+ if (startPos == paths.Length)
+ {
+ // No more paths in the string and we just skipped over some white space
+ outPath = string.Empty;
+ return false;
+ }
+
+ // Support paths being wrapped with quotations
+ while (startPos < paths.Length && paths[startPos] == '\"')
+ {
+ startPos++;
+ wrappedWithQuotes = true;
+ }
+
+ int iEnd = startPos; // Where current path ends
+ int iNext; // Where next path starts
+
+ static int IndexOfInRange(ReadOnlySpan str, int start, char ch)
+ {
+ int index = str[start..].IndexOf(ch);
+ return index >= 0 ? index + start : index;
+ }
+
+ if (wrappedWithQuotes)
+ {
+ iEnd = IndexOfInRange(paths, iEnd, '\"');
+ if (iEnd != -1)
+ {
+ // Find where the next path starts - there should be a path separator right after the closing quotation mark
+ iNext = IndexOfInRange(paths, iEnd, PathInternal.PathSeparator);
+ if (iNext != -1)
+ {
+ iNext++;
+ }
+ else
+ {
+ iNext = paths.Length;
+ }
+ }
+ else
+ {
+ // There was no terminating quotation mark - that's bad
+ throw new ArgumentException(nameof(paths));
+ }
+ }
+ else if ((iEnd = IndexOfInRange(paths, iEnd, PathInternal.PathSeparator)) != -1)
+ {
+ iNext = iEnd + 1;
+ }
+ else
+ {
+ iNext = iEnd = paths.Length;
+ }
+
+ // Skip any trailing spaces
+ while (paths[iEnd - 1] == ' ')
+ {
+ iEnd--;
+ }
+
+ Debug.Assert(startPos < iEnd);
+
+ outPath = paths[startPos..iEnd];
+ startPos = iNext;
+ return true;
+ }
+
+ private static bool GetNextTPAPath(string paths, ref int startPos, bool dllOnly, out string outPath, out string simpleName, out bool isNativeImage)
+ {
+ isNativeImage = false;
+
+ while (true)
+ {
+ if (!GetNextPath(paths, ref startPos, out outPath))
+ {
+ simpleName = string.Empty;
+ return false;
+ }
+
+ if (!Path.IsPathFullyQualified(outPath))
+ {
+ throw new ArgumentException(nameof(paths));
+ }
+
+ // Find the beginning of the simple name
+ int iSimpleNameStart = outPath.LastIndexOf(PathInternal.DirectorySeparatorChar);
+ if (iSimpleNameStart == -1)
+ {
+ iSimpleNameStart = 0;
+ }
+ else
+ {
+ // Advance past the directory separator to the first character of the file name
+ iSimpleNameStart++;
+ }
+
+ if (iSimpleNameStart == outPath.Length)
+ {
+ throw new ArgumentException(nameof(paths));
+ }
+
+ if (dllOnly && (outPath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)
+ || outPath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase)))
+ {
+ // Skip exe files when the caller requested only dlls
+ continue;
+ }
+
+ if (outPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase)
+ || outPath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase))
+ {
+ simpleName = outPath[iSimpleNameStart..^7];
+ isNativeImage = true;
+ }
+ else if (outPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)
+ || outPath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
+ {
+ simpleName = outPath[iSimpleNameStart..^4];
+ }
+ else
+ {
+ // Invalid filename
+ throw new ArgumentException(nameof(paths));
+ }
+
+ return true; ;
+ }
+ }
+
+ public void SetupBindingPaths(string trustedPlatformAssemblies, string platformResourceRoots, string appPaths, bool acquireLock)
+ {
+ if (acquireLock)
+ {
+ lock (ContextCriticalSection)
+ {
+ Core(trustedPlatformAssemblies, platformResourceRoots, appPaths);
+ }
+ }
+ else
+ {
+ Core(trustedPlatformAssemblies, platformResourceRoots, appPaths);
+ }
+
+ void Core(string trustedPlatformAssemblies, string platformResourceRoots, string appPaths)
+ {
+ if (TrustedPlatformAssemblyMap != null)
+ {
+ return;
+ }
+
+ //
+ // Parse TrustedPlatformAssemblies
+ //
+
+ TrustedPlatformAssemblyMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ for (int i = 0; i < trustedPlatformAssemblies.Length;)
+ {
+ if (!GetNextTPAPath(trustedPlatformAssemblies, ref i, dllOnly: false, out string fileName, out string simpleName, out bool isNativeImage))
+ {
+ break;
+ }
+
+ if (TrustedPlatformAssemblyMap.TryGetValue(simpleName, out TPAEntry? existingEntry))
+ {
+ //
+ // We want to store only the first entry matching a simple name we encounter.
+ // The exception is if we first store an IL reference and later in the string
+ // we encounter a native image. Since we don't touch IL in the presence of
+ // native images, we replace the IL entry with the NI.
+ //
+ if ((existingEntry.ILFileName != null && !isNativeImage) ||
+ (existingEntry.NIFileName != null && isNativeImage))
+ {
+ continue;
+ }
+ }
+
+ if (isNativeImage)
+ {
+ existingEntry ??= new TPAEntry();
+ existingEntry.NIFileName = fileName;
+ }
+ else
+ {
+ existingEntry ??= new TPAEntry();
+ existingEntry.ILFileName = fileName;
+ }
+
+ TrustedPlatformAssemblyMap[simpleName] = existingEntry;
+ }
+
+ //
+ // Parse PlatformResourceRoots
+ //
+
+ for (int i = 0; i < platformResourceRoots.Length;)
+ {
+ if (!GetNextPath(platformResourceRoots, ref i, out string pathName))
+ {
+ break;
+ }
+
+ if (!Path.IsPathFullyQualified(pathName))
+ {
+ throw new ArgumentException(nameof(pathName));
+ }
+
+ PlatformResourceRoots.Add(pathName);
+ }
+
+ //
+ // Parse AppPaths
+ //
+
+ for (int i = 0; i < appPaths.Length;)
+ {
+ if (!GetNextPath(appPaths, ref i, out string pathName))
+ {
+ break;
+ }
+
+
+ if (!Path.IsPathFullyQualified(pathName))
+ {
+ throw new ArgumentException(nameof(pathName));
+ }
+
+ AppPaths.Add(pathName);
+ }
+ }
+ }
+
+ public void AddToFailureCache(BinderAssemblyName assemblyName, int hresult)
+ {
+ FailureCache.Add(new FailureCacheKey(assemblyName.SimpleName, assemblyName.Version), hresult);
+ IncrementVersion();
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Assembly.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Assembly.cs
new file mode 100644
index 0000000000000..87036f58150f7
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Assembly.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.Loader
+{
+ // BINDER_SPACE::Assembly represents a result of binding to an actual assembly (PEImage)
+ // It is basically a tuple of 1) physical assembly and 2) binder which created/owns this binding
+ // We also store whether it was bound using TPA list
+ internal sealed class BinderAssembly
+ {
+ // fields used by VM
+#pragma warning disable CA1823, 414, 169
+ private BinderAssemblyName m_assemblyName;
+
+ // The assembly object is rooted by native object.
+ // Reference native ALC to allow managed ALC object to be collected.
+ private IntPtr m_binder;
+ private IntPtr m_peImage;
+ private IntPtr m_pDomainAssembly;
+ private bool m_isInTPA;
+ private bool m_isCoreLib;
+#pragma warning restore CA1823, 414, 169
+
+ public IntPtr Binder
+ {
+ get => m_binder;
+ set => m_binder = value;
+ }
+
+ public BinderAssemblyName AssemblyName => m_assemblyName;
+
+ public IntPtr PEImage => m_peImage;
+
+ public bool IsInTPA => m_isInTPA;
+
+ public BinderAssembly(nint pPEImage, bool isInTPA)
+ {
+ // Get assembly name def from meta data import and store it for later refs access
+ m_assemblyName = new BinderAssemblyName(pPEImage)
+ {
+ IsDefinition = true
+ };
+
+ m_isCoreLib = AssemblyName.IsCoreLib;
+
+ // validate architecture
+ if (!AssemblyBinderCommon.IsValidArchitecture(AssemblyName.ProcessorArchitecture))
+ {
+ // Assembly image can't be executed on this platform
+ throw new BadImageFormatException();
+ }
+
+ m_isInTPA = isInTPA;
+ m_peImage = pPEImage;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyIdentity.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyIdentity.cs
new file mode 100644
index 0000000000000..b344db93d25a7
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyIdentity.cs
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+
+namespace System.Runtime.Loader
+{
+ internal enum AssemblyIdentityFlags
+ {
+ IDENTITY_FLAG_EMPTY = 0x000,
+ IDENTITY_FLAG_SIMPLE_NAME = 0x001,
+ IDENTITY_FLAG_VERSION = 0x002,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN = 0x004,
+ IDENTITY_FLAG_PUBLIC_KEY = 0x008,
+ IDENTITY_FLAG_CULTURE = 0x010,
+ IDENTITY_FLAG_PROCESSOR_ARCHITECTURE = 0x040,
+ IDENTITY_FLAG_RETARGETABLE = 0x080,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL = 0x100,
+ IDENTITY_FLAG_CONTENT_TYPE = 0x800,
+ IDENTITY_FLAG_FULL_NAME = IDENTITY_FLAG_SIMPLE_NAME | IDENTITY_FLAG_VERSION
+ }
+
+ internal enum PEKind : uint
+ {
+ None = 0x00000000,
+ MSIL = 0x00000001,
+ I386 = 0x00000002,
+ IA64 = 0x00000003,
+ AMD64 = 0x00000004,
+ ARM = 0x00000005,
+ ARM64 = 0x00000006,
+ Invalid = 0xffffffff,
+ }
+
+ internal class AssemblyIdentity
+ {
+ public string SimpleName = string.Empty;
+ public AssemblyVersion Version = new AssemblyVersion();
+ public string CultureOrLanguage = string.Empty;
+ public byte[] PublicKeyOrTokenBLOB = Array.Empty();
+ public PEKind ProcessorArchitecture;
+ public AssemblyContentType ContentType;
+ public AssemblyIdentityFlags IdentityFlags = AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE | AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL;
+
+ // See https://docs.microsoft.com/dotnet/framework/reflection-and-codedom/specifying-fully-qualified-type-names#specifying-assembly-names
+ public const string NeutralCulture = "neutral";
+
+ public string NormalizedCulture => string.IsNullOrEmpty(CultureOrLanguage) ? NeutralCulture : CultureOrLanguage;
+
+ public bool IsRetargetable => (IdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE) != 0;
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Binder.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Binder.cs
new file mode 100644
index 0000000000000..b7cad3811e952
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Binder.cs
@@ -0,0 +1,204 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Runtime.Loader
+{
+ // System.Reflection.TypeLoading.AssemblyNameData
+ internal readonly unsafe struct AssemblyNameData
+ {
+ public readonly void* Name;
+ public readonly void* Culture;
+
+ public readonly byte* PublicKeyOrToken;
+ public readonly int PublicKeyOrTokenLength;
+
+ public readonly int MajorVersion;
+ public readonly int MinorVersion;
+ public readonly int BuildNumber;
+ public readonly int RevisionNumber;
+
+ public readonly PEKind ProcessorArchitecture;
+ public readonly AssemblyContentType ContentType;
+
+ public readonly AssemblyIdentityFlags IdentityFlags;
+ }
+
+ public partial class AssemblyLoadContext
+ {
+ // called by vm
+ private protected unsafe int BindAssemblyByName(void* pAssemblyNameData, out BinderAssembly? assembly)
+ => BindUsingAssemblyName(new BinderAssemblyName((AssemblyNameData*)pAssemblyNameData), out assembly);
+
+ internal ApplicationContext AppContext { get; } = new ApplicationContext();
+
+ // called by vm
+ // ensure to call with BaseDomain::LoadLockHolder in native (from native binder)
+ private void AddLoadedAssembly(IntPtr loadedAssembly)
+ {
+ _loadedAssemblies.Add(loadedAssembly);
+
+ // #ifdef FEATURE_READYTORUN
+ DeclareLoadedAssembly(loadedAssembly);
+ // #endif // FEATURE_READYTORUN
+ }
+
+ //# ifdef FEATURE_READYTORUN
+
+ private static void MvidMismatchFatalError(Guid mvidActual, Guid mvidExpected, string simpleName, bool compositeComponent, string assemblyRequirementName)
+ {
+ string message;
+
+ if (compositeComponent)
+ {
+ message = $"MVID mismatch between loaded assembly '{simpleName}' (MVID = {mvidActual}) and an assembly with the same simple name embedded in the native image '{assemblyRequirementName}' (MVID = {mvidExpected})";
+ }
+ else
+ {
+ message = $"MVID mismatch between loaded assembly '{simpleName}' (MVID = {mvidActual}) and version of assembly '{simpleName}' expected by assembly '{assemblyRequirementName}' (MVID = {mvidExpected})";
+ }
+
+ Environment.FailFast(message);
+ }
+
+ // called by vm
+ private unsafe void DeclareDependencyOnMvid(byte* simpleName, in Guid mvid, bool compositeComponent, byte* imageName)
+ => DeclareDependencyOnMvid(new MdUtf8String(simpleName).ToString(), mvid, compositeComponent, new MdUtf8String(imageName).ToString());
+
+ // Must be called under the LoadLock
+ private void DeclareDependencyOnMvid(string simpleName, Guid mvid, bool compositeComponent, string imageName)
+ {
+ // If the table is empty, then we didn't fill it with all the loaded assemblies as they were loaded. Record this detail, and fix after adding the dependency
+ bool addAllLoadedModules = false;
+ if (_assemblySimpleNameMvidCheckHash.Count == 0)
+ {
+ addAllLoadedModules = true;
+ }
+
+ ref SimpleNameToExpectedMVIDAndRequiringAssembly? entry = ref CollectionsMarshal.GetValueRefOrAddDefault(_assemblySimpleNameMvidCheckHash, simpleName, out bool found);
+ if (!found)
+ {
+ entry = new SimpleNameToExpectedMVIDAndRequiringAssembly
+ {
+ Mvid = mvid,
+ CompositeComponent = compositeComponent,
+ AssemblyRequirementName = imageName
+ };
+ }
+ else
+ {
+ Debug.Assert(entry != null);
+ // Elem already exists. Determine if the existing elem is another one with the same mvid, in which case just record that a dependency is in play.
+ // If the existing elem has a different mvid, fail.
+ if (entry.Mvid == mvid)
+ {
+ // Mvid matches exactly.
+ if (entry.AssemblyRequirementName == null)
+ {
+ entry.AssemblyRequirementName = imageName;
+ entry.CompositeComponent = compositeComponent;
+ }
+ else
+ {
+ MvidMismatchFatalError(entry.Mvid, mvid, simpleName, compositeComponent, imageName);
+ }
+ }
+ }
+
+ if (addAllLoadedModules)
+ {
+ foreach (IntPtr assembly in _loadedAssemblies)
+ {
+ DeclareLoadedAssembly(assembly);
+ }
+ }
+ }
+
+ // Must be called under the LoadLock
+ private unsafe void DeclareLoadedAssembly(IntPtr loadedAssembly)
+ {
+ // If table is empty, then no mvid dependencies have been declared, so we don't need to record this information
+ if (_assemblySimpleNameMvidCheckHash.Count == 0)
+ {
+ return;
+ }
+
+ var mdImport = new MetadataImport(Assembly_GetMDImport(loadedAssembly));
+ mdImport.GetScopeProps(out Guid mvid);
+ string simpleName = new MdUtf8String(Assembly_GetSimpleName(loadedAssembly)).ToString();
+
+ ref SimpleNameToExpectedMVIDAndRequiringAssembly? entry = ref CollectionsMarshal.GetValueRefOrAddDefault(_assemblySimpleNameMvidCheckHash, simpleName, out bool found);
+ if (!found)
+ {
+ entry = new SimpleNameToExpectedMVIDAndRequiringAssembly
+ {
+ Mvid = mvid,
+ CompositeComponent = false,
+ AssemblyRequirementName = null
+ };
+ }
+ else
+ {
+ Debug.Assert(entry != null);
+ // Elem already exists. Determine if the existing elem is another one with the same mvid, in which case do nothing. Everything is fine here.
+ // If the existing elem has a different mvid, but isn't a dependency on exact mvid elem, then set the mvid to all 0.
+ // If the existing elem has a different mvid, and is a dependency on exact mvid elem, then we've hit a fatal error.
+ if (entry.Mvid == mvid)
+ {
+ // Mvid matches exactly.
+ }
+ else if (entry.AssemblyRequirementName == null)
+ {
+ // Another loaded assembly, set the stored Mvid to all zeroes to indicate that it isn't a unique mvid
+ entry.Mvid = Guid.Empty;
+ }
+ else
+ {
+ MvidMismatchFatalError(entry.Mvid, mvid, simpleName, entry.CompositeComponent, entry.AssemblyRequirementName);
+ }
+ }
+ }
+ //#endif // FEATURE_READYTORUN
+
+ private sealed class SimpleNameToExpectedMVIDAndRequiringAssembly
+ {
+ // When an assembly is loaded, this Mvid value will be set to the mvid of the assembly. If there are multiple assemblies
+ // with different mvid's loaded with the same simple name, then the Mvid value will be set to all zeroes.
+ public Guid Mvid;
+
+ // If an assembly of this simple name is not yet loaded, but a depedency on an exact mvid is registered, then this field will
+ // be filled in with the simple assembly name of the first assembly loaded with an mvid dependency.
+ public string? AssemblyRequirementName;
+
+ // To disambiguate between component images of a composite image and requirements from a non-composite --inputbubble assembly, use this bool
+ public bool CompositeComponent;
+ }
+
+ // Use a case senstive comparison here even though
+ // assembly name matching should be case insensitive. Case insensitive
+ // comparisons are slow and have throwing scenarios, and this hash table
+ // provides a best-effort match to prevent problems, not perfection
+ private readonly Dictionary _assemblySimpleNameMvidCheckHash = new Dictionary();
+ private readonly List _loadedAssemblies = new List();
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetMDImport")]
+ private static partial IntPtr Assembly_GetMDImport(IntPtr pAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetSimpleNameNative")]
+ private static unsafe partial byte* Assembly_GetSimpleName(IntPtr pAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetExposedObject")]
+ internal static unsafe partial void Assembly_GetExposedObject(IntPtr pAssembly, ObjectHandleOnStack rtAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetPEImage")]
+ internal static partial IntPtr Assembly_GetPEImage(IntPtr pAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_SetSymbolBytes")]
+ internal static unsafe partial void Assembly_SetSymbolBytes(IntPtr pAssembly, byte* ptrSymbolArray, int cbSymbolArrayLength);
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.BinderCommon.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.BinderCommon.cs
new file mode 100644
index 0000000000000..e7b34f4f0966e
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.BinderCommon.cs
@@ -0,0 +1,1296 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader.Tracing;
+
+namespace System.Runtime.Loader
+{
+ internal enum CorPEKind
+ {
+ peNot = 0x00000000, // not a PE file
+ peILonly = 0x00000001, // flag IL_ONLY is set in COR header
+ pe32BitRequired = 0x00000002, // flag 32BITREQUIRED is set and 32BITPREFERRED is clear in COR header
+ pe32Plus = 0x00000004, // PE32+ file (64 bit)
+ pe32Unmanaged = 0x00000008, // PE32 without COR header
+ pe32BitPreferred = 0x00000010 // flags 32BITREQUIRED and 32BITPREFERRED are set in COR header
+ }
+
+ internal struct BundleFileLocation
+ {
+ public long Size;
+ public long Offset;
+ public long UncompressedSize;
+
+ public readonly bool IsValid => Offset != 0;
+ }
+
+ internal static partial class AssemblyBinderCommon
+ {
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEImage_BinderAcquireImport")]
+ internal static unsafe partial IntPtr BinderAcquireImport(IntPtr pPEImage, int* pdwPAFlags);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEImage_BinderAcquirePEImage", StringMarshalling = StringMarshalling.Utf16)]
+ private static unsafe partial int BinderAcquirePEImage(string szAssemblyPath, out IntPtr ppPEImage, BundleFileLocation bundleFileLocation);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEImage_Release")]
+ internal static partial void PEImage_Release(IntPtr pPEImage);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEImage_GetMVID")]
+ internal static partial void PEImage_GetMVID(IntPtr pPEImage, out Guid mvid);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEImage_GetPath", StringMarshalling = StringMarshalling.Utf16)]
+ internal static unsafe partial char* PEImage_GetPath(IntPtr pPEImage);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Bundle_AppIsBundle")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static partial bool AppIsBundle();
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Bundle_ProbeAppBundle", StringMarshalling = StringMarshalling.Utf16)]
+ private static partial void ProbeAppBundle(string path, [MarshalAs(UnmanagedType.Bool)] bool pathIsBundleRelative, out BundleFileLocation result);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Bundle_GetAppBundleBasePath")]
+ private static partial void GetAppBundleBasePath(StringHandleOnStack path);
+
+ public static bool IsCompatibleAssemblyVersion(BinderAssemblyName requestedName, BinderAssemblyName foundName)
+ {
+ AssemblyVersion pRequestedVersion = requestedName.Version;
+ AssemblyVersion pFoundVersion = foundName.Version;
+
+ if (!pRequestedVersion.HasMajor)
+ {
+ // An unspecified requested version component matches any value for the same component in the found version,
+ // regardless of lesser-order version components
+ return true;
+ }
+ if (!pFoundVersion.HasMajor || pRequestedVersion.Major > pFoundVersion.Major)
+ {
+ // - A specific requested version component does not match an unspecified value for the same component in
+ // the found version, regardless of lesser-order version components
+ // - Or, the requested version is greater than the found version
+ return false;
+ }
+ if (pRequestedVersion.Major < pFoundVersion.Major)
+ {
+ // The requested version is less than the found version
+ return true;
+ }
+
+ if (!pRequestedVersion.HasMinor)
+ {
+ return true;
+ }
+ if (!pFoundVersion.HasMinor || pRequestedVersion.Minor > pFoundVersion.Minor)
+ {
+ return false;
+ }
+ if (pRequestedVersion.Minor < pFoundVersion.Minor)
+ {
+ return true;
+ }
+
+ if (!pRequestedVersion.HasBuild)
+ {
+ return true;
+ }
+ if (!pFoundVersion.HasBuild || pRequestedVersion.Build > pFoundVersion.Build)
+ {
+ return false;
+ }
+ if (pRequestedVersion.Build < pFoundVersion.Build)
+ {
+ return true;
+ }
+
+ if (!pRequestedVersion.HasRevision)
+ {
+ return true;
+ }
+ if (!pFoundVersion.HasRevision || pRequestedVersion.Revision > pFoundVersion.Revision)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public static void CreateImageAssembly(IntPtr pPEImage, ref BindResult bindResult) => bindResult.SetResult(new BinderAssembly(pPEImage, isInTPA: false));
+
+ // defined in System.Reflection.PortableExecutable.Machine, but it's in System.Reflection.Metadata
+ // also defined in System.Reflection.ImageFileMachine
+ private const int IMAGE_FILE_MACHINE_I386 = 0x014c; // Intel 386.
+ private const int IMAGE_FILE_MACHINE_ARMNT = 0x01c4; // ARM Thumb-2 Little-Endian
+ private const int IMAGE_FILE_MACHINE_AMD64 = 0x8664; // AMD64 (K8)
+ private const int IMAGE_FILE_MACHINE_ARM64 = 0xAA64; // ARM64 Little-Endian
+
+ public static unsafe PEKind TranslatePEToArchitectureType(int* pdwPAFlags)
+ {
+ CorPEKind CLRPeKind = (CorPEKind)pdwPAFlags[0];
+ int dwImageType = pdwPAFlags[1];
+
+ if (CLRPeKind == CorPEKind.peNot)
+ {
+ // Not a PE. Shouldn't ever get here.
+ throw new BadImageFormatException();
+ }
+
+ if ((CLRPeKind & CorPEKind.peILonly) != 0 && (CLRPeKind & CorPEKind.pe32Plus) == 0 &&
+ (CLRPeKind & CorPEKind.pe32BitRequired) == 0 && dwImageType == IMAGE_FILE_MACHINE_I386)
+ {
+ // Processor-agnostic (MSIL)
+ return PEKind.MSIL;
+ }
+ else if ((CLRPeKind & CorPEKind.pe32Plus) != 0)
+ {
+ // 64-bit
+ if ((CLRPeKind & CorPEKind.pe32BitRequired) != 0)
+ {
+ // Invalid
+ throw new BadImageFormatException();
+ }
+
+ // Regardless of whether ILONLY is set or not, the architecture
+ // is the machine type.
+ if (dwImageType == IMAGE_FILE_MACHINE_ARM64)
+ return PEKind.ARM64;
+ else if (dwImageType == IMAGE_FILE_MACHINE_AMD64)
+ return PEKind.AMD64;
+ else
+ {
+ // We don't support other architectures
+ throw new BadImageFormatException();
+ }
+ }
+ else
+ {
+ // 32-bit, non-agnostic
+ if (dwImageType == IMAGE_FILE_MACHINE_I386)
+ return PEKind.I386;
+ else if (dwImageType == IMAGE_FILE_MACHINE_ARMNT)
+ return PEKind.ARM;
+ else
+ {
+ // Not supported
+ throw new BadImageFormatException();
+ }
+ }
+ }
+
+ // HResult
+ public const int RO_E_METADATA_NAME_NOT_FOUND = unchecked((int)0x8000000F);
+ public const int E_PATHNOTFOUND = unchecked((int)0x80070003);
+ public const int E_NOTREADY = unchecked((int)0x80070015);
+ public const int E_BADNETPATH = unchecked((int)0x80070035);
+ public const int E_BADNETNAME = unchecked((int)0x80070043);
+ public const int E_INVALID_NAME = unchecked((int)0x8007007B);
+ public const int E_MODNOTFOUND = unchecked((int)0x8007007E);
+ public const int E_DLLNOTFOUND = unchecked((int)0x80070485);
+ public const int E_WRONG_TARGET_NAME = unchecked((int)0x80070574);
+ public const int INET_E_CANNOT_CONNECT = unchecked((int)0x800C0004);
+ public const int INET_E_RESOURCE_NOT_FOUND = unchecked((int)0x800C0005);
+ public const int INET_E_OBJECT_NOT_FOUND = unchecked((int)0x800C0006);
+ public const int INET_E_DATA_NOT_AVAILABLE = unchecked((int)0x800C0007);
+ public const int INET_E_DOWNLOAD_FAILURE = unchecked((int)0x800C0008);
+ public const int INET_E_CONNECTION_TIMEOUT = unchecked((int)0x800C000B);
+ public const int INET_E_UNKNOWN_PROTOCOL = unchecked((int)0x800C000D);
+ public const int FUSION_E_APP_DOMAIN_LOCKED = unchecked((int)0x80131053);
+ public const int CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW = unchecked((int)0x80132000);
+ public const int CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH = unchecked((int)0x80132001);
+ public const int CLR_E_BIND_ASSEMBLY_NOT_FOUND = unchecked((int)0x80132004);
+ public const int CLR_E_BIND_TYPE_NOT_FOUND = unchecked((int)0x80132005);
+ public const int CLR_E_BIND_ARCHITECTURE_MISMATCH = unchecked((int)0x80132006);
+
+ public static int BindAssembly(AssemblyLoadContext binder, BinderAssemblyName assemblyName, bool excludeAppPaths, out BinderAssembly? result)
+ {
+ int kContextVersion = 0;
+ BindResult bindResult = default;
+ int hr = HResults.S_OK;
+ result = null;
+ ApplicationContext applicationContext = binder.AppContext;
+
+ // Tracing happens outside the binder lock to avoid calling into managed code within the lock
+ using var tracer = new ResolutionAttemptedOperation(assemblyName, binder, ref hr);
+
+ Retry:
+ lock (applicationContext.ContextCriticalSection)
+ {
+ hr = BindByName(applicationContext, assemblyName, false, false, excludeAppPaths, ref bindResult);
+
+ if (hr < 0) goto Exit;
+
+ // Remember the post-bind version
+ kContextVersion = applicationContext.Version;
+ }
+
+ Exit:
+ tracer.TraceBindResult(bindResult);
+
+ if (bindResult.Assembly != null)
+ {
+ hr = RegisterAndGetHostChosen(applicationContext, kContextVersion, bindResult, out BindResult hostBindResult);
+
+ if (hr == HResults.S_FALSE)
+ {
+ // Another bind interfered. We need to retry the entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult = default;
+ goto Retry;
+ }
+ else if (hr == HResults.S_OK)
+ {
+ Debug.Assert(hostBindResult.Assembly != null);
+ result = hostBindResult.Assembly;
+ }
+ }
+
+ return hr;
+ }
+
+ // Skipped - the managed binder can't bootstrap CoreLib
+ // static Assembly? BindToSystem(string systemDirectory);
+
+ // called by vm
+ private static unsafe int BindToSystemSatellite(char* systemDirectory, char* simpleName, char* cultureName, out BinderAssembly? assembly)
+ {
+ // Satellite assembly's relative path
+
+ // append culture name
+
+ // append satellite assembly's simple name
+
+ // append extension
+ string relativePath = (string.IsNullOrEmpty(new string(cultureName)) ? new string(simpleName) : new string(cultureName)) + ".dll";
+
+ // Satellite assembly's path:
+ // * Absolute path when looking for a file on disk
+ // * Bundle-relative path when looking within the single-file bundle.
+ string sCoreLibSatellite = string.Empty;
+
+ PathSource pathSource = PathSource.Bundle;
+ ProbeAppBundle(relativePath, pathIsBundleRelative: true, out BundleFileLocation bundleFileLocation);
+ if (!bundleFileLocation.IsValid)
+ {
+ sCoreLibSatellite = new string(systemDirectory);
+ pathSource = PathSource.ApplicationAssemblies;
+ }
+
+ sCoreLibSatellite = Path.Combine(sCoreLibSatellite, relativePath);
+
+ int hr = GetAssembly(sCoreLibSatellite, isInTPA: true, out assembly, default);
+ if (hr < 0)
+ {
+ assembly = null;
+ }
+
+ AssemblyLoadContext.TracePathProbed(sCoreLibSatellite, pathSource, hr);
+
+ return hr;
+ }
+
+ private static int BindByName(
+ ApplicationContext applicationContext,
+ BinderAssemblyName assemblyName,
+ bool skipFailureChecking,
+ bool skipVersionCompatibilityCheck,
+ bool excludeAppPaths,
+ ref BindResult bindResult)
+ {
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+
+ if (applicationContext.FailureCache.TryGetValue(new FailureCacheKey(assemblyName.SimpleName, assemblyName.Version), out int hr))
+ {
+ if (hr < 0) // FAILED(hr)
+ {
+ if (hr == HResults.E_FILENOTFOUND && skipFailureChecking)
+ {
+ // Ignore pre-existing transient bind error (re-bind will succeed)
+ applicationContext.FailureCache.Remove(new FailureCacheKey(assemblyName.SimpleName, assemblyName.Version));
+ }
+
+ return hr; // goto LogExit
+ }
+ else if (hr == HResults.S_FALSE)
+ {
+ // workaround: Special case for byte arrays. Rerun the bind to create binding log.
+ assemblyName.IsDefinition = true;
+ }
+ }
+
+ if (!IsValidArchitecture(assemblyName.ProcessorArchitecture))
+ {
+ // Assembly reference contains wrong architecture
+ hr = HResults.FUSION_E_INVALID_NAME;
+ goto Exit;
+ }
+
+ hr = BindLocked(applicationContext, assemblyName, skipVersionCompatibilityCheck, excludeAppPaths, ref bindResult);
+
+ if (hr < 0) return hr;
+
+ if (bindResult.Assembly == null)
+ {
+ // Behavior rules are clueless now
+ hr = HResults.E_FILENOTFOUND;
+ goto Exit;
+ }
+
+ Exit:
+ if (hr < 0)
+ {
+ if (skipFailureChecking)
+ {
+ if (hr != HResults.E_FILENOTFOUND)
+ {
+ // Cache non-transient bind error for byte-array
+ hr = HResults.S_FALSE;
+ }
+ else
+ {
+ // Ignore transient bind error (re-bind will succeed)
+ return hr; // goto LogExit;
+ }
+ }
+
+ applicationContext.AddToFailureCache(assemblyName, hr);
+ }
+
+ return hr;
+ }
+
+ private static int BindLocked(
+ ApplicationContext applicationContext,
+ BinderAssemblyName assemblyName,
+ bool skipVersionCompatibilityCheck,
+ bool excludeAppPaths,
+ ref BindResult bindResult)
+ {
+ bool isTpaListProvided = applicationContext.TrustedPlatformAssemblyMap != null;
+ int hr = FindInExecutionContext(applicationContext, assemblyName, out BinderAssembly? assembly);
+
+ // Add the attempt to the bind result on failure / not found. On success, it will be added after the version check.
+ if (hr < 0 || assembly == null)
+ bindResult.SetAttemptResult(hr, assembly, isInContext: true);
+
+ if (hr < 0) return hr;
+
+ if (assembly != null)
+ {
+ if (!skipVersionCompatibilityCheck)
+ {
+ // Can't give higher version than already bound
+ bool isCompatible = IsCompatibleAssemblyVersion(assemblyName, assembly.AssemblyName);
+ hr = isCompatible ? HResults.S_OK : FUSION_E_APP_DOMAIN_LOCKED;
+ bindResult.SetAttemptResult(hr, assembly, isInContext: true);
+
+ // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
+ if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided) // hr == FUSION_E_APP_DOMAIN_LOCKED
+ hr = HResults.FUSION_E_REF_DEF_MISMATCH;
+ }
+ else
+ {
+ bindResult.SetAttemptResult(hr, assembly, isInContext: true);
+ }
+
+ if (hr < 0) return hr;
+
+ bindResult.SetResult(assembly, isInContext: true);
+ }
+ else if (isTpaListProvided)
+ {
+ // BindByTpaList handles setting attempt results on the bind result
+ hr = BindByTpaList(applicationContext, assemblyName, excludeAppPaths, ref bindResult);
+
+ if (hr >= 0 && bindResult.Assembly != null) // SUCCEEDED(hr) && pBindResult->HaveResult()
+ {
+ bool isCompatible = IsCompatibleAssemblyVersion(assemblyName, bindResult.Assembly.AssemblyName);
+ hr = isCompatible ? HResults.S_OK : FUSION_E_APP_DOMAIN_LOCKED;
+ bindResult.SetAttemptResult(hr, bindResult.Assembly);
+
+ // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
+ if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided) // hr == FUSION_E_APP_DOMAIN_LOCKED
+ hr = HResults.FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ if (hr < 0)
+ {
+ bindResult.SetNoResult();
+ }
+ }
+
+ return hr;
+ }
+
+ private static int FindInExecutionContext(ApplicationContext applicationContext, BinderAssemblyName assemblyName, out BinderAssembly? assembly)
+ {
+ applicationContext.ExecutionContext.TryGetValue(assemblyName, out assembly);
+
+ // Set any found context entry. It is up to the caller to check the returned HRESULT
+ // for errors due to validation
+ if (assembly == null)
+ return HResults.S_FALSE;
+
+ if (assembly != null && assemblyName.IsDefinition
+ && (assembly.AssemblyName.ProcessorArchitecture != assemblyName.ProcessorArchitecture))
+ {
+ return FUSION_E_APP_DOMAIN_LOCKED;
+ }
+
+ return HResults.S_OK;
+ }
+
+ //
+ // Tests whether a candidate assembly's name matches the requested.
+ // This does not do a version check. The binder applies version policy
+ // further up the stack once it gets a successful bind.
+ //
+ private static bool TestCandidateRefMatchesDef(BinderAssemblyName requestedAssemblyName, BinderAssemblyName boundAssemblyName, bool tpaListAssembly)
+ {
+ AssemblyNameIncludeFlags includeFlags = AssemblyNameIncludeFlags.INCLUDE_DEFAULT;
+
+ if (!tpaListAssembly)
+ {
+ if (requestedAssemblyName.IsNeutralCulture)
+ {
+ includeFlags |= AssemblyNameIncludeFlags.EXCLUDE_CULTURE;
+ }
+ }
+
+ if (requestedAssemblyName.ProcessorArchitecture != PEKind.None)
+ {
+ includeFlags |= AssemblyNameIncludeFlags.INCLUDE_ARCHITECTURE;
+ }
+
+ return boundAssemblyName.Equals(requestedAssemblyName, includeFlags);
+ }
+
+ private static int BindSatelliteResourceFromBundle(BinderAssemblyName requestedAssemblyName, string relativePath, ref BindResult bindResult)
+ {
+ int hr = HResults.S_OK;
+
+ ProbeAppBundle(relativePath, pathIsBundleRelative: true, out BundleFileLocation bundleFileLocation);
+ if (!bundleFileLocation.IsValid)
+ {
+ return hr;
+ }
+
+ hr = GetAssembly(relativePath, isInTPA: false, out BinderAssembly? assembly, bundleFileLocation);
+
+ AssemblyLoadContext.TracePathProbed(relativePath, PathSource.Bundle, hr);
+
+ // Missing files are okay and expected when probing
+ if (hr == HResults.E_FILENOTFOUND)
+ {
+ return HResults.S_OK;
+ }
+
+ bindResult.SetAttemptResult(hr, assembly);
+ if (hr < 0)
+ return hr;
+
+ Debug.Assert(assembly != null);
+ BinderAssemblyName boundAssemblyName = assembly.AssemblyName;
+ if (TestCandidateRefMatchesDef(requestedAssemblyName, boundAssemblyName, tpaListAssembly: false))
+ {
+ bindResult.SetResult(assembly);
+ hr = HResults.S_OK;
+ }
+ else
+ {
+ hr = HResults.FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ bindResult.SetAttemptResult(hr, assembly);
+ return hr;
+ }
+
+ private static int BindSatelliteResourceByProbingPaths(
+ List resourceRoots,
+ BinderAssemblyName requestedAssemblyName,
+ string relativePath,
+ ref BindResult bindResult,
+ PathSource pathSource)
+ {
+ foreach (string bindingPath in resourceRoots)
+ {
+ string fileName = Path.Combine(bindingPath, relativePath);
+ int hr = GetAssembly(fileName, isInTPA: false, out BinderAssembly? assembly);
+ AssemblyLoadContext.TracePathProbed(fileName, pathSource, hr);
+
+ // Missing files are okay and expected when probing
+ if (hr == HResults.E_FILENOTFOUND)
+ {
+ continue;
+ }
+
+ bindResult.SetAttemptResult(hr, assembly);
+ if (hr < 0)
+ return hr;
+
+ Debug.Assert(assembly != null);
+ BinderAssemblyName boundAssemblyName = assembly.AssemblyName;
+ if (TestCandidateRefMatchesDef(requestedAssemblyName, boundAssemblyName, tpaListAssembly: false))
+ {
+ bindResult.SetResult(assembly);
+ hr = HResults.S_OK;
+ }
+ else
+ {
+ hr = HResults.FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ bindResult.SetAttemptResult(hr, assembly);
+ return hr;
+ }
+
+ // Up-stack expects S_OK when we don't find any candidate assemblies and no fatal error occurred (ie, no S_FALSE)
+ return HResults.S_OK;
+ }
+
+ private static int BindSatelliteResource(ApplicationContext applicationContext, BinderAssemblyName requestedAssemblyName, ref BindResult bindResult)
+ {
+ Debug.Assert(!requestedAssemblyName.IsNeutralCulture);
+
+ string fileName = Path.Combine(requestedAssemblyName.CultureOrLanguage, requestedAssemblyName.SimpleName) + ".dll";
+
+ // Satellite resource probing strategy is to look:
+ // * First within the single-file bundle
+ // * Then under each of the Platform Resource Roots
+ // * Then under each of the App Paths.
+ //
+ // During each search, if we find a platform resource file with matching file name, but whose ref-def didn't match,
+ // fall back to application resource lookup to handle case where a user creates resources with the same
+ // names as platform ones.
+
+ int hr = BindSatelliteResourceFromBundle(requestedAssemblyName, fileName, ref bindResult);
+
+ if (bindResult.Assembly != null || hr < 0)
+ {
+ return hr;
+ }
+
+ hr = BindSatelliteResourceByProbingPaths(applicationContext.PlatformResourceRoots, requestedAssemblyName, fileName, ref bindResult, PathSource.PlatformResourceRoots);
+
+ if (bindResult.Assembly != null || hr < 0)
+ {
+ return hr;
+ }
+
+ hr = BindSatelliteResourceByProbingPaths(applicationContext.AppPaths, requestedAssemblyName, fileName, ref bindResult, PathSource.AppPaths);
+
+ return hr;
+ }
+
+ private static int BindAssemblyByProbingPaths(List bindingPaths, BinderAssemblyName requestedAssemblyName, out BinderAssembly? result)
+ {
+ PathSource pathSource = PathSource.AppPaths;
+
+ // Loop through the binding paths looking for a matching assembly
+ foreach (string bindingPath in bindingPaths)
+ {
+ string fileNameWithoutExtension = Path.Combine(bindingPath, requestedAssemblyName.SimpleName);
+
+ // Look for a matching dll first
+ string fileName = fileNameWithoutExtension + ".dll";
+
+ int hr = GetAssembly(fileName, isInTPA: false, out BinderAssembly? assembly);
+ AssemblyLoadContext.TracePathProbed(fileName, pathSource, hr);
+
+ if (hr < 0)
+ {
+ fileName = fileNameWithoutExtension + ".exe";
+ hr = GetAssembly(fileName, isInTPA: false, out assembly);
+ AssemblyLoadContext.TracePathProbed(fileName, pathSource, hr);
+ }
+
+ // Since we're probing, file not founds are ok and we should just try another
+ // probing path
+ if (hr == HResults.COR_E_FILENOTFOUND)
+ {
+ continue;
+ }
+
+ // Set any found assembly. It is up to the caller to check the returned HRESULT for errors due to validation
+ result = assembly;
+ if (hr < 0)
+ return hr;
+
+ // We found a candidate.
+ //
+ // Below this point, we either establish that the ref-def matches, or
+ // we fail the bind.
+
+ Debug.Assert(assembly != null);
+
+ // Compare requested AssemblyName with that from the candidate assembly
+ if (!TestCandidateRefMatchesDef(requestedAssemblyName, assembly.AssemblyName, tpaListAssembly: false))
+ return HResults.FUSION_E_REF_DEF_MISMATCH;
+
+ return HResults.S_OK;
+ }
+
+ result = null;
+ return HResults.COR_E_FILENOTFOUND;
+ }
+
+ /*
+ * BindByTpaList is the entry-point for the custom binding algorithm in CoreCLR.
+ *
+ * The search for assemblies will proceed in the following order:
+ *
+ * If this application is a single-file bundle, the meta-data contained in the bundle
+ * will be probed to find the requested assembly. If the assembly is not found,
+ * The list of platform assemblies (TPAs) are considered next.
+ *
+ * Platform assemblies are specified as a list of files. This list is the only set of
+ * assemblies that we will load as platform. They can be specified as IL or NIs.
+ *
+ * Resources for platform assemblies are located by probing starting at the Platform Resource Roots,
+ * a set of folders configured by the host.
+ *
+ * If a requested assembly identity cannot be found in the TPA list or the resource roots,
+ * it is considered an application assembly. We probe for application assemblies in the
+ * AppPaths, a list of paths containing IL files and satellite resource folders.
+ *
+ */
+
+ public static int BindByTpaList(ApplicationContext applicationContext, BinderAssemblyName requestedAssemblyName, bool excludeAppPaths, ref BindResult bindResult)
+ {
+ bool fPartialMatchOnTpa = false;
+
+ if (!requestedAssemblyName.IsNeutralCulture)
+ {
+ int hr = BindSatelliteResource(applicationContext, requestedAssemblyName, ref bindResult);
+ if (hr < 0)
+ return hr;
+ }
+ else
+ {
+ BinderAssembly? tpaAssembly = null;
+
+ // Is assembly in the bundle?
+ // Single-file bundle contents take precedence over TPA.
+ // The list of bundled assemblies is contained in the bundle manifest, and NOT in the TPA.
+ // Therefore the bundle is first probed using the assembly's simple name.
+ // If found, the assembly is loaded from the bundle.
+ if (AppIsBundle())
+ {
+ // Search Assembly.ni.dll, then Assembly.dll
+ // The Assembly.ni.dll paths are rare, and intended for supporting managed C++ R2R assemblies.
+ ReadOnlySpan candidates = ["ni.dll", ".dll"];
+
+ // Loop through the binding paths looking for a matching assembly
+ foreach (string candidate in candidates)
+ {
+ string assemblyFileName = requestedAssemblyName.SimpleName + candidate;
+ string? assemblyFilePath = string.Empty;
+ GetAppBundleBasePath(new StringHandleOnStack(ref assemblyFilePath));
+ assemblyFilePath += assemblyFileName;
+
+ ProbeAppBundle(assemblyFileName, pathIsBundleRelative: true, out BundleFileLocation bundleFileLocation);
+ if (bundleFileLocation.IsValid)
+ {
+ int hr = GetAssembly(assemblyFilePath, isInTPA: true, out tpaAssembly, bundleFileLocation);
+
+ AssemblyLoadContext.TracePathProbed(assemblyFilePath, PathSource.Bundle, hr);
+
+ if (hr != HResults.E_FILENOTFOUND)
+ {
+ // Any other error is fatal
+ if (hr < 0) return hr;
+
+ Debug.Assert(tpaAssembly != null);
+ if (TestCandidateRefMatchesDef(requestedAssemblyName, tpaAssembly.AssemblyName, tpaListAssembly: true))
+ {
+ // We have found the requested assembly match in the bundle with validation of the full-qualified name.
+ // Bind to it.
+ bindResult.SetResult(tpaAssembly);
+ return HResults.S_OK;
+ }
+ }
+ }
+ }
+ }
+
+ // Is assembly on TPA list?
+ Debug.Assert(applicationContext.TrustedPlatformAssemblyMap != null);
+ if (applicationContext.TrustedPlatformAssemblyMap.TryGetValue(requestedAssemblyName.SimpleName, out TPAEntry? tpaEntry))
+ {
+ string? tpaFileName = tpaEntry.NIFileName ?? tpaEntry.ILFileName;
+ Debug.Assert(tpaFileName != null);
+
+ int hr = GetAssembly(tpaFileName, isInTPA: true, out tpaAssembly);
+ AssemblyLoadContext.TracePathProbed(tpaFileName, PathSource.ApplicationAssemblies, hr);
+
+ bindResult.SetAttemptResult(hr, tpaAssembly);
+
+ // On file not found, simply fall back to app path probing
+ if (hr != HResults.E_FILENOTFOUND)
+ {
+ // Any other error is fatal
+ if (hr < 0) return hr;
+
+ Debug.Assert(tpaAssembly != null);
+ if (TestCandidateRefMatchesDef(requestedAssemblyName, tpaAssembly.AssemblyName, tpaListAssembly: true))
+ {
+ // We have found the requested assembly match on TPA with validation of the full-qualified name. Bind to it.
+ bindResult.SetResult(tpaAssembly);
+ bindResult.SetAttemptResult(HResults.S_OK, tpaAssembly);
+ return HResults.S_OK;
+ }
+ else
+ {
+ // We found the assembly on TPA but it didn't match the RequestedAssembly assembly-name. In this case, lets proceed to see if we find the requested
+ // assembly in the App paths.
+ bindResult.SetAttemptResult(HResults.FUSION_E_REF_DEF_MISMATCH, tpaAssembly);
+ fPartialMatchOnTpa = true;
+ }
+ }
+
+ // We either didn't find a candidate, or the ref-def failed. Either way; fall back to app path probing.
+ }
+
+ if (!excludeAppPaths)
+ {
+ // Probe AppPaths
+
+ int hr = BindAssemblyByProbingPaths(applicationContext.AppPaths, requestedAssemblyName, out BinderAssembly? assembly);
+ bindResult.SetAttemptResult(hr, assembly);
+
+ if (hr != HResults.E_FILENOTFOUND)
+ {
+ if (hr < 0) return hr;
+ Debug.Assert(assembly != null);
+
+ // At this point, we have found an assembly with the expected name in the App paths. If this was also found on TPA,
+ // make sure that the app assembly has the same fullname (excluding version) as the TPA version. If it does, then
+ // we should bind to the TPA assembly. If it does not, then bind to the app assembly since it has a different fullname than the
+ // TPA assembly.
+ if (fPartialMatchOnTpa)
+ {
+ Debug.Assert(tpaAssembly != null);
+
+ if (TestCandidateRefMatchesDef(assembly.AssemblyName, tpaAssembly.AssemblyName, true))
+ {
+ // Fullname (SimpleName+Culture+PKT) matched for TPA and app assembly - so bind to TPA instance.
+ bindResult.SetResult(tpaAssembly);
+ bindResult.SetAttemptResult(hr, tpaAssembly);
+ return HResults.S_OK;
+ }
+ else
+ {
+ // Fullname (SimpleName+Culture+PKT) did not match for TPA and app assembly - so bind to app instance.
+ bindResult.SetResult(assembly);
+ return HResults.S_OK;
+ }
+ }
+ else
+ {
+ // We didn't see this assembly on TPA - so simply bind to the app instance.
+ bindResult.SetResult(assembly);
+ return HResults.S_OK;
+ }
+ }
+ }
+ }
+
+ // Couldn't find a matching assembly in any of the probing paths
+ // Return S_FALSE here. BindByName will interpret a successful HRESULT
+ // and lack of BindResult as a failure to find a matching assembly.
+ return HResults.S_FALSE;
+ }
+
+ private static int GetAssembly(string assemblyPath, bool isInTPA, out BinderAssembly? assembly, BundleFileLocation bundleFileLocation = default)
+ {
+ int hr = BinderAcquirePEImage(assemblyPath, out IntPtr pPEImage, bundleFileLocation);
+
+ try
+ {
+ if (hr < 0)
+ {
+ // Normalize file not found
+
+ // ported from Assembly::FileNotFound in coreclr\vm\assembly.cpp
+ if (hr is HResults.E_FILENOTFOUND
+ or E_MODNOTFOUND
+ or E_INVALID_NAME
+ or HResults.CTL_E_FILENOTFOUND
+ or E_PATHNOTFOUND
+ or E_BADNETNAME
+ or E_BADNETPATH
+ or E_NOTREADY
+ or E_WRONG_TARGET_NAME
+ or INET_E_UNKNOWN_PROTOCOL
+ or INET_E_CONNECTION_TIMEOUT
+ or INET_E_CANNOT_CONNECT
+ or INET_E_RESOURCE_NOT_FOUND
+ or INET_E_OBJECT_NOT_FOUND
+ or INET_E_DOWNLOAD_FAILURE
+ or INET_E_DATA_NOT_AVAILABLE
+ or E_DLLNOTFOUND
+ or CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW
+ or CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH
+ or CLR_E_BIND_ASSEMBLY_NOT_FOUND
+ or RO_E_METADATA_NAME_NOT_FOUND
+ or CLR_E_BIND_TYPE_NOT_FOUND)
+ {
+ hr = HResults.E_FILENOTFOUND;
+ }
+
+ assembly = null;
+ return hr;
+ }
+
+ assembly = new BinderAssembly(pPEImage, isInTPA);
+ pPEImage = IntPtr.Zero;
+ return HResults.S_OK;
+ }
+ catch (Exception e)
+ {
+ assembly = null;
+ return e.HResult;
+ }
+ finally
+ {
+ // SAFE_RELEASE(pPEImage);
+ if (pPEImage != IntPtr.Zero)
+ PEImage_Release(pPEImage);
+ }
+ }
+
+ public static int Register(ApplicationContext applicationContext, ref BindResult bindResult)
+ {
+ Debug.Assert(!bindResult.IsContextBound);
+ Debug.Assert(bindResult.Assembly != null);
+
+ applicationContext.IncrementVersion();
+
+ // Register the bindResult in the ExecutionContext only if we dont have it already.
+ // This method is invoked under a lock (by its caller), so we are thread safe.
+ int hr = FindInExecutionContext(applicationContext, bindResult.Assembly.AssemblyName, out BinderAssembly? assembly);
+ if (hr < 0)
+ return hr;
+
+ if (assembly == null)
+ {
+ applicationContext.ExecutionContext.Add(bindResult.Assembly.AssemblyName, bindResult.Assembly);
+ }
+ else
+ {
+ // Update the BindResult with the assembly we found
+ bindResult.SetResult(assembly, isInContext: true);
+ }
+
+ return HResults.S_OK;
+ }
+
+ public static int RegisterAndGetHostChosen(ApplicationContext applicationContext, int kContextVersion, in BindResult bindResult, out BindResult hostBindResult)
+ {
+ Debug.Assert(bindResult.Assembly != null);
+ hostBindResult = default;
+ int hr = HResults.S_OK;
+
+ if (!bindResult.IsContextBound)
+ {
+ hostBindResult = bindResult;
+
+ // Lock the application context
+ lock (applicationContext.ContextCriticalSection)
+ {
+ // Only perform costly validation if other binds succeeded before us
+ if (kContextVersion != applicationContext.Version)
+ {
+ hr = OtherBindInterfered(applicationContext, bindResult);
+ if (hr < 0) return hr;
+
+ if (hr == HResults.S_FALSE)
+ {
+ // Another bind interfered
+ return hr;
+ }
+ }
+
+ // No bind interfered, we can now register
+ hr = Register(applicationContext, ref hostBindResult);
+ if (hr < 0) return hr;
+ }
+ }
+ else
+ {
+ // No work required. Return the input
+ hostBindResult = bindResult;
+ }
+
+ return hr;
+ }
+
+ private static int OtherBindInterfered(ApplicationContext applicationContext, BindResult bindResult)
+ {
+ Debug.Assert(bindResult.Assembly != null);
+ Debug.Assert(bindResult.Assembly.AssemblyName != null);
+
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+ if (!applicationContext.FailureCache.ContainsKey(new FailureCacheKey(bindResult.Assembly.AssemblyName.SimpleName, bindResult.Assembly.AssemblyName.Version))) // hr == S_OK
+ {
+ int hr = FindInExecutionContext(applicationContext, bindResult.Assembly.AssemblyName, out BinderAssembly? assembly);
+ if (hr >= 0 && assembly != null)
+ {
+ // We can accept this bind in the domain
+ return HResults.S_OK;
+ }
+ }
+
+ // Some other bind interfered
+ return HResults.S_FALSE;
+ }
+
+ public static int BindUsingPEImage(AssemblyLoadContext binder, BinderAssemblyName assemblyName, IntPtr pPEImage, bool excludeAppPaths, out BinderAssembly? assembly)
+ {
+ int hr = HResults.S_OK;
+
+ int kContextVersion = 0;
+ BindResult bindResult = default;
+
+ // Prepare binding data
+ assembly = null;
+ ApplicationContext applicationContext = binder.AppContext;
+
+ // Tracing happens outside the binder lock to avoid calling into managed code within the lock
+ using var tracer = new ResolutionAttemptedOperation(assemblyName, binder, ref hr);
+
+ bool mvidMismatch = false;
+
+ try
+ {
+ Retry:
+ mvidMismatch = false;
+
+ // Lock the application context
+ lock (applicationContext.ContextCriticalSection)
+ {
+ // Attempt uncached bind and register stream if possible
+ // We skip version compatibility check - so assemblies with same simple name will be reported
+ // as a successful bind. Below we compare MVIDs in that case instead (which is a more precise equality check).
+ hr = BindByName(applicationContext, assemblyName, true, true, excludeAppPaths, ref bindResult);
+
+ if (hr == HResults.E_FILENOTFOUND)
+ {
+ // IF_FAIL_GO(CreateImageAssembly(pPEImage, &bindResult));
+ try
+ {
+ bindResult.SetResult(new BinderAssembly(pPEImage, false));
+ }
+ catch (Exception ex)
+ {
+ return ex.HResult;
+ }
+ }
+ else if (hr == HResults.S_OK)
+ {
+ if (bindResult.Assembly != null)
+ {
+ // Attempt was made to load an assembly that has the same name as a previously loaded one. Since same name
+ // does not imply the same assembly, we will need to check the MVID to confirm it is the same assembly as being
+ // requested.
+
+ Guid incomingMVID;
+ Guid boundMVID;
+
+ // GetMVID can throw exception
+ try
+ {
+ PEImage_GetMVID(pPEImage, out incomingMVID);
+ PEImage_GetMVID(bindResult.Assembly.PEImage, out boundMVID);
+ }
+ catch (Exception ex)
+ {
+ return ex.HResult;
+ }
+
+ mvidMismatch = incomingMVID != boundMVID;
+ if (mvidMismatch)
+ {
+ // MVIDs do not match, so fail the load.
+ return HResults.COR_E_FILELOAD;
+ }
+
+ // MVIDs match - request came in for the same assembly that was previously loaded.
+ // Let it through...
+ }
+ }
+
+ // Remember the post-bind version of the context
+ kContextVersion = applicationContext.Version;
+ }
+
+ if (bindResult.Assembly != null)
+ {
+ // This has to happen outside the binder lock as it can cause new binds
+ hr = RegisterAndGetHostChosen(applicationContext, kContextVersion, bindResult, out BindResult hostBindResult);
+ if (hr < 0) return hr;
+
+ if (hr == HResults.S_FALSE)
+ {
+ // tracer.TraceBindResult(bindResult);
+
+ // Another bind interfered. We need to retry entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult = default;
+ goto Retry;
+ }
+ else if (hr == HResults.S_OK)
+ {
+ assembly = hostBindResult.Assembly;
+ }
+ }
+ }
+ finally
+ {
+ tracer.TraceBindResult(bindResult, mvidMismatch);
+ }
+
+ return hr;
+ }
+
+ // CreateDefaultBinder
+
+ public static bool IsValidArchitecture(PEKind architecture)
+ {
+ if (architecture is PEKind.MSIL or PEKind.None)
+ return true;
+
+ PEKind processArchitecture =
+#if TARGET_X86
+ PEKind.I386;
+#elif TARGET_AMD64
+ PEKind.AMD64;
+#elif TARGET_ARM
+ PEKind.ARM;
+#elif TARGET_ARM64
+ PEKind.ARM64;
+#else
+ PEKind.MSIL;
+#endif
+
+ return architecture == processArchitecture;
+ }
+
+ // AssemblySpec::InitializeAssemblyNameRef
+ public static unsafe AssemblyName InitializeAssemblyNameRef(BinderAssemblyName assemblyName)
+ {
+ string culture = string.Empty;
+
+ if ((assemblyName.IdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE) != 0)
+ {
+ culture = assemblyName.IsNeutralCulture ? string.Empty : assemblyName.CultureOrLanguage;
+ }
+
+ fixed (char* pName = assemblyName.SimpleName)
+ fixed (char* pCulture = culture)
+ fixed (byte* pPublicKeyOrToken = assemblyName.PublicKeyOrTokenBLOB)
+ {
+ var nativeAssemblyNameParts = new NativeAssemblyNameParts
+ {
+ _pName = pName,
+ _pCultureName = pCulture,
+ _major = (ushort)assemblyName.Version.Major,
+ _minor = (ushort)assemblyName.Version.Minor,
+ _build = (ushort)assemblyName.Version.Build,
+ _revision = (ushort)assemblyName.Version.Revision,
+ _pPublicKeyOrToken = pPublicKeyOrToken,
+ _cbPublicKeyOrToken = assemblyName.PublicKeyOrTokenBLOB.Length,
+ };
+
+ if ((assemblyName.IdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY) != 0)
+ nativeAssemblyNameParts._flags |= System.Reflection.AssemblyNameFlags.PublicKey;
+
+ // Architecture unused
+
+ // Retargetable
+ if ((assemblyName.IdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE) != 0)
+ nativeAssemblyNameParts._flags |= System.Reflection.AssemblyNameFlags.Retargetable;
+
+ // Content type unused
+
+ return new AssemblyName(&nativeAssemblyNameParts);
+ }
+ }
+ }
+
+ public partial class AssemblyLoadContext
+ {
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "DomainAssembly_GetPEAssembly")]
+ private static partial IntPtr DomainAssembly_GetPEAssembly(IntPtr pDomainAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "PEAssembly_GetHostAssembly")]
+ private static partial IntPtr PEAssembly_GetHostAssembly(IntPtr pPEAssembly);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "DomainAssembly_EnsureReferenceBinder")]
+ private static partial IntPtr DomainAssembly_EnsureReferenceBinder(IntPtr pDomainAssembly, IntPtr pBinder);
+
+ internal static int BindUsingHostAssemblyResolver(
+ BinderAssemblyName assemblyName,
+ AssemblyLoadContext? defaultBinder,
+ AssemblyLoadContext binder,
+ out BinderAssembly? loadedAssembly)
+ {
+ int hr = HResults.E_FAIL;
+ loadedAssembly = null;
+ BinderAssembly? resolvedAssembly = null;
+
+ // body of RuntimeInvokeHostAssemblyResolver
+ bool fResolvedAssembly = false;
+ Assembly? refLoadedAssembly = null;
+ using var tracer = new ResolutionAttemptedOperation(assemblyName, binder, ref hr);
+
+ // Allocate an AssemblyName managed object
+ // Initialize the AssemblyName object
+ AssemblyName refAssemblyName = AssemblyBinderCommon.InitializeAssemblyNameRef(assemblyName);
+
+ bool isSatelliteAssemblyRequest = !assemblyName.IsNeutralCulture;
+ try
+ {
+ if (defaultBinder != null)
+ {
+ // Step 2 (of CustomAssemblyBinder::BindAssemblyByName) - Invoke Load method
+ // This is not invoked for TPA Binder since it always returns NULL.
+ tracer.GoToStage(Stage.AssemblyLoadContextLoad);
+
+ refLoadedAssembly = binder.ResolveUsingLoad(refAssemblyName);
+ if (refLoadedAssembly != null)
+ {
+ fResolvedAssembly = true;
+ }
+
+ hr = fResolvedAssembly ? HResults.S_OK : HResults.COR_E_FILENOTFOUND;
+
+ // Step 3 (of CustomAssemblyBinder::BindAssemblyByName)
+ if (!fResolvedAssembly && !isSatelliteAssemblyRequest)
+ {
+ tracer.GoToStage(Stage.DefaultAssemblyLoadContextFallback);
+
+ // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
+ // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
+
+ hr = defaultBinder.BindUsingAssemblyName(assemblyName, out BinderAssembly? coreCLRFoundAssembly);
+ if (hr >= 0)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ resolvedAssembly = coreCLRFoundAssembly;
+ fResolvedAssembly = true;
+ }
+ }
+ }
+
+ if (!fResolvedAssembly && isSatelliteAssemblyRequest)
+ {
+ // Step 4 (of CustomAssemblyBinder::BindAssemblyByName)
+
+ // Attempt to resolve it using the ResolveSatelliteAssembly method.
+ tracer.GoToStage(Stage.ResolveSatelliteAssembly);
+
+ refLoadedAssembly = binder.ResolveSatelliteAssembly(refAssemblyName);
+ if (refLoadedAssembly != null)
+ {
+ // Set the flag indicating we found the assembly
+ fResolvedAssembly = true;
+ }
+
+ hr = fResolvedAssembly ? HResults.S_OK : HResults.COR_E_FILENOTFOUND;
+ }
+
+ if (!fResolvedAssembly)
+ {
+ // Step 5 (of CustomAssemblyBinder::BindAssemblyByName)
+
+ // If we couldn't resolve the assembly using TPA LoadContext as well, then
+ // attempt to resolve it using the Resolving event.
+ tracer.GoToStage(Stage.AssemblyLoadContextResolvingEvent);
+
+ refLoadedAssembly = binder.ResolveUsingEvent(refAssemblyName);
+ if (refLoadedAssembly != null)
+ {
+ // Set the flag indicating we found the assembly
+ fResolvedAssembly = true;
+ }
+
+ hr = fResolvedAssembly ? HResults.S_OK : HResults.COR_E_FILENOTFOUND;
+ }
+
+ if (fResolvedAssembly && resolvedAssembly == null)
+ {
+ // If we are here, assembly was successfully resolved via Load or Resolving events.
+ Debug.Assert(refLoadedAssembly != null);
+
+ // We were able to get the assembly loaded. Now, get its name since the host could have
+ // performed the resolution using an assembly with different name.
+
+ RuntimeAssembly? rtAssembly =
+ GetRuntimeAssembly(refLoadedAssembly)
+ ?? throw new InvalidOperationException(SR.Arg_MustBeRuntimeAssembly);
+
+ IntPtr pDomainAssembly = rtAssembly.GetUnderlyingNativeHandle();
+ IntPtr pLoadedPEAssembly = IntPtr.Zero;
+ bool fFailLoad = false;
+ if (pDomainAssembly == IntPtr.Zero)
+ {
+ // Reflection emitted assemblies will not have a domain assembly.
+ fFailLoad = true;
+ }
+ else
+ {
+ pLoadedPEAssembly = DomainAssembly_GetPEAssembly(pDomainAssembly);
+ if (PEAssembly_GetHostAssembly(pLoadedPEAssembly) == IntPtr.Zero)
+ {
+ // Reflection emitted assemblies will not have a domain assembly.
+ fFailLoad = true;
+ }
+ }
+
+ // The loaded assembly's BINDER_SPACE::Assembly* is saved as HostAssembly in PEAssembly
+ if (fFailLoad)
+ {
+ // string name = assemblyName.GetDisplayName(AssemblyNameIncludeFlags.INCLUDE_ALL);
+ throw new InvalidOperationException(SR.Host_AssemblyResolver_DynamicallyEmittedAssemblies_Unsupported);
+ }
+
+ // For collectible assemblies, ensure that the parent loader allocator keeps the assembly's loader allocator
+ // alive for all its lifetime.
+ if (rtAssembly.IsCollectible)
+ {
+ DomainAssembly_EnsureReferenceBinder(pDomainAssembly, binder._nativeAssemblyLoadContext);
+ }
+
+ resolvedAssembly = GCHandle.FromIntPtr(PEAssembly_GetHostAssembly(pLoadedPEAssembly)).Target as BinderAssembly;
+ }
+
+ if (fResolvedAssembly)
+ {
+ Debug.Assert(resolvedAssembly != null);
+
+ // Get the BINDER_SPACE::Assembly reference to return back to.
+ loadedAssembly = resolvedAssembly;
+ hr = HResults.S_OK;
+
+ tracer.SetFoundAssembly(resolvedAssembly);
+ }
+ else
+ {
+ hr = HResults.COR_E_FILENOTFOUND;
+ }
+ }
+ catch (Exception ex)
+ {
+ tracer.SetException(ex);
+ throw;
+ }
+
+ return hr;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
index 27debf8d2a271..008254b57b7ed 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
@@ -45,20 +45,21 @@ internal static Assembly[] GetLoadedAssemblies()
internal static extern bool IsTracingEnabled();
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TraceResolvingHandlerInvoked", StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool TraceResolvingHandlerInvoked(string assemblyName, string handlerName, string? alcName, string? resultAssemblyName, string? resultAssemblyPath);
+ internal static partial void TraceResolvingHandlerInvoked(string assemblyName, string handlerName, string? alcName, string? resultAssemblyName, string? resultAssemblyPath);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TraceAssemblyResolveHandlerInvoked", StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool TraceAssemblyResolveHandlerInvoked(string assemblyName, string handlerName, string? resultAssemblyName, string? resultAssemblyPath);
+ internal static partial void TraceAssemblyResolveHandlerInvoked(string assemblyName, string handlerName, string? resultAssemblyName, string? resultAssemblyPath);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TraceAssemblyLoadFromResolveHandlerInvoked", StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool TraceAssemblyLoadFromResolveHandlerInvoked(string assemblyName, [MarshalAs(UnmanagedType.Bool)] bool isTrackedAssembly, string requestingAssemblyPath, string? requestedAssemblyPath);
+ internal static partial void TraceAssemblyLoadFromResolveHandlerInvoked(string assemblyName, [MarshalAs(UnmanagedType.Bool)] bool isTrackedAssembly, string requestingAssemblyPath, string? requestedAssemblyPath);
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TraceSatelliteSubdirectoryPathProbed", StringMarshalling = StringMarshalling.Utf16)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static partial bool TraceSatelliteSubdirectoryPathProbed(string filePath, int hResult);
+ internal static void TraceSatelliteSubdirectoryPathProbed(string filePath, int hResult) => TracePathProbed(filePath, PathSource.SatelliteSubdirectory, hResult);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TracePathProbed", StringMarshalling = StringMarshalling.Utf16)]
+ internal static partial void TracePathProbed(string filePath, PathSource source, int hResult);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_TraceResolutionAttempted", StringMarshalling = StringMarshalling.Utf16)]
+ internal static partial void TraceResolutionAttempted(string assemblyName, Tracing.Stage stage, string assemblyLoadContextName, Tracing.Result result, string resultAssemblyName, string resultAssemblyPath, string errorMsg);
[RequiresUnreferencedCode("Types and members the loaded assembly depends on might be removed")]
private RuntimeAssembly InternalLoadFromPath(string? assemblyPath, string? nativeImagePath)
@@ -107,17 +108,6 @@ internal Assembly LoadFromInMemoryModule(IntPtr moduleHandle)
}
}
#endif
-
- // This method is invoked by the VM to resolve a satellite assembly reference
- // after trying assembly resolution via Load override without success.
- private static Assembly? ResolveSatelliteAssembly(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
- {
- AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!;
-
- // Invoke the ResolveSatelliteAssembly method
- return context.ResolveSatelliteAssembly(assemblyName);
- }
-
// This method is invoked by the VM when using the host-provided assembly load context
// implementation.
private static IntPtr ResolveUnmanagedDll(string unmanagedDllName, IntPtr gchManagedAssemblyLoadContext)
@@ -134,15 +124,6 @@ private static IntPtr ResolveUnmanagedDllUsingEvent(string unmanagedDllName, Ass
return context.GetResolvedUnmanagedDll(assembly, unmanagedDllName);
}
- // This method is invoked by the VM to resolve an assembly reference using the Resolving event
- // after trying assembly resolution via Load override and TPA load context without success.
- private static Assembly? ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
- {
- AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!;
- // Invoke the AssemblyResolve event callbacks if wired up
- return context.ResolveUsingEvent(assemblyName);
- }
-
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AssemblyNative_GetLoadContextForAssembly")]
private static partial IntPtr GetLoadContextForAssembly(QCallAssembly assembly);
@@ -218,13 +199,16 @@ private static void StopAssemblyLoad(ref Guid activityId)
// Don't use trace to TPL event source in ActivityTracker - that event source is a singleton and its instantiation may have triggered the load.
ActivityTracker.Instance.OnStop(NativeRuntimeEventSource.Log.Name, AssemblyLoadName, 0, ref activityId, useTplSource: false);
}
-
- ///
- /// Called by the runtime to make sure the default ALC is initialized
- ///
- private static void InitializeDefaultContext()
- {
- _ = Default;
- }
}
+
+ // This must match the BindingPathSource value map in ClrEtwAll.man
+ internal enum PathSource : ushort
+ {
+ ApplicationAssemblies,
+ Unused,
+ AppPaths,
+ PlatformResourceRoots,
+ SatelliteSubdirectory,
+ Bundle
+ };
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CustomBinder.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CustomBinder.cs
new file mode 100644
index 0000000000000..96db193288ee4
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CustomBinder.cs
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+
+namespace System.Runtime.Loader
+{
+ public partial class AssemblyLoadContext
+ {
+ private int BindAssemblyByNameWorker(BinderAssemblyName assemblyName, out BinderAssembly? coreCLRFoundAssembly)
+ {
+ // CoreLib should be bound using BindToSystem
+ Debug.Assert(!assemblyName.IsCoreLib);
+
+ int hr = AssemblyBinderCommon.BindAssembly(this, assemblyName, excludeAppPaths: false, out coreCLRFoundAssembly);
+
+ if (hr >= 0)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ coreCLRFoundAssembly.Binder = _nativeAssemblyLoadContext;
+ }
+
+ return hr;
+ }
+
+ internal virtual int BindUsingAssemblyName(BinderAssemblyName assemblyName, out BinderAssembly? assembly)
+ {
+ int hr;
+ BinderAssembly? coreCLRFoundAssembly;
+
+ // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
+ //
+ // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it.
+ // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it.
+ // 3) Lookup the assembly within DefaultBinder (except for satellite requests). If assembly is found, use it.
+ // 4) Invoke the LoadContext's ResolveSatelliteAssembly method (for satellite requests). If assembly is found, use it.
+ // 5) Invoke the LoadContext's Resolving event. If assembly is found, use it.
+ // 6) Raise exception.
+ //
+ // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading
+ // a different (or even the same!) version.
+
+ {
+ // Step 1 - Try to find the assembly within the LoadContext.
+ hr = BindAssemblyByNameWorker(assemblyName, out coreCLRFoundAssembly);
+ if (hr is HResults.E_FILENOTFOUND or AssemblyBinderCommon.FUSION_E_APP_DOMAIN_LOCKED or HResults.FUSION_E_REF_DEF_MISMATCH)
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
+ // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
+ // that has been loaded.
+
+ hr = BindUsingHostAssemblyResolver(assemblyName, Default, this, out coreCLRFoundAssembly);
+
+ if (hr >= 0)
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyBinder instance.
+ // In such a case, we will not overwrite the binder (which would be wrong since the assembly would not
+ // be present in the cache of the current binding context).
+ Debug.Assert(coreCLRFoundAssembly != null);
+ if (coreCLRFoundAssembly.Binder == IntPtr.Zero)
+ coreCLRFoundAssembly.Binder = _nativeAssemblyLoadContext;
+ }
+ }
+ }
+
+ assembly = hr < 0 ? null : coreCLRFoundAssembly;
+ return hr;
+ }
+
+ // called by vm
+ internal virtual int BindUsingPEImage(nint pPEImage, bool excludeAppPaths, out BinderAssembly? assembly)
+ {
+ assembly = null;
+ int hr;
+
+ try
+ {
+ BinderAssembly? coreCLRFoundAssembly;
+ BinderAssemblyName assemblyName = new BinderAssemblyName(pPEImage);
+
+ // Validate architecture
+ if (!AssemblyBinderCommon.IsValidArchitecture(assemblyName.ProcessorArchitecture))
+ return AssemblyBinderCommon.CLR_E_BIND_ARCHITECTURE_MISMATCH;
+
+ // Disallow attempt to bind to the core library. Aside from that,
+ // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA).
+ if (assemblyName.IsCoreLib)
+ return HResults.E_FILENOTFOUND;
+
+ hr = AssemblyBinderCommon.BindUsingPEImage(this, assemblyName, pPEImage, excludeAppPaths, out coreCLRFoundAssembly);
+ if (hr == HResults.S_OK)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ coreCLRFoundAssembly.Binder = _nativeAssemblyLoadContext;
+ assembly = coreCLRFoundAssembly;
+ }
+ }
+ catch (Exception ex)
+ {
+ return ex.HResult;
+ }
+
+ return hr;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.DefaultBinder.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.DefaultBinder.cs
new file mode 100644
index 0000000000000..e1c737c70b396
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.DefaultBinder.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+
+namespace System.Runtime.Loader
+{
+ public partial class AssemblyLoadContext
+ {
+ // called by vm
+ private static BinderAssembly InitializeDefault(IntPtr pCoreLibAssembly)
+ {
+ // ensure to touch Default to make it initialized
+ Default.AddLoadedAssembly(pCoreLibAssembly);
+ return new BinderAssembly(Assembly_GetPEImage(pCoreLibAssembly), true) { Binder = Default._nativeAssemblyLoadContext };
+ }
+
+ // called by VM
+ private static unsafe void SetupBindingPaths(char* trustedPlatformAssemblies, char* platformResourceRoots, char* appPaths)
+ {
+ Default.AppContext.SetupBindingPaths(new string(trustedPlatformAssemblies), new string(platformResourceRoots), new string(appPaths), acquireLock: true);
+ }
+
+ private protected IntPtr GetNativeAssemblyLoadContext() => _nativeAssemblyLoadContext;
+ }
+
+ internal partial class DefaultAssemblyLoadContext
+ {
+ // Helper functions
+ private int BindAssemblyByNameWorker(BinderAssemblyName assemblyName, out BinderAssembly? coreCLRFoundAssembly, bool excludeAppPaths)
+ {
+ // CoreLib should be bound using BindToSystem
+ Debug.Assert(!assemblyName.IsCoreLib);
+
+ int hr = AssemblyBinderCommon.BindAssembly(this, assemblyName, excludeAppPaths, out coreCLRFoundAssembly);
+
+ if (hr >= 0)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ coreCLRFoundAssembly.Binder = GetNativeAssemblyLoadContext();
+ }
+
+ return hr;
+ }
+
+ internal override int BindUsingAssemblyName(BinderAssemblyName assemblyName, out BinderAssembly? assembly)
+ {
+ assembly = null;
+
+ int hr = BindAssemblyByNameWorker(assemblyName, out BinderAssembly? coreCLRFoundAssembly, excludeAppPaths: false);
+
+ if (hr is HResults.E_FILENOTFOUND or AssemblyBinderCommon.FUSION_E_APP_DOMAIN_LOCKED or HResults.FUSION_E_REF_DEF_MISMATCH)
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Attempt to resolve the assembly via managed ALC instance. This can either fail the bind or return reference to an existing
+ // assembly that has been loaded
+
+ // For satellite assemblies, the managed ALC has additional resolution logic (defined by the runtime) which
+ // should be run even if the managed default ALC has not yet been used. (For non-satellite assemblies, any
+ // additional logic comes through a user-defined event handler which would have initialized the managed ALC,
+ // so if the managed ALC is not set yet, there is no additional logic to run)
+
+ // The logic was folded from native ALC. We are the managed ALC now and no additional initialization is required.
+
+ hr = BindUsingHostAssemblyResolver(assemblyName, null, this, out coreCLRFoundAssembly);
+
+ if (hr >= 0)
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ Debug.Assert(coreCLRFoundAssembly != null);
+ if (coreCLRFoundAssembly.Binder == IntPtr.Zero)
+ coreCLRFoundAssembly.Binder = GetNativeAssemblyLoadContext();
+ }
+ }
+
+ if (hr >= 0)
+ assembly = coreCLRFoundAssembly;
+
+ return hr;
+ }
+
+ internal override int BindUsingPEImage(nint pPEImage, bool excludeAppPaths, out BinderAssembly? assembly)
+ {
+ assembly = null;
+ int hr;
+
+ try
+ {
+ BinderAssembly? coreCLRFoundAssembly;
+ BinderAssemblyName assemblyName = new BinderAssemblyName(pPEImage);
+
+ // Validate architecture
+ if (!AssemblyBinderCommon.IsValidArchitecture(assemblyName.ProcessorArchitecture))
+ return AssemblyBinderCommon.CLR_E_BIND_ARCHITECTURE_MISMATCH;
+
+ // Easy out for CoreLib
+ if (assemblyName.IsCoreLib)
+ return HResults.E_FILENOTFOUND;
+
+ {
+ // Ensure we are not being asked to bind to a TPA assembly
+
+ Debug.Assert(AppContext.TrustedPlatformAssemblyMap != null);
+
+ if (AppContext.TrustedPlatformAssemblyMap.ContainsKey(assemblyName.SimpleName))
+ {
+ // The simple name of the assembly being requested to be bound was found in the TPA list.
+ // Now, perform the actual bind to see if the assembly was really in the TPA assembly list or not.
+ hr = BindAssemblyByNameWorker(assemblyName, out coreCLRFoundAssembly, excludeAppPaths: true);
+ if (hr >= 0)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ if (coreCLRFoundAssembly.IsInTPA)
+ {
+ assembly = coreCLRFoundAssembly;
+ return hr;
+ }
+ }
+ }
+ }
+
+ hr = AssemblyBinderCommon.BindUsingPEImage(this, assemblyName, pPEImage, excludeAppPaths, out coreCLRFoundAssembly);
+ if (hr == HResults.S_OK)
+ {
+ Debug.Assert(coreCLRFoundAssembly != null);
+ coreCLRFoundAssembly.Binder = GetNativeAssemblyLoadContext();
+ assembly = coreCLRFoundAssembly;
+ }
+ }
+ catch (Exception ex)
+ {
+ return ex.HResult;
+ }
+
+ return hr;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyName.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyName.cs
new file mode 100644
index 0000000000000..c04c1e5733f88
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyName.cs
@@ -0,0 +1,379 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.IO;
+using System.Numerics;
+using System.Reflection;
+
+namespace System.Runtime.Loader
+{
+ internal unsafe struct AssemblyMetaDataInternal
+ {
+ public ushort usMajorVersion; // Major Version.
+ public ushort usMinorVersion; // Minor Version.
+ public ushort usBuildNumber; // Build Number.
+ public ushort usRevisionNumber; // Revision Number.
+ public byte* szLocale; // Locale.
+ }
+
+ internal enum CorAssemblyFlags
+ {
+ afPublicKey = 0x0001, // The assembly ref holds the full (unhashed) public key.
+
+ afPA_None = 0x0000, // Processor Architecture unspecified
+ afPA_MSIL = 0x0010, // Processor Architecture: neutral (PE32)
+ afPA_x86 = 0x0020, // Processor Architecture: x86 (PE32)
+ afPA_IA64 = 0x0030, // Processor Architecture: Itanium (PE32+)
+ afPA_AMD64 = 0x0040, // Processor Architecture: AMD X64 (PE32+)
+ afPA_ARM = 0x0050, // Processor Architecture: ARM (PE32)
+ afPA_ARM64 = 0x0060, // Processor Architecture: ARM64 (PE32+)
+ afPA_NoPlatform = 0x0070, // applies to any platform but cannot run on any (e.g. reference assembly), should not have "specified" set
+ afPA_Specified = 0x0080, // Propagate PA flags to AssemblyRef record
+ afPA_Mask = 0x0070, // Bits describing the processor architecture
+ afPA_FullMask = 0x00F0, // Bits describing the PA incl. Specified
+ afPA_Shift = 0x0004, // NOT A FLAG, shift count in PA flags <--> index conversion
+
+ afEnableJITcompileTracking = 0x8000, // From "DebuggableAttribute".
+ afDisableJITcompileOptimizer = 0x4000, // From "DebuggableAttribute".
+ afDebuggableAttributeMask = 0xc000,
+
+ afRetargetable = 0x0100, // The assembly can be retargeted (at runtime) to an
+ // assembly from a different publisher.
+
+ afContentType_Default = 0x0000,
+ afContentType_WindowsRuntime = 0x0200,
+ afContentType_Mask = 0x0E00, // Bits describing ContentType
+ }
+
+ internal enum AssemblyNameIncludeFlags
+ {
+ INCLUDE_DEFAULT = 0x00,
+ INCLUDE_VERSION = 0x01,
+ INCLUDE_ARCHITECTURE = 0x02,
+ INCLUDE_RETARGETABLE = 0x04,
+ INCLUDE_CONTENT_TYPE = 0x08,
+ INCLUDE_PUBLIC_KEY_TOKEN = 0x10,
+ EXCLUDE_CULTURE = 0x20,
+ INCLUDE_ALL = INCLUDE_VERSION
+ | INCLUDE_ARCHITECTURE
+ | INCLUDE_RETARGETABLE
+ | INCLUDE_CONTENT_TYPE
+ | INCLUDE_PUBLIC_KEY_TOKEN,
+ }
+
+ internal sealed unsafe class BinderAssemblyName : AssemblyIdentity, IEquatable
+ {
+ public bool IsDefinition;
+
+ public BinderAssemblyName(IntPtr pPEImage)
+ {
+ int* dwPAFlags = stackalloc int[2];
+ IntPtr pIMetaDataAssemblyImport = AssemblyBinderCommon.BinderAcquireImport(pPEImage, dwPAFlags);
+ var scope = new MetadataImport(pIMetaDataAssemblyImport);
+
+ ProcessorArchitecture = AssemblyBinderCommon.TranslatePEToArchitectureType(dwPAFlags);
+
+ // Get the assembly token
+ uint mda = scope.GetAssemblyFromScope();
+
+ AssemblyMetaDataInternal amd = default;
+
+ // Get name and metadata
+ scope.GetAssemblyProps(
+ mda,
+ out byte* pvPublicKeyToken,
+ out uint dwPublicKeyToken,
+ out uint dwHashAlgId,
+ out string? assemblyName,
+ &amd,
+ out uint flags);
+
+ CorAssemblyFlags dwRefOrDefFlags = (CorAssemblyFlags)flags;
+
+ {
+ string culture = new MdUtf8String(amd.szLocale).ToString();
+ int index = culture.IndexOf(';');
+ if (index != -1)
+ {
+ culture = culture[..index];
+ }
+
+ CultureOrLanguage = culture;
+ IdentityFlags |= AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE;
+ }
+
+ {
+ const int MAX_PATH_FNAME = 260;
+ if (assemblyName.Length >= MAX_PATH_FNAME)
+ {
+ throw new FileLoadException
+ {
+ HResult = HResults.FUSION_E_INVALID_NAME
+ };
+ }
+
+ SimpleName = assemblyName;
+ IdentityFlags |= AssemblyIdentityFlags.IDENTITY_FLAG_SIMPLE_NAME;
+ }
+
+ // See if the assembly[def] is retargetable (ie, for a generic assembly).
+ if ((dwRefOrDefFlags & CorAssemblyFlags.afRetargetable) != 0)
+ {
+ IdentityFlags |= AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE;
+ }
+
+ // Set ContentType
+ if ((dwRefOrDefFlags & CorAssemblyFlags.afContentType_Mask) == CorAssemblyFlags.afContentType_Default)
+ {
+ ContentType = AssemblyContentType.Default;
+ }
+ else
+ {
+ // We no longer support WindowsRuntime assembly.
+ throw new FileLoadException
+ {
+ HResult = HResults.FUSION_E_INVALID_NAME
+ };
+ }
+
+ // Set the assembly version
+ {
+ Version = new AssemblyVersion
+ {
+ Major = amd.usMajorVersion,
+ Minor = amd.usMinorVersion,
+ Build = amd.usBuildNumber,
+ Revision = amd.usRevisionNumber
+ };
+
+ IdentityFlags |= AssemblyIdentityFlags.IDENTITY_FLAG_VERSION;
+ }
+
+ // Set public key and/or public key token (if we have it)
+ if (dwPublicKeyToken != 0 && pvPublicKeyToken != null)
+ {
+ if ((dwRefOrDefFlags & CorAssemblyFlags.afPublicKey) != 0)
+ {
+ byte[] publicKeyToken = AssemblyNameHelpers.ComputePublicKeyToken(new ReadOnlySpan(pvPublicKeyToken, (int)dwPublicKeyToken));
+
+ PublicKeyOrTokenBLOB = publicKeyToken;
+ }
+ else
+ {
+ PublicKeyOrTokenBLOB = new ReadOnlySpan(pvPublicKeyToken, (int)dwPublicKeyToken).ToArray();
+ }
+
+ IdentityFlags |= AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN;
+ }
+ }
+
+ public unsafe BinderAssemblyName(AssemblyNameData* data)
+ {
+ AssemblyIdentityFlags flags = data->IdentityFlags;
+ SimpleName = new MdUtf8String(data->Name).ToString();
+ Version = new AssemblyVersion
+ {
+ Major = data->MajorVersion,
+ Minor = data->MinorVersion,
+ Build = data->BuildNumber,
+ Revision = data->RevisionNumber
+ };
+ CultureOrLanguage = new MdUtf8String(data->Culture).ToString();
+
+ PublicKeyOrTokenBLOB = new ReadOnlySpan(data->PublicKeyOrToken, data->PublicKeyOrTokenLength).ToArray();
+ if ((flags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY) != 0)
+ {
+ // Convert public key to token
+
+ byte[]? publicKeyToken = AssemblyNameHelpers.ComputePublicKeyToken(PublicKeyOrTokenBLOB);
+ Debug.Assert(publicKeyToken != null);
+
+ PublicKeyOrTokenBLOB = publicKeyToken;
+ flags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY;
+ flags |= AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN;
+ }
+
+ ProcessorArchitecture = data->ProcessorArchitecture;
+ ContentType = data->ContentType;
+ IdentityFlags |= flags;
+ }
+
+ // TODO: Is this simple comparison enough?
+ public bool IsCoreLib => string.EqualsOrdinalIgnoreCase(SimpleName, CoreLib.Name);
+
+ public bool IsNeutralCulture => string.IsNullOrEmpty(CultureOrLanguage) || string.EqualsOrdinalIgnoreCase(CultureOrLanguage, NeutralCulture);
+
+ public override int GetHashCode() => GetHashCode(AssemblyNameIncludeFlags.INCLUDE_DEFAULT);
+
+ public int GetHashCode(AssemblyNameIncludeFlags dwIncludeFlags)
+ {
+ uint dwHash = 0;
+ AssemblyIdentityFlags dwUseIdentityFlags = IdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_CONTENT_TYPE;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_PUBLIC_KEY_TOKEN) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY;
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.EXCLUDE_CULTURE) != 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE;
+ }
+
+ static uint HashBytes(ReadOnlySpan bytes)
+ {
+ // ported from coreclr/inc/utilcode.h
+ uint hash = 5831;
+
+ foreach (byte b in bytes)
+ {
+ hash = ((hash << 5) + hash) ^ b;
+ }
+
+ return hash;
+ }
+
+ dwHash ^= (uint)SimpleName.GetNonRandomizedHashCodeOrdinalIgnoreCase();
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY) != 0 ||
+ (dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN) != 0)
+ {
+ dwHash ^= HashBytes(PublicKeyOrTokenBLOB);
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+ }
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_VERSION) != 0)
+ {
+
+ dwHash ^= (uint)Version.Major;
+ dwHash = BitOperations.RotateLeft(dwHash, 8);
+ dwHash ^= (uint)Version.Minor;
+ dwHash = BitOperations.RotateLeft(dwHash, 8);
+ dwHash ^= (uint)Version.Build;
+ dwHash = BitOperations.RotateLeft(dwHash, 8);
+ dwHash ^= (uint)Version.Revision;
+ dwHash = BitOperations.RotateLeft(dwHash, 8);
+ }
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE) != 0)
+ {
+ dwHash ^= (uint)NormalizedCulture.GetNonRandomizedHashCodeOrdinalIgnoreCase();
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+ }
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE) != 0)
+ {
+ dwHash ^= 1;
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+ }
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PROCESSOR_ARCHITECTURE) != 0)
+ {
+ dwHash ^= (uint)ProcessorArchitecture;
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+ }
+
+ if ((dwUseIdentityFlags & AssemblyIdentityFlags.IDENTITY_FLAG_CONTENT_TYPE) != 0)
+ {
+ dwHash ^= (uint)ContentType;
+ dwHash = BitOperations.RotateLeft(dwHash, 4);
+ }
+
+ return (int)dwHash;
+ }
+
+ public override bool Equals(object? obj) => obj is BinderAssemblyName other && Equals(other);
+
+ public bool Equals(BinderAssemblyName? other) => Equals(other, AssemblyNameIncludeFlags.INCLUDE_DEFAULT);
+
+ public bool Equals(AssemblyIdentity? other, AssemblyNameIncludeFlags dwIncludeFlags)
+ {
+ if (other is null)
+ return false;
+
+ bool fEquals = false;
+
+ if (ContentType == AssemblyContentType.WindowsRuntime)
+ { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
+ return ContentType == other.ContentType;
+ }
+
+ if (string.Equals(SimpleName, other.SimpleName, StringComparison.OrdinalIgnoreCase) &&
+ ContentType == other.ContentType)
+ {
+ fEquals = true;
+
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.EXCLUDE_CULTURE) == 0)
+ {
+ fEquals = string.Equals(NormalizedCulture, other.NormalizedCulture, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (fEquals && (dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_PUBLIC_KEY_TOKEN) != 0)
+ {
+ fEquals = PublicKeyOrTokenBLOB.AsSpan().SequenceEqual(other.PublicKeyOrTokenBLOB);
+ }
+
+ if (fEquals && ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_ARCHITECTURE) != 0))
+ {
+ fEquals = ProcessorArchitecture == other.ProcessorArchitecture;
+ }
+
+ if (fEquals && ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_VERSION) != 0))
+ {
+ fEquals = Version.Equals(other.Version);
+ }
+
+ if (fEquals && ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_RETARGETABLE) != 0))
+ {
+ fEquals = IsRetargetable == other.IsRetargetable;
+ }
+ }
+
+ return fEquals;
+ }
+
+ public string GetDisplayName(AssemblyNameIncludeFlags dwIncludeFlags)
+ {
+ AssemblyIdentityFlags dwUseIdentityFlags = IdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & AssemblyNameIncludeFlags.INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentityFlags.IDENTITY_FLAG_CONTENT_TYPE;
+ }
+
+ return TextualIdentityParser.ToString(this, dwUseIdentityFlags);
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyVersion.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyVersion.cs
new file mode 100644
index 0000000000000..94fb43c299055
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyVersion.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.Loader
+{
+ internal struct AssemblyVersion : IEquatable
+ {
+ public int Major;
+ public int Minor;
+ public int Build;
+ public int Revision;
+
+ public const int Unspecified = -1;
+
+ public AssemblyVersion()
+ {
+ Major = Unspecified;
+ Minor = Unspecified;
+ Build = Unspecified;
+ Revision = Unspecified;
+ }
+
+ public bool HasMajor => Major != Unspecified;
+
+ public bool HasMinor => Minor != Unspecified;
+
+ public bool HasBuild => Build != Unspecified;
+
+ public bool HasRevision => Revision != Unspecified;
+
+ public bool Equals(AssemblyVersion other) =>
+ Major == other.Major &&
+ Minor == other.Minor &&
+ Build == other.Build &&
+ Revision == other.Revision;
+
+ public override bool Equals(object? obj)
+ => obj is AssemblyVersion other && Equals(other);
+
+ public override int GetHashCode() => HashCode.Combine(Major, Minor, Build, Revision);
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/BindResult.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/BindResult.cs
new file mode 100644
index 0000000000000..27dffcffd617f
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/BindResult.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.Loader
+{
+ internal struct BindResult
+ {
+ public struct AttemptResult
+ {
+ public BinderAssembly? Assembly;
+ public int HResult;
+ public bool Attempted;
+ }
+
+ public bool IsContextBound { get; private set; }
+ public BinderAssembly? Assembly { get; private set; }
+
+ private AttemptResult _inContextAttempt;
+ private AttemptResult _applicationAssembliesResult;
+
+ public void SetAttemptResult(int hResult, BinderAssembly? assembly, bool isInContext = false)
+ {
+ ref AttemptResult result = ref (isInContext ? ref _inContextAttempt : ref _applicationAssembliesResult);
+ result.HResult = hResult;
+ result.Assembly = assembly;
+ result.Attempted = true;
+ }
+
+ public readonly AttemptResult GetAttemptResult(bool isInContext = false) => isInContext ? _inContextAttempt : _applicationAssembliesResult;
+
+ public void SetResult(BinderAssembly assembly, bool isInContext = false)
+ {
+ Assembly = assembly;
+ IsContextBound = isInContext;
+ }
+
+ public void SetNoResult()
+ {
+ Assembly = null;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/TextualIdentityParser.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/TextualIdentityParser.cs
new file mode 100644
index 0000000000000..4903bfd48e992
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/TextualIdentityParser.cs
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Reflection;
+using System.Text;
+
+namespace System.Runtime.Loader
+{
+ internal static class TextualIdentityParser
+ {
+ public static string ToString(AssemblyIdentity pAssemblyIdentity, AssemblyIdentityFlags includeFlags)
+ {
+ if (string.IsNullOrEmpty(pAssemblyIdentity.SimpleName))
+ {
+ return string.Empty;
+ }
+
+ ValueStringBuilder textualIdentity = new ValueStringBuilder(256);
+
+ AppendStringEscaped(ref textualIdentity, pAssemblyIdentity.SimpleName);
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_VERSION) != 0)
+ {
+ AssemblyVersion version = pAssemblyIdentity.Version;
+ textualIdentity.Append(", Version=");
+ textualIdentity.AppendSpanFormattable(version.Major);
+ textualIdentity.Append('.');
+ textualIdentity.AppendSpanFormattable(version.Minor);
+ textualIdentity.Append('.');
+ textualIdentity.AppendSpanFormattable(version.Build);
+ textualIdentity.Append('.');
+ textualIdentity.AppendSpanFormattable(version.Revision);
+ }
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_CULTURE) != 0)
+ {
+ textualIdentity.Append(", Culture=");
+ AppendStringEscaped(ref textualIdentity, pAssemblyIdentity.NormalizedCulture);
+ }
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY) != 0)
+ {
+ textualIdentity.Append(", PublicKey=");
+ AppendBinary(ref textualIdentity, pAssemblyIdentity.PublicKeyOrTokenBLOB);
+ }
+ else if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN) != 0)
+ {
+ textualIdentity.Append(", PublicKeyToken=");
+ AppendBinary(ref textualIdentity, pAssemblyIdentity.PublicKeyOrTokenBLOB);
+ }
+ else if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL) != 0)
+ {
+ textualIdentity.Append(", PublicKeyToken=null");
+ }
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_PROCESSOR_ARCHITECTURE) != 0)
+ {
+ textualIdentity.Append(", processorArchitecture=");
+ textualIdentity.Append(pAssemblyIdentity.ProcessorArchitecture switch
+ {
+ PEKind.I386 => "x86",
+ PEKind.IA64 => "IA64",
+ PEKind.AMD64 => "AMD64",
+ PEKind.ARM => "ARM",
+ PEKind.MSIL => "MSIL",
+ _ => throw new UnreachableException()
+ });
+ }
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_RETARGETABLE) != 0)
+ {
+ textualIdentity.Append(", Retargetable=Yes");
+ }
+
+ if ((includeFlags & AssemblyIdentityFlags.IDENTITY_FLAG_CONTENT_TYPE) != 0)
+ {
+ textualIdentity.Append($", ContentType={nameof(AssemblyContentType.WindowsRuntime)}");
+ }
+
+ return textualIdentity.ToString();
+ }
+
+ private static void AppendStringEscaped(ref ValueStringBuilder vsb, string input)
+ {
+ Debug.Assert(input.Length > 0);
+
+ bool fNeedQuotes = (input[0] is '\n' or '\r' or ' ' or '\t')
+ || (input[^1] is '\n' or '\r' or ' ' or '\t');
+ char quoteCharacter = '\"';
+
+ ValueStringBuilder tmpString = new ValueStringBuilder(stackalloc char[256]);
+
+ // Fusion textual identity compat: escape all non-quote characters even if quoted
+ foreach (char ch in input)
+ {
+ switch (ch)
+ {
+ case '\"':
+ case '\'':
+ if (fNeedQuotes && (quoteCharacter != ch))
+ {
+ tmpString.Append(ch);
+ }
+ else if (!fNeedQuotes)
+ {
+ fNeedQuotes = true;
+ quoteCharacter = (ch == '\"') ? '\'' : '\"';
+ tmpString.Append(ch);
+ }
+ else
+ {
+ tmpString.Append('\\');
+ tmpString.Append(ch);
+ }
+ break;
+
+ case '=':
+ case ',':
+ case '\\':
+ tmpString.Append('\\');
+ tmpString.Append(ch);
+ break;
+
+ case (char)9:
+ tmpString.Append("\\t");
+ break;
+
+ case (char)10:
+ tmpString.Append("\\n");
+ break;
+
+ case (char)13:
+ tmpString.Append("\\r");
+ break;
+
+ default:
+ tmpString.Append(ch);
+ break;
+ }
+ }
+
+ if (fNeedQuotes)
+ {
+ vsb.Append(quoteCharacter);
+ vsb.Append(tmpString.AsSpan());
+ vsb.Append(quoteCharacter);
+ }
+ else
+ {
+ vsb.Append(tmpString.AsSpan());
+ }
+
+ tmpString.Dispose();
+ }
+
+ private static void AppendBinary(ref ValueStringBuilder vsb, ReadOnlySpan data)
+ {
+ vsb.EnsureCapacity(vsb.Length + data.Length * 2);
+ HexConverter.EncodeToUtf16(data, vsb.RawChars[vsb.Length..], HexConverter.Casing.Lower);
+ vsb.Length += data.Length * 2;
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Tracing/ResolutionAttemptedOperation.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Tracing/ResolutionAttemptedOperation.cs
new file mode 100644
index 0000000000000..bcecf1199aca2
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/Tracing/ResolutionAttemptedOperation.cs
@@ -0,0 +1,238 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+
+namespace System.Runtime.Loader.Tracing
+{
+ // This must match the ResolutionAttemptedStage value map in ClrEtwAll.man
+ internal enum Stage : ushort
+ {
+ FindInLoadContext = 0,
+ AssemblyLoadContextLoad = 1,
+ ApplicationAssemblies = 2,
+ DefaultAssemblyLoadContextFallback = 3,
+ ResolveSatelliteAssembly = 4,
+ AssemblyLoadContextResolvingEvent = 5,
+ AppDomainAssemblyResolveEvent = 6,
+ NotYetStarted = 0xffff, // Used as flag to not fire event; not present in value map
+ };
+
+ // This must match the ResolutionAttemptedResult value map in ClrEtwAll.man
+ internal enum Result : ushort
+ {
+ Success = 0,
+ AssemblyNotFound = 1,
+ IncompatibleVersion = 2,
+ MismatchedAssemblyName = 3,
+ Failure = 4,
+ Exception = 5,
+ };
+
+ // An object of this class manages firing events for all the stages during a binder resolving
+ // attempt operation. It has minimal cost if tracing for this event is disabled.
+ //
+ // This class should be declared in the stack. As information is determined by each stage
+ // (e.g. an AssemblySpec is initialized), the appropriate Set*() method should be called. All
+ // pointers held by an object of this class must either be a nullptr, or point to a valid
+ // object during the time it is in scope.
+ //
+ // As the resolution progresses to different stages, the GoToStage() method should be called.
+ // Calling it will fire an event for the previous stage with whatever context the class had
+ // at that point; it is assumed that if GoToStage() is called, the previous stage failed
+ // (the HRESULT is read by the dtor to assess success).
+ //
+ // It holds a reference to a HRESULT (that must be live during the lifetime of this object),
+ // which is used to determine the success or failure of a stage either at the moment this
+ // class is destructed (e.g. last stage), or when moving from one stage to another. (This
+ // is especially useful if the HRESULT is captured from an exception handler.)
+ internal ref struct ResolutionAttemptedOperation
+ {
+ private ref readonly int _hr;
+ private Stage _stage;
+ private bool _tracingEnabled;
+ private BinderAssemblyName? _assemblyNameObject;
+ private BinderAssembly? _foundAssembly;
+ private string _assemblyName = string.Empty;
+ private string _assemblyLoadContextName = string.Empty;
+ private string? _exceptionMessage;
+
+ public ResolutionAttemptedOperation(BinderAssemblyName? assemblyName, AssemblyLoadContext binder, ref int hResult)
+ {
+ _hr = ref hResult;
+ _stage = Stage.NotYetStarted;
+ _tracingEnabled = AssemblyLoadContext.IsTracingEnabled();
+ _assemblyNameObject = assemblyName;
+
+ if (!_tracingEnabled)
+ return;
+
+ // When binding the main assembly (by code base instead of name), the assembly name will be null. In this special case, we just
+ // leave the assembly name empty.
+ if (_assemblyNameObject != null)
+ _assemblyName = _assemblyNameObject.GetDisplayName(AssemblyNameIncludeFlags.INCLUDE_VERSION | AssemblyNameIncludeFlags.INCLUDE_PUBLIC_KEY_TOKEN);
+
+ _assemblyLoadContextName = (binder == AssemblyLoadContext.Default ? "Default" : binder.ToString());
+ }
+
+ public void TraceBindResult(in BindResult bindResult, bool mvidMismatch = false)
+ {
+ if (!_tracingEnabled)
+ return;
+
+ string? errorMsg = null;
+
+ // Use the error message that would be reported in the file load exception
+ if (mvidMismatch)
+ {
+ errorMsg = SR.Format(SR.EE_FileLoad_Error_Generic, _assemblyName, SR.Host_AssemblyResolver_AssemblyAlreadyLoadedInContext);
+ }
+
+ BindResult.AttemptResult inContextAttempt = bindResult.GetAttemptResult(isInContext: true);
+ BindResult.AttemptResult appAssembliesAttempt = bindResult.GetAttemptResult(isInContext: false);
+
+ if (inContextAttempt.Attempted)
+ {
+ // If there the attempt HR represents a success, but the tracked HR represents a failure (e.g. from further validation), report the failed HR
+ bool isLastAttempt = !appAssembliesAttempt.Attempted;
+ TraceStage(Stage.FindInLoadContext,
+ isLastAttempt && (_hr < 0) && (inContextAttempt.HResult >= 0) ? _hr : inContextAttempt.HResult,
+ inContextAttempt.Assembly,
+ mvidMismatch && isLastAttempt ? errorMsg : null);
+ }
+
+ if (appAssembliesAttempt.Attempted)
+ {
+ TraceStage(Stage.ApplicationAssemblies,
+ (_hr < 0) && (appAssembliesAttempt.HResult >= 0) ? _hr : appAssembliesAttempt.HResult,
+ appAssembliesAttempt.Assembly,
+ mvidMismatch ? errorMsg : null);
+ }
+ }
+
+ public void SetFoundAssembly(BinderAssembly assembly) => _foundAssembly = assembly;
+
+ public void GoToStage(Stage stage)
+ {
+ Debug.Assert(stage != _stage);
+ Debug.Assert(stage != Stage.NotYetStarted);
+
+ if (!_tracingEnabled)
+ return;
+
+ // Going to a different stage should only happen if the current
+ // stage failed (or if the binding process wasn't yet started).
+ // Firing the event at this point not only helps timing each binding
+ // stage, but avoids keeping track of which stages were reached to
+ // resolve the assembly.
+ TraceStage(_stage, _hr, _foundAssembly);
+ _stage = stage;
+ _exceptionMessage = string.Empty;
+ }
+
+ public void SetException(Exception ex)
+ {
+ if (!_tracingEnabled)
+ return;
+
+ _exceptionMessage = ex.Message;
+ }
+
+ // FEATURE_EVENT_TRACE
+ public void Dispose()
+ {
+ if (!_tracingEnabled)
+ return;
+
+ TraceStage(_stage, _hr, _foundAssembly);
+ }
+
+ private unsafe void TraceStage(Stage stage, int hResult, BinderAssembly? resultAssembly, string? customError = null)
+ {
+ if (!_tracingEnabled || stage == Stage.NotYetStarted)
+ return;
+
+ string resultAssemblyName = string.Empty;
+ string resultAssemblyPath = string.Empty;
+
+ if (resultAssembly != null)
+ {
+ resultAssemblyName = resultAssembly.AssemblyName.GetDisplayName(AssemblyNameIncludeFlags.INCLUDE_VERSION | AssemblyNameIncludeFlags.INCLUDE_PUBLIC_KEY_TOKEN);
+ resultAssemblyPath = new string(AssemblyBinderCommon.PEImage_GetPath(resultAssembly.PEImage));
+ }
+
+ Result result;
+ string errorMsg;
+ if (customError != null)
+ {
+ errorMsg = customError;
+ result = Result.Failure;
+ }
+ else if (!string.IsNullOrEmpty(_exceptionMessage))
+ {
+ errorMsg = _exceptionMessage;
+ result = Result.Exception;
+ }
+ else
+ {
+ switch (hResult)
+ {
+ case HResults.S_FALSE:
+ case HResults.COR_E_FILENOTFOUND:
+ result = Result.AssemblyNotFound;
+ errorMsg = "Could not locate assembly";
+ break;
+
+ case AssemblyBinderCommon.FUSION_E_APP_DOMAIN_LOCKED:
+ result = Result.IncompatibleVersion;
+ errorMsg = "Requested version";
+
+ if (_assemblyNameObject != null)
+ {
+ AssemblyVersion version = _assemblyNameObject.Version;
+ errorMsg += $" {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
+ }
+
+ if (resultAssembly != null)
+ {
+ AssemblyVersion version = resultAssembly.AssemblyName.Version;
+ errorMsg += $" is incompatible with found version {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
+ }
+
+ break;
+
+ case HResults.FUSION_E_REF_DEF_MISMATCH:
+ result = Result.MismatchedAssemblyName;
+ errorMsg = $"Requested assembly name ':{_assemblyName}' does not match found assembly name";
+
+ if (resultAssembly != null)
+ {
+ errorMsg += $" '{resultAssemblyName}'";
+ }
+
+ break;
+
+ case >= 0: // SUCCEEDED(hr)
+ result = Result.Success;
+ Debug.Assert(resultAssembly != null);
+ errorMsg = string.Empty;
+ break;
+
+ default:
+ result = Result.Failure;
+ errorMsg = $"Resolution failed with HRESULT ({_hr:x8})";
+ break;
+ }
+ }
+
+ AssemblyLoadContext.TraceResolutionAttempted(
+ _assemblyName,
+ stage,
+ _assemblyLoadContextName,
+ result,
+ resultAssemblyName,
+ resultAssemblyPath,
+ errorMsg);
+ }
+ }
+}
diff --git a/src/coreclr/binder/CMakeLists.txt b/src/coreclr/binder/CMakeLists.txt
index f52dcb6bb44ef..0856a1b3985a0 100644
--- a/src/coreclr/binder/CMakeLists.txt
+++ b/src/coreclr/binder/CMakeLists.txt
@@ -4,24 +4,15 @@ include_directories(BEFORE "../vm")
include_directories(BEFORE "inc")
set(BINDER_COMMON_SOURCES
- applicationcontext.cpp
- assembly.cpp
assemblybindercommon.cpp
assemblyname.cpp
bindertracing.cpp
- defaultassemblybinder.cpp
- failurecache.cpp
textualidentityparser.cpp
utils.cpp
)
set(BINDER_COMMON_HEADERS
- inc/applicationcontext.hpp
- inc/applicationcontext.inl
- inc/assembly.hpp
- inc/assembly.inl
inc/assemblybindercommon.hpp
- inc/assemblyhashtraits.hpp
inc/assemblyidentity.hpp
inc/assemblyname.hpp
inc/assemblyname.inl
@@ -29,11 +20,7 @@ set(BINDER_COMMON_HEADERS
inc/assemblyversion.inl
inc/bindertypes.hpp
inc/bindertracing.h
- inc/bindresult.hpp
- inc/bindresult.inl
inc/defaultassemblybinder.h
- inc/failurecache.hpp
- inc/failurecachehashtraits.hpp
inc/textualidentityparser.hpp
inc/utils.hpp
)
diff --git a/src/coreclr/binder/applicationcontext.cpp b/src/coreclr/binder/applicationcontext.cpp
deleted file mode 100644
index e41b504c8feb6..0000000000000
--- a/src/coreclr/binder/applicationcontext.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// ApplicationContext.cpp
-//
-
-
-//
-// Implements the ApplicationContext class
-//
-// ============================================================
-
-#include "applicationcontext.hpp"
-#include "assemblyhashtraits.hpp"
-#include "stringarraylist.h"
-#include "failurecache.hpp"
-#include "utils.hpp"
-#include "ex.h"
-#include "clr/fs/path.h"
-using namespace clr::fs;
-
-namespace BINDER_SPACE
-{
- ApplicationContext::ApplicationContext()
- {
- m_pExecutionContext = NULL;
- m_pFailureCache = NULL;
- m_contextCS = NULL;
- m_pTrustedPlatformAssemblyMap = nullptr;
- }
-
- ApplicationContext::~ApplicationContext()
- {
- SAFE_DELETE(m_pExecutionContext);
- SAFE_DELETE(m_pFailureCache);
-
- if (m_contextCS != NULL)
- {
- ClrDeleteCriticalSection(m_contextCS);
- }
-
- if (m_pTrustedPlatformAssemblyMap != nullptr)
- {
- delete m_pTrustedPlatformAssemblyMap;
- }
- }
-
- HRESULT ApplicationContext::Init()
- {
- HRESULT hr = S_OK;
-
- NewHolder pExecutionContext;
-
- FailureCache *pFailureCache = NULL;
-
- // Allocate context objects
- SAFE_NEW(pExecutionContext, ExecutionContext);
-
- SAFE_NEW(pFailureCache, FailureCache);
-
- m_contextCS = ClrCreateCriticalSection(
- CrstFusionAppCtx,
- CRST_REENTRANCY);
- if (!m_contextCS)
- {
- SAFE_DELETE(pFailureCache);
- hr = E_OUTOFMEMORY;
- }
- else
- {
- m_pExecutionContext = pExecutionContext.Extract();
-
- m_pFailureCache = pFailureCache;
- }
-
- Exit:
- return hr;
- }
-
- HRESULT ApplicationContext::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
- SString &sPlatformResourceRoots,
- SString &sAppPaths,
- BOOL fAcquireLock)
- {
- HRESULT hr = S_OK;
-
- CRITSEC_Holder contextLock(fAcquireLock ? GetCriticalSectionCookie() : NULL);
- if (m_pTrustedPlatformAssemblyMap != nullptr)
- {
- GO_WITH_HRESULT(S_OK);
- }
-
- //
- // Parse TrustedPlatformAssemblies
- //
- m_pTrustedPlatformAssemblyMap = new SimpleNameToFileNameMap();
-
- sTrustedPlatformAssemblies.Normalize();
-
- for (SString::Iterator i = sTrustedPlatformAssemblies.Begin(); i != sTrustedPlatformAssemblies.End(); )
- {
- SString fileName;
- SString simpleName;
- bool isNativeImage = false;
- HRESULT pathResult = S_OK;
- IF_FAIL_GO(pathResult = GetNextTPAPath(sTrustedPlatformAssemblies, i, /*dllOnly*/ false, fileName, simpleName, isNativeImage));
- if (pathResult == S_FALSE)
- {
- break;
- }
-
- const SimpleNameToFileNameMapEntry *pExistingEntry = m_pTrustedPlatformAssemblyMap->LookupPtr(simpleName.GetUnicode());
-
- if (pExistingEntry != nullptr)
- {
- //
- // We want to store only the first entry matching a simple name we encounter.
- // The exception is if we first store an IL reference and later in the string
- // we encounter a native image. Since we don't touch IL in the presence of
- // native images, we replace the IL entry with the NI.
- //
- if ((pExistingEntry->m_wszILFileName != nullptr && !isNativeImage) ||
- (pExistingEntry->m_wszNIFileName != nullptr && isNativeImage))
- {
- continue;
- }
- }
-
- LPWSTR wszSimpleName = nullptr;
- if (pExistingEntry == nullptr)
- {
- wszSimpleName = new WCHAR[simpleName.GetCount() + 1];
- if (wszSimpleName == nullptr)
- {
- GO_WITH_HRESULT(E_OUTOFMEMORY);
- }
- wcscpy_s(wszSimpleName, simpleName.GetCount() + 1, simpleName.GetUnicode());
- }
- else
- {
- wszSimpleName = pExistingEntry->m_wszSimpleName;
- }
-
- LPWSTR wszFileName = new WCHAR[fileName.GetCount() + 1];
- if (wszFileName == nullptr)
- {
- GO_WITH_HRESULT(E_OUTOFMEMORY);
- }
- wcscpy_s(wszFileName, fileName.GetCount() + 1, fileName.GetUnicode());
-
- SimpleNameToFileNameMapEntry mapEntry;
- mapEntry.m_wszSimpleName = wszSimpleName;
- if (isNativeImage)
- {
- mapEntry.m_wszNIFileName = wszFileName;
- mapEntry.m_wszILFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszILFileName;
- }
- else
- {
- mapEntry.m_wszILFileName = wszFileName;
- mapEntry.m_wszNIFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszNIFileName;
- }
-
- m_pTrustedPlatformAssemblyMap->AddOrReplace(mapEntry);
- }
-
- //
- // Parse PlatformResourceRoots
- //
- sPlatformResourceRoots.Normalize();
- for (SString::Iterator i = sPlatformResourceRoots.Begin(); i != sPlatformResourceRoots.End(); )
- {
- SString pathName;
- HRESULT pathResult = S_OK;
-
- IF_FAIL_GO(pathResult = GetNextPath(sPlatformResourceRoots, i, pathName));
- if (pathResult == S_FALSE)
- {
- break;
- }
-
- if (Path::IsRelative(pathName))
- {
- GO_WITH_HRESULT(E_INVALIDARG);
- }
-
- m_platformResourceRoots.Append(pathName);
- }
-
- //
- // Parse AppPaths
- //
- sAppPaths.Normalize();
- for (SString::Iterator i = sAppPaths.Begin(); i != sAppPaths.End(); )
- {
- SString pathName;
- HRESULT pathResult = S_OK;
-
- IF_FAIL_GO(pathResult = GetNextPath(sAppPaths, i, pathName));
- if (pathResult == S_FALSE)
- {
- break;
- }
-
- if (Path::IsRelative(pathName))
- {
- GO_WITH_HRESULT(E_INVALIDARG);
- }
-
- m_appPaths.Append(pathName);
- }
-
- Exit:
- return hr;
- }
-
- bool ApplicationContext::IsTpaListProvided()
- {
- return m_pTrustedPlatformAssemblyMap != nullptr;
- }
-};
diff --git a/src/coreclr/binder/assembly.cpp b/src/coreclr/binder/assembly.cpp
deleted file mode 100644
index 9348c7b67e4e8..0000000000000
--- a/src/coreclr/binder/assembly.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// Assembly.cpp
-//
-
-
-//
-// Implements the Assembly class
-//
-// ============================================================
-#include "common.h"
-#include "assembly.hpp"
-#include "utils.hpp"
-#include "assemblybindercommon.hpp"
-
-namespace BINDER_SPACE
-{
- Assembly::Assembly()
- {
- m_cRef = 1;
- m_pPEImage = NULL;
- m_pAssemblyName = NULL;
- m_isInTPA = false;
- m_pBinder = NULL;
- m_domainAssembly = NULL;
- }
-
- Assembly::~Assembly()
- {
- SAFE_RELEASE(m_pPEImage);
- SAFE_RELEASE(m_pAssemblyName);
- }
-
- HRESULT Assembly::Init(PEImage *pPEImage, BOOL fIsInTPA)
- {
- HRESULT hr = S_OK;
-
- ReleaseHolder pAssemblyName;
- SAFE_NEW(pAssemblyName, AssemblyName);
-
- // Get assembly name def from meta data import and store it for later refs access
- IF_FAIL_GO(pAssemblyName->Init(pPEImage));
- pAssemblyName->SetIsDefinition(TRUE);
-
- // validate architecture
- if (!AssemblyBinderCommon::IsValidArchitecture(pAssemblyName->GetArchitecture()))
- {
- // Assembly image can't be executed on this platform
- IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
- }
-
- m_isInTPA = fIsInTPA;
-
- pPEImage->AddRef();
- m_pPEImage = pPEImage;
-
- // Now take ownership of assembly name
- m_pAssemblyName = pAssemblyName.Extract();
-
- Exit:
- return hr;
- }
-
- PEImage* Assembly::GetPEImage()
- {
- return m_pPEImage;
- }
-
- LPCWSTR Assembly::GetSimpleName()
- {
- AssemblyName *pAsmName = GetAssemblyName();
- return (pAsmName == nullptr ? nullptr : (LPCWSTR)pAsmName->GetSimpleName());
- }
-}
-
diff --git a/src/coreclr/binder/assemblybindercommon.cpp b/src/coreclr/binder/assemblybindercommon.cpp
index e1de7af70677e..1caae65b2a3c7 100644
--- a/src/coreclr/binder/assemblybindercommon.cpp
+++ b/src/coreclr/binder/assemblybindercommon.cpp
@@ -15,24 +15,13 @@
#include "assemblybindercommon.hpp"
#include "assemblyname.hpp"
#include "assembly.hpp"
-#include "applicationcontext.hpp"
-#include "assemblyhashtraits.hpp"
#include "bindertracing.h"
-#include "bindresult.inl"
-#include "failurecache.hpp"
#include "utils.hpp"
#include "stringarraylist.h"
#include "configuration.h"
#if !defined(DACCESS_COMPILE)
#include "defaultassemblybinder.h"
-// Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver
-extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin,
- BINDER_SPACE::AssemblyName *pAssemblyName,
- DefaultAssemblyBinder *pDefaultBinder,
- AssemblyBinder *pBinder,
- BINDER_SPACE::Assembly **ppLoadedAssembly);
-
#endif // !defined(DACCESS_COMPILE)
STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath,
@@ -41,89 +30,6 @@ STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath,
namespace BINDER_SPACE
{
- namespace
- {
- //
- // This defines the assembly equivalence relation
- //
- bool IsCompatibleAssemblyVersion(/* in */ AssemblyName *pRequestedName,
- /* in */ AssemblyName *pFoundName)
- {
- AssemblyVersion *pRequestedVersion = pRequestedName->GetVersion();
- AssemblyVersion *pFoundVersion = pFoundName->GetVersion();
-
- if (!pRequestedVersion->HasMajor())
- {
- // An unspecified requested version component matches any value for the same component in the found version,
- // regardless of lesser-order version components
- return true;
- }
- if (!pFoundVersion->HasMajor() || pRequestedVersion->GetMajor() > pFoundVersion->GetMajor())
- {
- // - A specific requested version component does not match an unspecified value for the same component in
- // the found version, regardless of lesser-order version components
- // - Or, the requested version is greater than the found version
- return false;
- }
- if (pRequestedVersion->GetMajor() < pFoundVersion->GetMajor())
- {
- // The requested version is less than the found version
- return true;
- }
-
- if (!pRequestedVersion->HasMinor())
- {
- return true;
- }
- if (!pFoundVersion->HasMinor() || pRequestedVersion->GetMinor() > pFoundVersion->GetMinor())
- {
- return false;
- }
- if (pRequestedVersion->GetMinor() < pFoundVersion->GetMinor())
- {
- return true;
- }
-
- if (!pRequestedVersion->HasBuild())
- {
- return true;
- }
- if (!pFoundVersion->HasBuild() || pRequestedVersion->GetBuild() > pFoundVersion->GetBuild())
- {
- return false;
- }
- if (pRequestedVersion->GetBuild() < pFoundVersion->GetBuild())
- {
- return true;
- }
-
- if (!pRequestedVersion->HasRevision())
- {
- return true;
- }
- if (!pFoundVersion->HasRevision() || pRequestedVersion->GetRevision() > pFoundVersion->GetRevision())
- {
- return false;
- }
- return true;
- }
-
- HRESULT CreateImageAssembly(PEImage *pPEImage,
- BindResult *pBindResult)
- {
- HRESULT hr = S_OK;
- ReleaseHolder pAssembly;
-
- SAFE_NEW(pAssembly, Assembly);
- IF_FAIL_GO(pAssembly->Init(pPEImage, /* fIsInTPA */ FALSE ));
-
- pBindResult->SetResult(pAssembly);
-
- Exit:
- return hr;
- }
- };
-
HRESULT AssemblyBinderCommon::TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind)
{
HRESULT hr = S_OK;
@@ -188,76 +94,16 @@ namespace BINDER_SPACE
Exit:
return hr;
}
-
- HRESULT AssemblyBinderCommon::BindAssembly(/* in */ AssemblyBinder *pBinder,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ bool excludeAppPaths,
- /* out */ Assembly **ppAssembly)
- {
- HRESULT hr = S_OK;
- LONG kContextVersion = 0;
- BindResult bindResult;
- ApplicationContext* pApplicationContext = pBinder->GetAppContext();
-
- // Tracing happens outside the binder lock to avoid calling into managed code within the lock
- BinderTracing::ResolutionAttemptedOperation tracer{pAssemblyName, pBinder, 0 /*managedALC*/, hr};
-
- Retry:
- {
- // Lock the binding application context
- CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
-
- _ASSERTE(pAssemblyName != NULL);
- IF_FAIL_GO(BindByName(pApplicationContext,
- pAssemblyName,
- false, // skipFailureCaching
- false, // skipVersionCompatibilityCheck
- excludeAppPaths,
- &bindResult));
-
- // Remember the post-bind version
- kContextVersion = pApplicationContext->GetVersion();
-
- } // lock(pApplicationContext)
-
- Exit:
- tracer.TraceBindResult(bindResult);
-
- if (bindResult.HaveResult())
- {
- BindResult hostBindResult;
-
- hr = RegisterAndGetHostChosen(pApplicationContext,
- kContextVersion,
- &bindResult,
- &hostBindResult);
-
- if (hr == S_FALSE)
- {
- // Another bind interfered. We need to retry the entire bind.
- // This by design loops as long as needed because by construction we eventually
- // will succeed or fail the bind.
- bindResult.Reset();
- goto Retry;
- }
- else if (hr == S_OK)
- {
- *ppAssembly = hostBindResult.GetAssembly(TRUE /* fAddRef */);
- }
- }
-
- return hr;
- }
-
+
/* static */
HRESULT AssemblyBinderCommon::BindToSystem(SString &systemDirectory,
- Assembly **ppSystemAssembly)
+ PEImage **ppPEImage)
{
HRESULT hr = S_OK;
- _ASSERTE(ppSystemAssembly != NULL);
+ _ASSERTE(ppPEImage != NULL);
- ReleaseHolder pSystemAssembly;
+ ReleaseHolder pSystemAssembly;
// System.Private.CoreLib.dll is expected to be found at one of the following locations:
// * Non-single-file app: In systemDirectory, beside coreclr.dll
@@ -279,14 +125,11 @@ namespace BINDER_SPACE
sCoreLib.Set(systemDirectory);
CombinePath(sCoreLib, sCoreLibName, sCoreLib);
- hr = AssemblyBinderCommon::GetAssembly(sCoreLib,
- TRUE /* fIsInTPA */,
- &pSystemAssembly,
- bundleFileLocation);
+ hr = BinderAcquirePEImage(sCoreLib.GetUnicode(), &pSystemAssembly, bundleFileLocation);
BinderTracing::PathProbed(sCoreLib, pathSource, hr);
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ if ((FAILED(hr)) && IsFileNotFound(hr))
{
// Try to find corelib in the TPA
StackSString sCoreLibSimpleName(CoreLibName_W);
@@ -318,971 +161,21 @@ namespace BINDER_SPACE
{
GO_WITH_HRESULT(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
}
-
- hr = AssemblyBinderCommon::GetAssembly(sCoreLib,
- TRUE /* fIsInTPA */,
- &pSystemAssembly,
- bundleFileLocation);
+
+ hr = BinderAcquirePEImage(sCoreLib.GetUnicode(), &pSystemAssembly, bundleFileLocation);
BinderTracing::PathProbed(sCoreLib, BinderTracing::PathSource::ApplicationAssemblies, hr);
}
IF_FAIL_GO(hr);
- *ppSystemAssembly = pSystemAssembly.Extract();
-
- Exit:
- return hr;
- }
-
-
- /* static */
- HRESULT AssemblyBinderCommon::BindToSystemSatellite(SString& systemDirectory,
- SString& simpleName,
- SString& cultureName,
- Assembly** ppSystemAssembly)
- {
- HRESULT hr = S_OK;
-
- _ASSERTE(ppSystemAssembly != NULL);
-
- // Satellite assembly's relative path
- StackSString relativePath;
-
- // append culture name
- if (!cultureName.IsEmpty())
- {
- CombinePath(relativePath, cultureName, relativePath);
- }
-
- // append satellite assembly's simple name
- CombinePath(relativePath, simpleName, relativePath);
-
- // append extension
- relativePath.Append(W(".dll"));
-
- // Satellite assembly's path:
- // * Absolute path when looking for a file on disk
- // * Bundle-relative path when looking within the single-file bundle.
- StackSString sCoreLibSatellite;
-
- BinderTracing::PathSource pathSource = BinderTracing::PathSource::Bundle;
- BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /*pathIsBundleRelative */ true);
- if (!bundleFileLocation.IsValid())
- {
- sCoreLibSatellite.Set(systemDirectory);
- pathSource = BinderTracing::PathSource::ApplicationAssemblies;
- }
- CombinePath(sCoreLibSatellite, relativePath, sCoreLibSatellite);
-
- ReleaseHolder pSystemAssembly;
- IF_FAIL_GO(AssemblyBinderCommon::GetAssembly(sCoreLibSatellite,
- TRUE /* fIsInTPA */,
- &pSystemAssembly,
- bundleFileLocation));
- BinderTracing::PathProbed(sCoreLibSatellite, pathSource, hr);
-
- *ppSystemAssembly = pSystemAssembly.Extract();
-
- Exit:
- return hr;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::BindByName(ApplicationContext *pApplicationContext,
- AssemblyName *pAssemblyName,
- bool skipFailureCaching,
- bool skipVersionCompatibilityCheck,
- bool excludeAppPaths,
- BindResult *pBindResult)
- {
- HRESULT hr = S_OK;
- PathString assemblyDisplayName;
-
- // Look for already cached binding failure (ignore PA, every PA will lock the context)
- pAssemblyName->GetDisplayName(assemblyDisplayName,
- AssemblyName::INCLUDE_VERSION);
-
- hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
- if (FAILED(hr))
- {
- if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) && skipFailureCaching)
- {
- // Ignore pre-existing transient bind error (re-bind will succeed)
- pApplicationContext->GetFailureCache()->Remove(assemblyDisplayName);
- }
-
- goto LogExit;
- }
- else if (hr == S_FALSE)
- {
- // workaround: Special case for byte arrays. Rerun the bind to create binding log.
- pAssemblyName->SetIsDefinition(TRUE);
- hr = S_OK;
- }
-
- if (!IsValidArchitecture(pAssemblyName->GetArchitecture()))
- {
- // Assembly reference contains wrong architecture
- IF_FAIL_GO(FUSION_E_INVALID_NAME);
- }
-
- IF_FAIL_GO(BindLocked(pApplicationContext,
- pAssemblyName,
- skipVersionCompatibilityCheck,
- excludeAppPaths,
- pBindResult));
-
- if (!pBindResult->HaveResult())
- {
- // Behavior rules are clueless now
- IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
- }
-
- Exit:
- if (FAILED(hr))
- {
- if (skipFailureCaching)
- {
- if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- // Cache non-transient bind error for byte-array
- hr = S_FALSE;
- }
- else
- {
- // Ignore transient bind error (re-bind will succeed)
- goto LogExit;
- }
- }
-
- hr = pApplicationContext->AddToFailureCache(assemblyDisplayName, hr);
- }
-
- LogExit:
- return hr;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::BindLocked(ApplicationContext *pApplicationContext,
- AssemblyName *pAssemblyName,
- bool skipVersionCompatibilityCheck,
- bool excludeAppPaths,
- BindResult *pBindResult)
- {
- HRESULT hr = S_OK;
-
- bool isTpaListProvided = pApplicationContext->IsTpaListProvided();
- Assembly *pAssembly = NULL;
- hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pAssembly);
-
- // Add the attempt to the bind result on failure / not found. On success, it will be added after the version check.
- if (FAILED(hr) || pAssembly == NULL)
- pBindResult->SetAttemptResult(hr, pAssembly, /*isInContext*/ true);
-
- IF_FAIL_GO(hr);
- if (pAssembly != NULL)
- {
- if (!skipVersionCompatibilityCheck)
- {
- // Can't give higher version than already bound
- bool isCompatible = IsCompatibleAssemblyVersion(pAssemblyName, pAssembly->GetAssemblyName());
- hr = isCompatible ? S_OK : FUSION_E_APP_DOMAIN_LOCKED;
- pBindResult->SetAttemptResult(hr, pAssembly, /*isInContext*/ true);
-
- // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
- if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided)
- hr = FUSION_E_REF_DEF_MISMATCH;
- }
- else
- {
- pBindResult->SetAttemptResult(hr, pAssembly, /*isInContext*/ true);
- }
-
- IF_FAIL_GO(hr);
-
- pBindResult->SetResult(pAssembly, /*isInContext*/ true);
- }
- else
- if (isTpaListProvided)
- {
- // BindByTpaList handles setting attempt results on the bind result
- hr = BindByTpaList(pApplicationContext,
- pAssemblyName,
- excludeAppPaths,
- pBindResult);
- if (SUCCEEDED(hr) && pBindResult->HaveResult())
- {
- bool isCompatible = IsCompatibleAssemblyVersion(pAssemblyName, pBindResult->GetAssemblyName());
- hr = isCompatible ? S_OK : FUSION_E_APP_DOMAIN_LOCKED;
- pBindResult->SetAttemptResult(hr, pBindResult->GetAssembly());
-
- // TPA binder returns FUSION_E_REF_DEF_MISMATCH for incompatible version
- if (hr == FUSION_E_APP_DOMAIN_LOCKED && isTpaListProvided)
- hr = FUSION_E_REF_DEF_MISMATCH;
- }
-
- if (FAILED(hr))
- {
- pBindResult->SetNoResult();
- }
- IF_FAIL_GO(hr);
- }
- Exit:
- return hr;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::FindInExecutionContext(ApplicationContext *pApplicationContext,
- AssemblyName *pAssemblyName,
- Assembly **ppAssembly)
- {
- _ASSERTE(pApplicationContext != NULL);
- _ASSERTE(pAssemblyName != NULL);
- _ASSERTE(ppAssembly != NULL);
-
- ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
- Assembly *pAssembly = pExecutionContext->Lookup(pAssemblyName);
-
- // Set any found context entry. It is up to the caller to check the returned HRESULT
- // for errors due to validation
- *ppAssembly = pAssembly;
- if (pAssembly == NULL)
- return S_FALSE;
-
- AssemblyName *pContextName = pAssembly->GetAssemblyName();
- if (pAssemblyName->GetIsDefinition() &&
- (pContextName->GetArchitecture() != pAssemblyName->GetArchitecture()))
- {
- return FUSION_E_APP_DOMAIN_LOCKED;
- }
-
- return S_OK;
- }
-
-
- //
- // Tests whether a candidate assembly's name matches the requested.
- // This does not do a version check. The binder applies version policy
- // further up the stack once it gets a successful bind.
- //
- BOOL TestCandidateRefMatchesDef(AssemblyName *pRequestedAssemblyName,
- AssemblyName *pBoundAssemblyName,
- BOOL tpaListAssembly)
- {
- DWORD dwIncludeFlags = AssemblyName::INCLUDE_DEFAULT;
-
- if (!tpaListAssembly)
- {
- if (pRequestedAssemblyName->IsNeutralCulture())
- {
- dwIncludeFlags |= AssemblyName::EXCLUDE_CULTURE;
- }
- }
-
- if (pRequestedAssemblyName->GetArchitecture() != peNone)
- {
- dwIncludeFlags |= AssemblyName::INCLUDE_ARCHITECTURE;
- }
-
- return pBoundAssemblyName->Equals(pRequestedAssemblyName, dwIncludeFlags);
- }
-
- namespace
- {
- HRESULT BindSatelliteResourceFromBundle(
- AssemblyName* pRequestedAssemblyName,
- SString &relativePath,
- BindResult* pBindResult)
- {
- HRESULT hr = S_OK;
-
- BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /* pathIsBundleRelative */ true);
- if (!bundleFileLocation.IsValid())
- {
- return hr;
- }
-
- ReleaseHolder pAssembly;
- hr = AssemblyBinderCommon::GetAssembly(relativePath,
- FALSE /* fIsInTPA */,
- &pAssembly,
- bundleFileLocation);
-
- BinderTracing::PathProbed(relativePath, BinderTracing::PathSource::Bundle, hr);
-
- // Missing files are okay and expected when probing
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- return S_OK;
- }
-
- pBindResult->SetAttemptResult(hr, pAssembly);
- if (FAILED(hr))
- return hr;
-
- AssemblyName* pBoundAssemblyName = pAssembly->GetAssemblyName();
- if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
- {
- pBindResult->SetResult(pAssembly);
- hr = S_OK;
- }
- else
- {
- hr = FUSION_E_REF_DEF_MISMATCH;
- }
-
- pBindResult->SetAttemptResult(hr, pAssembly);
- return hr;
- }
-
- HRESULT BindSatelliteResourceByProbingPaths(
- const StringArrayList *pResourceRoots,
- AssemblyName *pRequestedAssemblyName,
- SString &relativePath,
- BindResult *pBindResult,
- BinderTracing::PathSource pathSource)
- {
- HRESULT hr = S_OK;
-
- for (UINT i = 0; i < pResourceRoots->GetCount(); i++)
- {
- ReleaseHolder pAssembly;
- SString &wszBindingPath = (*pResourceRoots)[i];
- SString fileName(wszBindingPath);
- CombinePath(fileName, relativePath, fileName);
-
- hr = AssemblyBinderCommon::GetAssembly(fileName,
- FALSE /* fIsInTPA */,
- &pAssembly);
- BinderTracing::PathProbed(fileName, pathSource, hr);
-
- // Missing files are okay and expected when probing
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- continue;
- }
-
- pBindResult->SetAttemptResult(hr, pAssembly);
- if (FAILED(hr))
- return hr;
-
- AssemblyName *pBoundAssemblyName = pAssembly->GetAssemblyName();
- if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
- {
- pBindResult->SetResult(pAssembly);
- hr = S_OK;
- }
- else
- {
- hr = FUSION_E_REF_DEF_MISMATCH;
- }
-
- pBindResult->SetAttemptResult(hr, pAssembly);
- return hr;
- }
-
- // Up-stack expects S_OK when we don't find any candidate assemblies and no fatal error occurred (ie, no S_FALSE)
- return S_OK;
- }
-
- HRESULT BindSatelliteResource(
- ApplicationContext* pApplicationContext,
- AssemblyName* pRequestedAssemblyName,
- BindResult* pBindResult)
- {
- // Satellite resource probing strategy is to look:
- // * First within the single-file bundle
- // * Then under each of the Platform Resource Roots
- // * Then under each of the App Paths.
- //
- // During each search, if we find a platform resource file with matching file name, but whose ref-def didn't match,
- // fall back to application resource lookup to handle case where a user creates resources with the same
- // names as platform ones.
-
- HRESULT hr = S_OK;
- const SString& simpleNameRef = pRequestedAssemblyName->GetSimpleName();
- SString& cultureRef = pRequestedAssemblyName->GetCulture();
-
- _ASSERTE(!pRequestedAssemblyName->IsNeutralCulture());
-
- ReleaseHolder pAssembly;
- SString fileName;
- CombinePath(fileName, cultureRef, fileName);
- CombinePath(fileName, simpleNameRef, fileName);
- fileName.Append(W(".dll"));
-
- hr = BindSatelliteResourceFromBundle(pRequestedAssemblyName, fileName, pBindResult);
-
- if (pBindResult->HaveResult() || FAILED(hr))
- {
- return hr;
- }
-
- hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetPlatformResourceRoots(),
- pRequestedAssemblyName,
- fileName,
- pBindResult,
- BinderTracing::PathSource::PlatformResourceRoots);
-
- if (pBindResult->HaveResult() || FAILED(hr))
- {
- return hr;
- }
-
- hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetAppPaths(),
- pRequestedAssemblyName,
- fileName,
- pBindResult,
- BinderTracing::PathSource::AppPaths);
-
- return hr;
- }
-
- HRESULT BindAssemblyByProbingPaths(
- const StringArrayList *pBindingPaths,
- AssemblyName *pRequestedAssemblyName,
- Assembly **ppAssembly)
- {
- const SString &simpleName = pRequestedAssemblyName->GetSimpleName();
- BinderTracing::PathSource pathSource = BinderTracing::PathSource::AppPaths;
- // Loop through the binding paths looking for a matching assembly
- for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
- {
- HRESULT hr;
- ReleaseHolder pAssembly;
- LPCWSTR wszBindingPath = (*pBindingPaths)[i];
-
- PathString fileNameWithoutExtension(wszBindingPath);
- CombinePath(fileNameWithoutExtension, simpleName, fileNameWithoutExtension);
-
- // Look for a matching dll first
- PathString fileName(fileNameWithoutExtension);
- fileName.Append(W(".dll"));
- hr = AssemblyBinderCommon::GetAssembly(fileName,
- FALSE, // fIsInTPA
- &pAssembly);
- BinderTracing::PathProbed(fileName, pathSource, hr);
-
- if (FAILED(hr))
- {
- fileName.Set(fileNameWithoutExtension);
- fileName.Append(W(".exe"));
- hr = AssemblyBinderCommon::GetAssembly(fileName,
- FALSE, // fIsInTPA
- &pAssembly);
- BinderTracing::PathProbed(fileName, pathSource, hr);
- }
-
- // Since we're probing, file not founds are ok and we should just try another
- // probing path
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- continue;
- }
-
- // Set any found assembly. It is up to the caller to check the returned HRESULT for errors due to validation
- *ppAssembly = pAssembly.Extract();
- if (FAILED(hr))
- return hr;
-
- // We found a candidate.
- //
- // Below this point, we either establish that the ref-def matches, or
- // we fail the bind.
-
- // Compare requested AssemblyName with that from the candidate assembly
- if (!TestCandidateRefMatchesDef(pRequestedAssemblyName, pAssembly->GetAssemblyName(), false /*tpaListAssembly*/))
- return FUSION_E_REF_DEF_MISMATCH;
-
- return S_OK;
- }
-
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
- }
-
- /*
- * BindByTpaList is the entry-point for the custom binding algorithm in CoreCLR.
- *
- * The search for assemblies will proceed in the following order:
- *
- * If this application is a single-file bundle, the meta-data contained in the bundle
- * will be probed to find the requested assembly. If the assembly is not found,
- * The list of platform assemblies (TPAs) are considered next.
- *
- * Platform assemblies are specified as a list of files. This list is the only set of
- * assemblies that we will load as platform. They can be specified as IL or NIs.
- *
- * Resources for platform assemblies are located by probing starting at the Platform Resource Roots,
- * a set of folders configured by the host.
- *
- * If a requested assembly identity cannot be found in the TPA list or the resource roots,
- * it is considered an application assembly. We probe for application assemblies in the
- * AppPaths, a list of paths containing IL files and satellite resource folders.
- *
- */
- /* static */
- HRESULT AssemblyBinderCommon::BindByTpaList(ApplicationContext *pApplicationContext,
- AssemblyName *pRequestedAssemblyName,
- bool excludeAppPaths,
- BindResult *pBindResult)
- {
- HRESULT hr = S_OK;
-
- bool fPartialMatchOnTpa = false;
-
- if (!pRequestedAssemblyName->IsNeutralCulture())
- {
- IF_FAIL_GO(BindSatelliteResource(pApplicationContext, pRequestedAssemblyName, pBindResult));
- }
- else
- {
- ReleaseHolder pTPAAssembly;
- const SString& simpleName = pRequestedAssemblyName->GetSimpleName();
-
- // Is assembly in the bundle?
- // Single-file bundle contents take precedence over TPA.
- // The list of bundled assemblies is contained in the bundle manifest, and NOT in the TPA.
- // Therefore the bundle is first probed using the assembly's simple name.
- // If found, the assembly is loaded from the bundle.
- if (Bundle::AppIsBundle())
- {
- // Search Assembly.ni.dll, then Assembly.dll
- // The Assembly.ni.dll paths are rare, and intended for supporting managed C++ R2R assemblies.
- const WCHAR* const candidates[] = { W(".ni.dll"), W(".dll") };
-
- // Loop through the binding paths looking for a matching assembly
- for (int i = 0; i < 2; i++)
- {
- SString assemblyFileName(simpleName);
- assemblyFileName.Append(candidates[i]);
-
- SString assemblyFilePath(Bundle::AppBundle->BasePath());
- assemblyFilePath.Append(assemblyFileName);
-
- BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(assemblyFileName, /* pathIsBundleRelative */ true);
- if (bundleFileLocation.IsValid())
- {
- hr = GetAssembly(assemblyFilePath,
- TRUE, // fIsInTPA
- &pTPAAssembly,
- bundleFileLocation);
-
- BinderTracing::PathProbed(assemblyFilePath, BinderTracing::PathSource::Bundle, hr);
-
- if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- // Any other error is fatal
- IF_FAIL_GO(hr);
-
- if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
- {
- // We have found the requested assembly match in the bundle with validation of the full-qualified name.
- // Bind to it.
- pBindResult->SetResult(pTPAAssembly);
- GO_WITH_HRESULT(S_OK);
- }
- }
- }
- }
- }
-
- // Is assembly on TPA list?
- SimpleNameToFileNameMap * tpaMap = pApplicationContext->GetTpaList();
- const SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(simpleName.GetUnicode());
- if (pTpaEntry != nullptr)
- {
- if (pTpaEntry->m_wszNIFileName != nullptr)
- {
- SString fileName(pTpaEntry->m_wszNIFileName);
-
- hr = GetAssembly(fileName,
- TRUE, // fIsInTPA
- &pTPAAssembly);
- BinderTracing::PathProbed(fileName, BinderTracing::PathSource::ApplicationAssemblies, hr);
- }
- else
- {
- _ASSERTE(pTpaEntry->m_wszILFileName != nullptr);
- SString fileName(pTpaEntry->m_wszILFileName);
-
- hr = GetAssembly(fileName,
- TRUE, // fIsInTPA
- &pTPAAssembly);
- BinderTracing::PathProbed(fileName, BinderTracing::PathSource::ApplicationAssemblies, hr);
- }
-
- pBindResult->SetAttemptResult(hr, pTPAAssembly);
-
- // On file not found, simply fall back to app path probing
- if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- // Any other error is fatal
- IF_FAIL_GO(hr);
-
- if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
- {
- // We have found the requested assembly match on TPA with validation of the full-qualified name. Bind to it.
- pBindResult->SetResult(pTPAAssembly);
- pBindResult->SetAttemptResult(S_OK, pTPAAssembly);
- GO_WITH_HRESULT(S_OK);
- }
- else
- {
- // We found the assembly on TPA but it didn't match the RequestedAssembly assembly-name. In this case, lets proceed to see if we find the requested
- // assembly in the App paths.
- pBindResult->SetAttemptResult(FUSION_E_REF_DEF_MISMATCH, pTPAAssembly);
- fPartialMatchOnTpa = true;
- }
- }
-
- // We either didn't find a candidate, or the ref-def failed. Either way; fall back to app path probing.
- }
-
- if (!excludeAppPaths)
- {
- // Probe AppPaths
- ReleaseHolder pAssembly;
- hr = BindAssemblyByProbingPaths(pApplicationContext->GetAppPaths(),
- pRequestedAssemblyName,
- &pAssembly);
-
- pBindResult->SetAttemptResult(hr, pAssembly);
- if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- IF_FAIL_GO(hr);
-
- // At this point, we have found an assembly with the expected name in the App paths. If this was also found on TPA,
- // make sure that the app assembly has the same fullname (excluding version) as the TPA version. If it does, then
- // we should bind to the TPA assembly. If it does not, then bind to the app assembly since it has a different fullname than the
- // TPA assembly.
- if (fPartialMatchOnTpa)
- {
- if (TestCandidateRefMatchesDef(pAssembly->GetAssemblyName(), pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
- {
- // Fullname (SimpleName+Culture+PKT) matched for TPA and app assembly - so bind to TPA instance.
- pBindResult->SetResult(pTPAAssembly);
- pBindResult->SetAttemptResult(hr, pTPAAssembly);
- GO_WITH_HRESULT(S_OK);
- }
- else
- {
- // Fullname (SimpleName+Culture+PKT) did not match for TPA and app assembly - so bind to app instance.
- pBindResult->SetResult(pAssembly);
- GO_WITH_HRESULT(S_OK);
- }
- }
- else
- {
- // We didn't see this assembly on TPA - so simply bind to the app instance.
- pBindResult->SetResult(pAssembly);
- GO_WITH_HRESULT(S_OK);
- }
- }
- }
- }
-
- // Couldn't find a matching assembly in any of the probing paths
- // Return S_FALSE here. BindByName will interpret a successful HRESULT
- // and lack of BindResult as a failure to find a matching assembly.
- hr = S_FALSE;
-
- Exit:
- return hr;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::GetAssembly(SString &assemblyPath,
- BOOL fIsInTPA,
- Assembly **ppAssembly,
- BundleFileLocation bundleFileLocation)
- {
- HRESULT hr = S_OK;
-
- _ASSERTE(ppAssembly != NULL);
-
- ReleaseHolder pAssembly;
- PEImage *pPEImage = NULL;
-
- // Allocate assembly object
- SAFE_NEW(pAssembly, Assembly);
-
- // Obtain assembly meta data
- {
- LPCTSTR szAssemblyPath = const_cast(assemblyPath.GetUnicode());
-
- hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, bundleFileLocation);
- IF_FAIL_GO(hr);
- }
-
- // Initialize assembly object
- IF_FAIL_GO(pAssembly->Init(pPEImage, fIsInTPA));
-
- // We're done
- *ppAssembly = pAssembly.Extract();
-
- Exit:
-
- SAFE_RELEASE(pPEImage);
-
- // Normalize file not found
- if ((FAILED(hr)) && IsFileNotFound(hr))
- {
- hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
-
- return hr;
- }
-
-
- /* static */
- HRESULT AssemblyBinderCommon::Register(ApplicationContext *pApplicationContext,
- BindResult *pBindResult)
- {
- _ASSERTE(!pBindResult->GetIsContextBound());
-
- pApplicationContext->IncrementVersion();
-
- // Register the bindResult in the ExecutionContext only if we dont have it already.
- // This method is invoked under a lock (by its caller), so we are thread safe.
- Assembly *pAssembly = NULL;
- HRESULT hr = FindInExecutionContext(pApplicationContext, pBindResult->GetAssemblyName(), &pAssembly);
- if (FAILED(hr))
- return hr;
-
- if (pAssembly == NULL)
- {
- ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
- pExecutionContext->Add(pBindResult->GetAssembly(/*fAddRef*/ TRUE));
- }
- else
- {
- // Update the BindResult with the assembly we found
- pBindResult->SetResult(pAssembly, /*isContextBound*/ true);
- }
-
- return S_OK;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::RegisterAndGetHostChosen(ApplicationContext *pApplicationContext,
- LONG kContextVersion,
- BindResult *pBindResult,
- BindResult *pHostBindResult)
- {
- HRESULT hr = S_OK;
-
- _ASSERTE(pBindResult != NULL);
- _ASSERTE(pBindResult->HaveResult());
- _ASSERTE(pHostBindResult != NULL);
-
- if (!pBindResult->GetIsContextBound())
- {
- pHostBindResult->SetResult(pBindResult);
-
- {
- // Lock the application context
- CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
-
- // Only perform costly validation if other binds succeeded before us
- if (kContextVersion != pApplicationContext->GetVersion())
- {
- IF_FAIL_GO(AssemblyBinderCommon::OtherBindInterfered(pApplicationContext,
- pBindResult));
-
- if (hr == S_FALSE)
- {
- // Another bind interfered
- GO_WITH_HRESULT(hr);
- }
- }
-
- // No bind interfered, we can now register
- IF_FAIL_GO(Register(pApplicationContext,
- pHostBindResult));
- }
- }
- else
- {
- // No work required. Return the input
- pHostBindResult->SetResult(pBindResult);
- }
-
- Exit:
- return hr;
- }
-
- /* static */
- HRESULT AssemblyBinderCommon::OtherBindInterfered(ApplicationContext *pApplicationContext,
- BindResult *pBindResult)
- {
- HRESULT hr = S_FALSE;
- AssemblyName *pAssemblyName = pBindResult->GetAssemblyName();
- PathString assemblyDisplayName;
-
- _ASSERTE(pAssemblyName != NULL);
-
- // Look for already cached binding failure (ignore PA, every PA will lock the context)
- pAssemblyName->GetDisplayName(assemblyDisplayName, AssemblyName::INCLUDE_VERSION);
- hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
-
- if (hr == S_OK)
- {
- Assembly *pAssembly = NULL;
- hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pAssembly);
- if (SUCCEEDED(hr) && (pAssembly == NULL))
- {
- // We can accept this bind in the domain
- GO_WITH_HRESULT(S_OK);
- }
- }
-
- // Some other bind interfered
- GO_WITH_HRESULT(S_FALSE);
+ *ppPEImage = pSystemAssembly.Extract();
Exit:
return hr;
}
-
-
+
#if !defined(DACCESS_COMPILE)
-HRESULT AssemblyBinderCommon::BindUsingHostAssemblyResolver(/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ DefaultAssemblyBinder *pDefaultBinder,
- /* in */ AssemblyBinder *pBinder,
- /* out */ Assembly **ppAssembly)
-{
- HRESULT hr = E_FAIL;
-
- _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL);
-
- // RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CustomAssemblyBinder::BindAssemblyByName.
- BINDER_SPACE::Assembly *pLoadedAssembly = NULL;
- hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin,
- pAssemblyName, pDefaultBinder, pBinder, &pLoadedAssembly);
- if (SUCCEEDED(hr))
- {
- _ASSERTE(pLoadedAssembly != NULL);
- *ppAssembly = pLoadedAssembly;
- }
-
- return hr;
-}
-
-/* static */
-HRESULT AssemblyBinderCommon::BindUsingPEImage(/* in */ AssemblyBinder* pBinder,
- /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
- /* in */ PEImage *pPEImage,
- /* in */ bool excludeAppPaths,
- /* [retval] [out] */ Assembly **ppAssembly)
-{
- HRESULT hr = E_FAIL;
-
- LONG kContextVersion = 0;
- BindResult bindResult;
-
- // Prepare binding data
- *ppAssembly = NULL;
- ApplicationContext* pApplicationContext = pBinder->GetAppContext();
-
- // Tracing happens outside the binder lock to avoid calling into managed code within the lock
- BinderTracing::ResolutionAttemptedOperation tracer{pAssemblyName, pBinder, 0 /*managedALC*/, hr};
-
- // Attempt the actual bind (eventually more than once)
-Retry:
- bool mvidMismatch = false;
- {
- // Lock the application context
- CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
-
- // Attempt uncached bind and register stream if possible
- // We skip version compatibility check - so assemblies with same simple name will be reported
- // as a successful bind. Below we compare MVIDs in that case instead (which is a more precise equality check).
- hr = BindByName(pApplicationContext,
- pAssemblyName,
- true, // skipFailureCaching
- true, // skipVersionCompatibilityCheck
- excludeAppPaths, // excludeAppPaths
- &bindResult);
-
- if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- IF_FAIL_GO(CreateImageAssembly(pPEImage, &bindResult));
- }
- else if (hr == S_OK)
- {
- if (bindResult.HaveResult())
- {
- // Attempt was made to load an assembly that has the same name as a previously loaded one. Since same name
- // does not imply the same assembly, we will need to check the MVID to confirm it is the same assembly as being
- // requested.
-
- GUID incomingMVID;
- GUID boundMVID;
-
- // GetMVID can throw exception
- EX_TRY
- {
- pPEImage->GetMVID(&incomingMVID);
- bindResult.GetAssembly()->GetPEImage()->GetMVID(&boundMVID);
- }
- EX_CATCH
- {
- hr = GET_EXCEPTION()->GetHR();
- goto Exit;
- }
- EX_END_CATCH(SwallowAllExceptions);
-
-
- mvidMismatch = incomingMVID != boundMVID;
- if (mvidMismatch)
- {
- // MVIDs do not match, so fail the load.
- IF_FAIL_GO(COR_E_FILELOAD);
- }
-
- // MVIDs match - request came in for the same assembly that was previously loaded.
- // Let it through...
- }
- }
-
- // Remember the post-bind version of the context
- kContextVersion = pApplicationContext->GetVersion();
-
- } // lock(pApplicationContext)
-
- if (bindResult.HaveResult())
- {
- BindResult hostBindResult;
-
- // This has to happen outside the binder lock as it can cause new binds
- IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
- kContextVersion,
- &bindResult,
- &hostBindResult));
-
- if (hr == S_FALSE)
- {
- tracer.TraceBindResult(bindResult);
-
- // Another bind interfered. We need to retry entire bind.
- // This by design loops as long as needed because by construction we eventually
- // will succeed or fail the bind.
- bindResult.Reset();
- goto Retry;
- }
- else if (hr == S_OK)
- {
- *ppAssembly = hostBindResult.GetAssembly(TRUE /* fAddRef */);
- }
- }
-
-Exit:
- tracer.TraceBindResult(bindResult, mvidMismatch);
- return hr;
-}
-
HRESULT AssemblyBinderCommon::CreateDefaultBinder(DefaultAssemblyBinder** ppDefaultBinder)
{
HRESULT hr = S_OK;
@@ -1293,8 +186,6 @@ HRESULT AssemblyBinderCommon::CreateDefaultBinder(DefaultAssemblyBinder** ppDefa
NewHolder pBinder;
SAFE_NEW(pBinder, DefaultAssemblyBinder);
- BINDER_SPACE::ApplicationContext* pApplicationContext = pBinder->GetAppContext();
- hr = pApplicationContext->Init();
if (SUCCEEDED(hr))
{
pBinder->SetManagedAssemblyLoadContext((INT_PTR)NULL);
diff --git a/src/coreclr/binder/bindertracing.cpp b/src/coreclr/binder/bindertracing.cpp
index 82b31932bd030..cbe083157d3d2 100644
--- a/src/coreclr/binder/bindertracing.cpp
+++ b/src/coreclr/binder/bindertracing.cpp
@@ -13,7 +13,7 @@
#include "common.h"
#include "bindertracing.h"
-#include "bindresult.hpp"
+#include "assemblybinder.h"
#include "activitytracker.h"
@@ -180,175 +180,6 @@ namespace BinderTracing
namespace BinderTracing
{
- ResolutionAttemptedOperation::ResolutionAttemptedOperation(AssemblyName *assemblyName, AssemblyBinder* binder, INT_PTR managedALC, const HRESULT& hr)
- : m_hr { hr }
- , m_stage { Stage::NotYetStarted }
- , m_tracingEnabled { BinderTracing::IsEnabled() }
- , m_assemblyNameObject { assemblyName }
- , m_pFoundAssembly { nullptr }
- {
- _ASSERTE(binder != nullptr || managedALC != 0);
-
- if (!m_tracingEnabled)
- return;
-
- // When binding the main assembly (by code base instead of name), the assembly name will be null. In this special case, we just
- // leave the assembly name empty.
- if (m_assemblyNameObject != nullptr)
- m_assemblyNameObject->GetDisplayName(m_assemblyName, AssemblyName::INCLUDE_VERSION | AssemblyName::INCLUDE_PUBLIC_KEY_TOKEN);
-
- if (managedALC != 0)
- {
- AssemblyBinder::GetNameForDiagnosticsFromManagedALC(managedALC, m_assemblyLoadContextName);
- }
- else
- {
- binder->GetNameForDiagnostics(m_assemblyLoadContextName);
- }
- }
-
- // This function simply traces out the two stages represented by the bind result.
- // It does not change the stage/assembly of the ResolutionAttemptedOperation class instance.
- void ResolutionAttemptedOperation::TraceBindResult(const BindResult &bindResult, bool mvidMismatch)
- {
- if (!m_tracingEnabled)
- return;
-
- // Use the error message that would be reported in the file load exception
- StackSString errorMsg;
- if (mvidMismatch)
- {
- StackSString format;
- format.LoadResource(CCompRC::Error, IDS_EE_FILELOAD_ERROR_GENERIC);
- StackSString details;
- details.LoadResource(CCompRC::Error, IDS_HOST_ASSEMBLY_RESOLVER_ASSEMBLY_ALREADY_LOADED_IN_CONTEXT);
- errorMsg.FormatMessage(FORMAT_MESSAGE_FROM_STRING, format.GetUnicode(), 0, 0, m_assemblyName, details);
- }
-
- const BindResult::AttemptResult *inContextAttempt = bindResult.GetAttempt(true /*foundInContext*/);
- const BindResult::AttemptResult *appAssembliesAttempt = bindResult.GetAttempt(false /*foundInContext*/);
-
- if (inContextAttempt != nullptr)
- {
- // If there the attempt HR represents a success, but the tracked HR represents a failure (e.g. from further validation), report the failed HR
- bool isLastAttempt = appAssembliesAttempt == nullptr;
- TraceStage(Stage::FindInLoadContext,
- isLastAttempt && FAILED(m_hr) && SUCCEEDED(inContextAttempt->HResult) ? m_hr : inContextAttempt->HResult,
- inContextAttempt->Assembly,
- mvidMismatch && isLastAttempt ? errorMsg.GetUnicode() : nullptr);
- }
-
- if (appAssembliesAttempt != nullptr)
- TraceStage(Stage::ApplicationAssemblies, FAILED(m_hr) && SUCCEEDED(appAssembliesAttempt->HResult) ? m_hr : appAssembliesAttempt->HResult, appAssembliesAttempt->Assembly, mvidMismatch ? errorMsg.GetUnicode() : nullptr);
- }
-
- void ResolutionAttemptedOperation::TraceStage(Stage stage, HRESULT hr, BINDER_SPACE::Assembly *resultAssembly, const WCHAR *customError)
- {
- if (!m_tracingEnabled || stage == Stage::NotYetStarted)
- return;
-
- PathString resultAssemblyName;
- StackSString resultAssemblyPath;
- if (resultAssembly != nullptr)
- {
- resultAssembly->GetAssemblyName()->GetDisplayName(resultAssemblyName, AssemblyName::INCLUDE_VERSION | AssemblyName::INCLUDE_PUBLIC_KEY_TOKEN);
- resultAssemblyPath = resultAssembly->GetPEImage()->GetPath();
- }
-
- Result result;
- StackSString errorMsg;
- if (customError != nullptr)
- {
- errorMsg.Set(customError);
- result = Result::Failure;
- }
- else if (!m_exceptionMessage.IsEmpty())
- {
- errorMsg = m_exceptionMessage;
- result = Result::Exception;
- }
- else
- {
- switch (hr)
- {
- case S_FALSE:
- case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
- static_assert(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == COR_E_FILENOTFOUND,
- "COR_E_FILENOTFOUND has sane value");
-
- result = Result::AssemblyNotFound;
- errorMsg.Set(s_assemblyNotFoundMessage);
- break;
-
- case FUSION_E_APP_DOMAIN_LOCKED:
- result = Result::IncompatibleVersion;
-
- {
- SString errorMsgUtf8(SString::Utf8, "Requested version");
- if (m_assemblyNameObject != nullptr)
- {
- const auto &reqVersion = m_assemblyNameObject->GetVersion();
- errorMsgUtf8.AppendPrintf(" %d.%d.%d.%d",
- reqVersion->GetMajor(),
- reqVersion->GetMinor(),
- reqVersion->GetBuild(),
- reqVersion->GetRevision());
- }
-
- errorMsgUtf8.AppendUTF8(" is incompatible with found version");
- if (resultAssembly != nullptr)
- {
- const auto &foundVersion = resultAssembly->GetAssemblyName()->GetVersion();
- errorMsgUtf8.AppendPrintf(" %d.%d.%d.%d",
- foundVersion->GetMajor(),
- foundVersion->GetMinor(),
- foundVersion->GetBuild(),
- foundVersion->GetRevision());
- }
- errorMsg.Set(errorMsgUtf8.GetUnicode());
- }
- break;
-
- case FUSION_E_REF_DEF_MISMATCH:
- result = Result::MismatchedAssemblyName;
- errorMsg.Append(W("Requested assembly name '"));
- errorMsg.Append(m_assemblyName.GetUnicode());
- errorMsg.Append(W("' does not match found assembly name"));
- if (resultAssembly != nullptr)
- {
- errorMsg.Append(W(" '"));
- errorMsg.Append(resultAssemblyName.GetUnicode());
- errorMsg.Append(W("'"));
- }
-
- break;
-
- default:
- if (SUCCEEDED(hr))
- {
- result = Result::Success;
- _ASSERTE(resultAssembly != nullptr);
- // Leave errorMsg empty in this case.
- }
- else
- {
- result = Result::Failure;
- errorMsg.Printf("Resolution failed with HRESULT (%08x)", m_hr);
- }
- }
- }
-
- FireEtwResolutionAttempted(
- GetClrInstanceId(),
- m_assemblyName,
- static_cast(stage),
- m_assemblyLoadContextName,
- static_cast(result),
- resultAssemblyName,
- resultAssemblyPath,
- errorMsg);
- }
-
// static
void ResolutionAttemptedOperation::TraceAppDomainAssemblyResolve(AssemblySpec *spec, PEAssembly *resultAssembly, Exception *exception)
{
diff --git a/src/coreclr/binder/customassemblybinder.cpp b/src/coreclr/binder/customassemblybinder.cpp
index 99297c2bd9ce3..cc5e53ee396b0 100644
--- a/src/coreclr/binder/customassemblybinder.cpp
+++ b/src/coreclr/binder/customassemblybinder.cpp
@@ -10,139 +10,6 @@
using namespace BINDER_SPACE;
-// ============================================================================
-// CustomAssemblyBinder implementation
-// ============================================================================
-HRESULT CustomAssemblyBinder::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
- BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly)
-{
- VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
- HRESULT hr = S_OK;
-
-#ifdef _DEBUG
- // CoreLib should be bound using BindToSystem
- _ASSERTE(!pAssemblyName->IsCoreLib());
-#endif
-
- // Do we have the assembly already loaded in the context of the current binder?
- hr = AssemblyBinderCommon::BindAssembly(this,
- pAssemblyName,
- false, //excludeAppPaths,
- ppCoreCLRFoundAssembly);
- if (!FAILED(hr))
- {
- _ASSERTE(*ppCoreCLRFoundAssembly != NULL);
- (*ppCoreCLRFoundAssembly)->SetBinder(this);
- }
-
- return hr;
-}
-
-HRESULT CustomAssemblyBinder::BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName,
- BINDER_SPACE::Assembly** ppAssembly)
-{
- // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
- //
- // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it.
- // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it.
- // 3) Lookup the assembly within DefaultBinder (except for satellite requests). If assembly is found, use it.
- // 4) Invoke the LoadContext's ResolveSatelliteAssembly method (for satellite requests). If assembly is found, use it.
- // 5) Invoke the LoadContext's Resolving event. If assembly is found, use it.
- // 6) Raise exception.
- //
- // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading
- // a different (or even the same!) version.
-
- HRESULT hr = S_OK;
- ReleaseHolder pCoreCLRFoundAssembly;
-
- {
- // Step 1 - Try to find the assembly within the LoadContext.
- hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly);
- if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
- (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
- {
- // If we are here, one of the following is possible:
- //
- // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
- // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
- // mismatch (either due to version difference or strong-name difference).
- //
- // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
- // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
- // that has been loaded.
- //
- hr = AssemblyBinderCommon::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName,
- m_pDefaultBinder, this, &pCoreCLRFoundAssembly);
- if (SUCCEEDED(hr))
- {
- // We maybe returned an assembly that was bound to a different AssemblyBinder instance.
- // In such a case, we will not overwrite the binder (which would be wrong since the assembly would not
- // be present in the cache of the current binding context).
- if (pCoreCLRFoundAssembly->GetBinder() == NULL)
- {
- pCoreCLRFoundAssembly->SetBinder(this);
- }
- }
- }
- }
-
- IF_FAIL_GO(hr);
-
- // Extract the assembly reference.
- //
- // For TPA assemblies that were bound, DefaultBinder
- // would have already set the binder reference for the assembly, so we just need to
- // extract the reference now.
- *ppAssembly = pCoreCLRFoundAssembly.Extract();
-
-Exit:;
-
- return hr;
-}
-
-HRESULT CustomAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage,
- /* in */ bool excludeAppPaths,
- /* [retval][out] */ BINDER_SPACE::Assembly **ppAssembly)
-{
- HRESULT hr = S_OK;
-
- EX_TRY
- {
- ReleaseHolder pCoreCLRFoundAssembly;
- ReleaseHolder pAssemblyName;
-
- // Using the information we just got, initialize the assemblyname
- SAFE_NEW(pAssemblyName, BINDER_SPACE::AssemblyName);
- IF_FAIL_GO(pAssemblyName->Init(pPEImage));
-
- // Validate architecture
- if (!AssemblyBinderCommon::IsValidArchitecture(pAssemblyName->GetArchitecture()))
- {
- IF_FAIL_GO(CLR_E_BIND_ARCHITECTURE_MISMATCH);
- }
-
- // Disallow attempt to bind to the core library. Aside from that,
- // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA).
- if (pAssemblyName->IsCoreLib())
- {
- IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
- }
-
- hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, excludeAppPaths, &pCoreCLRFoundAssembly);
- if (hr == S_OK)
- {
- _ASSERTE(pCoreCLRFoundAssembly != NULL);
- pCoreCLRFoundAssembly->SetBinder(this);
- *ppAssembly = pCoreCLRFoundAssembly.Extract();
- }
-Exit:;
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
AssemblyLoaderAllocator* CustomAssemblyBinder::GetLoaderAllocator()
{
return m_pAssemblyLoaderAllocator;
@@ -161,7 +28,7 @@ HRESULT CustomAssemblyBinder::SetupContext(DefaultAssemblyBinder *pDefaultBinder
UINT_PTR ptrAssemblyLoadContext,
CustomAssemblyBinder **ppBindContext)
{
- HRESULT hr = E_FAIL;
+ HRESULT hr = S_OK;
EX_TRY
{
if(ppBindContext != NULL)
@@ -169,7 +36,6 @@ HRESULT CustomAssemblyBinder::SetupContext(DefaultAssemblyBinder *pDefaultBinder
NewHolder pBinder;
SAFE_NEW(pBinder, CustomAssemblyBinder);
- hr = pBinder->GetAppContext()->Init();
if(SUCCEEDED(hr))
{
// Save reference to the DefaultBinder that is required to be present.
diff --git a/src/coreclr/binder/defaultassemblybinder.cpp b/src/coreclr/binder/defaultassemblybinder.cpp
deleted file mode 100644
index 54a70e51f05ec..0000000000000
--- a/src/coreclr/binder/defaultassemblybinder.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-#include "common.h"
-#include "assemblybindercommon.hpp"
-#include "defaultassemblybinder.h"
-
-using namespace BINDER_SPACE;
-
-//=============================================================================
-// Helper functions
-//-----------------------------------------------------------------------------
-
-HRESULT DefaultAssemblyBinder::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
- BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
- bool excludeAppPaths)
-{
- VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
- HRESULT hr = S_OK;
-
-#ifdef _DEBUG
- // CoreLib should be bound using BindToSystem
- _ASSERTE(!pAssemblyName->IsCoreLib());
-#endif
-
- hr = AssemblyBinderCommon::BindAssembly(this,
- pAssemblyName,
- excludeAppPaths,
- ppCoreCLRFoundAssembly);
- if (!FAILED(hr))
- {
- (*ppCoreCLRFoundAssembly)->SetBinder(this);
- }
-
- return hr;
-}
-
-// ============================================================================
-// DefaultAssemblyBinder implementation
-// ============================================================================
-HRESULT DefaultAssemblyBinder::BindUsingAssemblyName(BINDER_SPACE::AssemblyName *pAssemblyName,
- BINDER_SPACE::Assembly **ppAssembly)
-{
- HRESULT hr = S_OK;
- VALIDATE_ARG_RET(pAssemblyName != nullptr && ppAssembly != nullptr);
-
- *ppAssembly = nullptr;
-
- ReleaseHolder pCoreCLRFoundAssembly;
-
- hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, false /* excludeAppPaths */);
-
-#if !defined(DACCESS_COMPILE)
- if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
- (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
- {
- // If we are here, one of the following is possible:
- //
- // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
- // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
- // mismatch (either due to version difference or strong-name difference).
- //
- // Attempt to resolve the assembly via managed ALC instance. This can either fail the bind or return reference to an existing
- // assembly that has been loaded
- INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
- if (pManagedAssemblyLoadContext == (INT_PTR)NULL)
- {
- // For satellite assemblies, the managed ALC has additional resolution logic (defined by the runtime) which
- // should be run even if the managed default ALC has not yet been used. (For non-satellite assemblies, any
- // additional logic comes through a user-defined event handler which would have initialized the managed ALC,
- // so if the managed ALC is not set yet, there is no additional logic to run)
- if (!pAssemblyName->IsNeutralCulture())
- {
- // Make sure the managed default ALC is initialized.
- GCX_COOP();
- PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__INITIALIZE_DEFAULT_CONTEXT);
- DECLARE_ARGHOLDER_ARRAY(args, 0);
- CALL_MANAGED_METHOD_NORET(args)
-
- pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
- _ASSERTE(pManagedAssemblyLoadContext != (INT_PTR)NULL);
- }
- }
-
- if (pManagedAssemblyLoadContext != (INT_PTR)NULL)
- {
- hr = AssemblyBinderCommon::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName,
- NULL, this, &pCoreCLRFoundAssembly);
- if (SUCCEEDED(hr))
- {
- // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
- // In such a case, we will not overwrite the binding context (which would be wrong since it would not
- // be present in the cache of the current binding context).
- if (pCoreCLRFoundAssembly->GetBinder() == NULL)
- {
- pCoreCLRFoundAssembly->SetBinder(this);
- }
- }
- }
- }
-#endif // !defined(DACCESS_COMPILE)
-
- IF_FAIL_GO(hr);
-
- *ppAssembly = pCoreCLRFoundAssembly.Extract();
-
-Exit:;
-
- return hr;
-}
-
-#if !defined(DACCESS_COMPILE)
-HRESULT DefaultAssemblyBinder::BindUsingPEImage( /* in */ PEImage *pPEImage,
- /* in */ bool excludeAppPaths,
- /* [retval][out] */ BINDER_SPACE::Assembly **ppAssembly)
-{
- HRESULT hr = S_OK;
-
- EX_TRY
- {
- ReleaseHolder pCoreCLRFoundAssembly;
- ReleaseHolder pAssemblyName;
-
- // Using the information we just got, initialize the assemblyname
- SAFE_NEW(pAssemblyName, AssemblyName);
- IF_FAIL_GO(pAssemblyName->Init(pPEImage));
-
- // Validate architecture
- if (!AssemblyBinderCommon::IsValidArchitecture(pAssemblyName->GetArchitecture()))
- {
- IF_FAIL_GO(CLR_E_BIND_ARCHITECTURE_MISMATCH);
- }
-
- // Easy out for CoreLib
- if (pAssemblyName->IsCoreLib())
- {
- IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
- }
-
- {
- // Ensure we are not being asked to bind to a TPA assembly
- //
- const SString& simpleName = pAssemblyName->GetSimpleName();
- SimpleNameToFileNameMap* tpaMap = GetAppContext()->GetTpaList();
- if (tpaMap->LookupPtr(simpleName.GetUnicode()) != NULL)
- {
- // The simple name of the assembly being requested to be bound was found in the TPA list.
- // Now, perform the actual bind to see if the assembly was really in the TPA assembly list or not.
- hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */);
- if (SUCCEEDED(hr))
- {
- if (pCoreCLRFoundAssembly->GetIsInTPA())
- {
- *ppAssembly = pCoreCLRFoundAssembly.Extract();
- goto Exit;
- }
- }
- }
- }
-
- hr = AssemblyBinderCommon::BindUsingPEImage(this, pAssemblyName, pPEImage, excludeAppPaths, &pCoreCLRFoundAssembly);
- if (hr == S_OK)
- {
- _ASSERTE(pCoreCLRFoundAssembly != NULL);
- pCoreCLRFoundAssembly->SetBinder(this);
- *ppAssembly = pCoreCLRFoundAssembly.Extract();
- }
-Exit:;
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-#endif // !defined(DACCESS_COMPILE)
-
-HRESULT DefaultAssemblyBinder::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
- SString &sPlatformResourceRoots,
- SString &sAppPaths)
-{
- HRESULT hr = S_OK;
-
- EX_TRY
- {
- hr = GetAppContext()->SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths, TRUE /* fAcquireLock */);
- }
- EX_CATCH_HRESULT(hr);
- return hr;
-}
-
-HRESULT DefaultAssemblyBinder::BindToSystem(BINDER_SPACE::Assembly** ppSystemAssembly)
-{
- HRESULT hr = S_OK;
- _ASSERTE(ppSystemAssembly != NULL);
-
- EX_TRY
- {
- ReleaseHolder pAsm;
- StackSString systemPath(SystemDomain::System()->SystemDirectory());
- hr = AssemblyBinderCommon::BindToSystem(systemPath, &pAsm);
- if (SUCCEEDED(hr))
- {
- _ASSERTE(pAsm != NULL);
- *ppSystemAssembly = pAsm.Extract();
- (*ppSystemAssembly)->SetBinder(this);
- }
-
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
diff --git a/src/coreclr/binder/failurecache.cpp b/src/coreclr/binder/failurecache.cpp
deleted file mode 100644
index c6e1f286fbb7e..0000000000000
--- a/src/coreclr/binder/failurecache.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// FailureCache.cpp
-//
-
-
-//
-// Implements the FailureCache class
-//
-// ============================================================
-
-#include "failurecache.hpp"
-
-namespace BINDER_SPACE
-{
- FailureCache::FailureCache() : SHash::SHash()
- {
- // Nothing to do here
- }
-
- FailureCache::~FailureCache()
- {
- // Delete entries and contents array
- for (Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
- {
- const FailureCacheEntry *pFailureCacheEntry = *i;
- delete pFailureCacheEntry;
- }
- RemoveAll();
- }
-
- HRESULT FailureCache::Add(SString &assemblyNameorPath,
- HRESULT hrBindingResult)
- {
- HRESULT hr = S_OK;
-
- NewHolder pFailureCacheEntry;
- SAFE_NEW(pFailureCacheEntry, FailureCacheEntry);
-
- // No error occurred; report the original error
- hr = hrBindingResult;
-
- pFailureCacheEntry->GetAssemblyNameOrPath().Set(assemblyNameorPath);
- pFailureCacheEntry->SetBindingResult(hrBindingResult);
-
- Hash::Add(pFailureCacheEntry);
- pFailureCacheEntry.SuppressRelease();
-
- Exit:
- return hr;
- }
-
- HRESULT FailureCache::Lookup(SString &assemblyNameorPath)
- {
- HRESULT hr = S_OK;
- FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyNameorPath);
-
- if (pFailureCachEntry != NULL)
- {
- hr = pFailureCachEntry->GetBindingResult();
- }
-
- return hr;
- }
-
- void FailureCache::Remove(SString &assemblyName)
- {
- FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyName);
-
- // Hash::Remove does not clean up entries
- Hash::Remove(assemblyName);
- SAFE_DELETE(pFailureCachEntry);
- }
-};
diff --git a/src/coreclr/binder/inc/applicationcontext.hpp b/src/coreclr/binder/inc/applicationcontext.hpp
deleted file mode 100644
index 721f571af1e5d..0000000000000
--- a/src/coreclr/binder/inc/applicationcontext.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// ApplicationContext.hpp
-//
-
-
-//
-// Defines the ApplicationContext class
-//
-// ============================================================
-
-#ifndef __BINDER__APPLICATION_CONTEXT_HPP__
-#define __BINDER__APPLICATION_CONTEXT_HPP__
-
-#include "bindertypes.hpp"
-#include "failurecache.hpp"
-#include "stringarraylist.h"
-
-namespace BINDER_SPACE
-{
- //=============================================================================================
- // Data structures for Simple Name -> File Name hash
-
- // Entry in SHash table that maps namespace to list of files
- struct SimpleNameToFileNameMapEntry
- {
- LPWSTR m_wszSimpleName;
- LPWSTR m_wszILFileName;
- LPWSTR m_wszNIFileName;
- };
-
- // SHash traits for Namespace -> FileNameList hash
- class SimpleNameToFileNameMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits< SimpleNameToFileNameMapEntry > >
- {
- public:
- typedef PCWSTR key_t;
- static const SimpleNameToFileNameMapEntry Null() { SimpleNameToFileNameMapEntry e; e.m_wszSimpleName = nullptr; return e; }
- static bool IsNull(const SimpleNameToFileNameMapEntry & e) { return e.m_wszSimpleName == nullptr; }
- static key_t GetKey(const SimpleNameToFileNameMapEntry & e)
- {
- key_t key;
- key = e.m_wszSimpleName;
- return key;
- }
- static count_t Hash(const key_t &str)
- {
- SString ssKey(SString::Literal, str);
- return ssKey.HashCaseInsensitive();
- }
- static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (SString::_wcsicmp(lhs, rhs) == 0); }
-
- void OnDestructPerEntryCleanupAction(const SimpleNameToFileNameMapEntry & e)
- {
- if (e.m_wszILFileName == nullptr && e.m_wszNIFileName == nullptr)
- {
- // Don't delete simple name here since it's a filename only entry and will be cleaned up
- // by the SimpleName -> FileName entry which reuses the same filename pointer.
- return;
- }
-
- if (e.m_wszSimpleName != nullptr)
- {
- delete [] e.m_wszSimpleName;
- }
- if (e.m_wszILFileName != nullptr)
- {
- delete [] e.m_wszILFileName;
- }
- if (e.m_wszNIFileName != nullptr)
- {
- delete [] e.m_wszNIFileName;
- }
- }
- static const bool s_DestructPerEntryCleanupAction = true;
- };
-
- typedef SHash SimpleNameToFileNameMap;
-
- class AssemblyHashTraits;
- typedef SHash ExecutionContext;
-
- class ApplicationContext
- {
- public:
- // ApplicationContext methods
- ApplicationContext();
- ~ApplicationContext();
- HRESULT Init();
-
- inline SString &GetApplicationName();
-
- HRESULT SetupBindingPaths(/* in */ SString &sTrustedPlatformAssemblies,
- /* in */ SString &sPlatformResourceRoots,
- /* in */ SString &sAppPaths,
- /* in */ BOOL fAcquireLock);
-
- // Getters/Setter
- inline ExecutionContext *GetExecutionContext();
- inline FailureCache *GetFailureCache();
- inline HRESULT AddToFailureCache(SString &assemblyNameOrPath,
- HRESULT hrBindResult);
- inline StringArrayList *GetAppPaths();
- inline SimpleNameToFileNameMap *GetTpaList();
- inline StringArrayList *GetPlatformResourceRoots();
-
- // Using a host-configured Trusted Platform Assembly list
- bool IsTpaListProvided();
- inline CRITSEC_COOKIE GetCriticalSectionCookie();
- inline LONG GetVersion();
- inline void IncrementVersion();
-
- private:
- Volatile m_cVersion;
- SString m_applicationName;
- ExecutionContext *m_pExecutionContext;
- FailureCache *m_pFailureCache;
- CRITSEC_COOKIE m_contextCS;
-
- StringArrayList m_platformResourceRoots;
- StringArrayList m_appPaths;
-
- SimpleNameToFileNameMap * m_pTrustedPlatformAssemblyMap;
- };
-
-#include "applicationcontext.inl"
-
-};
-
-#endif
diff --git a/src/coreclr/binder/inc/applicationcontext.inl b/src/coreclr/binder/inc/applicationcontext.inl
deleted file mode 100644
index 16ec0c6d87de2..0000000000000
--- a/src/coreclr/binder/inc/applicationcontext.inl
+++ /dev/null
@@ -1,71 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// ApplicationContext.inl
-//
-
-
-//
-// Implements inlined methods of ApplicationContext
-//
-// ============================================================
-
-#ifndef __BINDER__APPLICATION_CONTEXT_INL__
-#define __BINDER__APPLICATION_CONTEXT_INL__
-
-LONG ApplicationContext::GetVersion()
-{
- return m_cVersion;
-}
-
-void ApplicationContext::IncrementVersion()
-{
- InterlockedIncrement(&m_cVersion);
-}
-
-SString &ApplicationContext::GetApplicationName()
-{
- return m_applicationName;
-}
-
-ExecutionContext *ApplicationContext::GetExecutionContext()
-{
- return m_pExecutionContext;
-}
-
-FailureCache *ApplicationContext::GetFailureCache()
-{
- _ASSERTE(m_pFailureCache != NULL);
- return m_pFailureCache;
-}
-
-HRESULT ApplicationContext::AddToFailureCache(SString &assemblyNameOrPath,
- HRESULT hrBindResult)
-{
- HRESULT hr = GetFailureCache()->Add(assemblyNameOrPath, hrBindResult);
- IncrementVersion();
- return hr;
-}
-
-StringArrayList *ApplicationContext::GetAppPaths()
-{
- return &m_appPaths;
-}
-
-SimpleNameToFileNameMap * ApplicationContext::GetTpaList()
-{
- return m_pTrustedPlatformAssemblyMap;
-}
-
-StringArrayList * ApplicationContext::GetPlatformResourceRoots()
-{
- return &m_platformResourceRoots;
-}
-
-CRITSEC_COOKIE ApplicationContext::GetCriticalSectionCookie()
-{
- return m_contextCS;
-}
-
-#endif
diff --git a/src/coreclr/binder/inc/assembly.hpp b/src/coreclr/binder/inc/assembly.hpp
deleted file mode 100644
index 908e938793265..0000000000000
--- a/src/coreclr/binder/inc/assembly.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// Assembly.hpp
-//
-
-
-//
-// Defines the Assembly class
-//
-// ============================================================
-
-#ifndef __BINDER__ASSEMBLY_HPP__
-#define __BINDER__ASSEMBLY_HPP__
-
-#include "bindertypes.hpp"
-#include "assemblyname.hpp"
-
-#include "corpriv.h"
-
-#include "defaultassemblybinder.h"
-
-#if !defined(DACCESS_COMPILE)
-#include "customassemblybinder.h"
-#endif // !defined(DACCESS_COMPILE)
-
-#include "bundle.h"
-#include
-
-class DomainAssembly;
-
-namespace BINDER_SPACE
-{
- // BINDER_SPACE::Assembly represents a result of binding to an actual assembly (PEImage)
- // It is basically a tuple of 1) physical assembly and 2) binder which created/owns this binding
- // We also store whether it was bound using TPA list
- class Assembly
- {
- public:
- ULONG AddRef();
- ULONG Release();
-
- Assembly();
- virtual ~Assembly();
-
- HRESULT Init(PEImage *pPEImage, BOOL fIsInTPA);
-
- LPCWSTR GetSimpleName();
- AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
- PEImage* GetPEImage();
- BOOL GetIsInTPA();
-
- PTR_AssemblyBinder GetBinder()
- {
- return m_pBinder;
- }
-
- DomainAssembly* GetDomainAssembly()
- {
- return m_domainAssembly;
- }
-
- void SetDomainAssembly(DomainAssembly* value)
- {
- _ASSERTE(value == NULL || m_domainAssembly == NULL);
- m_domainAssembly = value;
- }
-
- private:
- LONG m_cRef;
- PEImage *m_pPEImage;
- AssemblyName *m_pAssemblyName;
- PTR_AssemblyBinder m_pBinder;
- bool m_isInTPA;
- DomainAssembly *m_domainAssembly;
-
-#if !defined(DACCESS_COMPILE)
- inline void SetBinder(AssemblyBinder *pBinder)
- {
- _ASSERTE(m_pBinder == NULL || m_pBinder == pBinder);
- m_pBinder = pBinder;
- }
-
- friend class ::CustomAssemblyBinder;
-#endif // !defined(DACCESS_COMPILE)
-
- friend class ::DefaultAssemblyBinder;
- };
-
-#include "assembly.inl"
-};
-
-#endif
diff --git a/src/coreclr/binder/inc/assembly.inl b/src/coreclr/binder/inc/assembly.inl
deleted file mode 100644
index a256be8ff5196..0000000000000
--- a/src/coreclr/binder/inc/assembly.inl
+++ /dev/null
@@ -1,50 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// Assembly.inl
-//
-
-
-//
-// Implements the inline methods of Assembly
-//
-// ============================================================
-
-#ifndef __BINDER__ASSEMBLY_INL__
-#define __BINDER__ASSEMBLY_INL__
-
-inline ULONG Assembly::AddRef()
-{
- return InterlockedIncrement(&m_cRef);
-}
-
-inline ULONG Assembly::Release()
-{
- ULONG ulRef = InterlockedDecrement(&m_cRef);
-
- if (ulRef == 0)
- {
- delete this;
- }
-
- return ulRef;
-}
-
-inline AssemblyName *Assembly::GetAssemblyName(BOOL fAddRef /* = FALSE */)
-{
- AssemblyName *pAssemblyName = m_pAssemblyName;
-
- if (fAddRef && (pAssemblyName != NULL))
- {
- pAssemblyName->AddRef();
- }
- return pAssemblyName;
-}
-
-inline BOOL Assembly::GetIsInTPA()
-{
- return m_isInTPA;
-}
-
-#endif
diff --git a/src/coreclr/binder/inc/assemblybindercommon.hpp b/src/coreclr/binder/inc/assemblybindercommon.hpp
index cdc091b980244..d67e859838735 100644
--- a/src/coreclr/binder/inc/assemblybindercommon.hpp
+++ b/src/coreclr/binder/inc/assemblybindercommon.hpp
@@ -15,7 +15,6 @@
#define __BINDER__ASSEMBLY_BINDER_COMMON_HPP__
#include "bindertypes.hpp"
-#include "bindresult.hpp"
#include "bundle.h"
class AssemblyBinder;
@@ -28,76 +27,14 @@ namespace BINDER_SPACE
class AssemblyBinderCommon
{
public:
- static HRESULT BindAssembly(/* in */ AssemblyBinder *pBinder,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ bool excludeAppPaths,
- /* out */ Assembly **ppAssembly);
-
static HRESULT BindToSystem(/* in */ SString &systemDirectory,
- /* out */ Assembly **ppSystemAssembly);
-
- static HRESULT BindToSystemSatellite(/* in */ SString &systemDirectory,
- /* in */ SString &simpleName,
- /* in */ SString &cultureName,
- /* out */ Assembly **ppSystemAssembly);
-
- static HRESULT GetAssembly(/* in */ SString &assemblyPath,
- /* in */ BOOL fIsInTPA,
- /* out */ Assembly **ppAssembly,
- /* in */ BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid());
-
-#if !defined(DACCESS_COMPILE)
- static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ DefaultAssemblyBinder *pDefaultBinder,
- /* in */ AssemblyBinder *pBinder,
- /* out */ Assembly **ppAssembly);
-
- static HRESULT BindUsingPEImage(/* in */ AssemblyBinder *pBinder,
- /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
- /* in */ PEImage *pPEImage,
- /* in */ bool excludeAppPaths,
- /* [retval] [out] */ Assembly **ppAssembly);
-#endif // !defined(DACCESS_COMPILE)
+ /* out */ PEImage **ppPEImage);
static HRESULT TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind);
static HRESULT CreateDefaultBinder(DefaultAssemblyBinder** ppDefaultBinder);
static BOOL IsValidArchitecture(PEKIND kArchitecture);
-
- private:
- static HRESULT BindByName(/* in */ ApplicationContext *pApplicationContext,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ bool skipFailureCaching,
- /* in */ bool skipVersionCompatibilityCheck,
- /* in */ bool excludeAppPaths,
- /* out */ BindResult *pBindResult);
-
- static HRESULT BindLocked(/* in */ ApplicationContext *pApplicationContext,
- /* in */ AssemblyName *pAssemblyName,
- /* in */ bool skipVersionCompatibilityCheck,
- /* in */ bool excludeAppPaths,
- /* out */ BindResult *pBindResult);
-
- static HRESULT FindInExecutionContext(/* in */ ApplicationContext *pApplicationContext,
- /* in */ AssemblyName *pAssemblyName,
- /* out */ Assembly **ppAssembly);
-
- static HRESULT BindByTpaList(/* in */ ApplicationContext *pApplicationContext,
- /* in */ AssemblyName *pRequestedAssemblyName,
- /* in */ bool excludeAppPaths,
- /* out */ BindResult *pBindResult);
-
- static HRESULT Register(/* in */ ApplicationContext *pApplicationContext,
- /* in */ BindResult *pBindResult);
- static HRESULT RegisterAndGetHostChosen(/* in */ ApplicationContext *pApplicationContext,
- /* in */ LONG kContextVersion,
- /* in */ BindResult *pBindResult,
- /* out */ BindResult *pHostBindResult);
-
- static HRESULT OtherBindInterfered(/* in */ ApplicationContext *pApplicationContext,
- /* in */ BindResult *pBindResult);
};
};
diff --git a/src/coreclr/binder/inc/assemblyhashtraits.hpp b/src/coreclr/binder/inc/assemblyhashtraits.hpp
deleted file mode 100644
index c9d0cd2d7c71d..0000000000000
--- a/src/coreclr/binder/inc/assemblyhashtraits.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// AssemblyHashTraits.hpp
-//
-
-
-//
-// Defines the AssemblyHashTraits template class
-//
-// ============================================================
-
-#ifndef __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
-#define __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
-
-#include "bindertypes.hpp"
-#include "assembly.hpp"
-#include "shash.h"
-
-namespace BINDER_SPACE
-{
- class AssemblyHashTraits : public NoRemoveSHashTraits>
- {
- public:
- typedef AssemblyName* key_t;
-
- // GetKey, Equals and Hash can throw due to SString
- static const bool s_NoThrow = false;
-
- static key_t GetKey(const element_t& entry)
- {
- return entry->GetAssemblyName();
- }
- static BOOL Equals(key_t pAssemblyName1, key_t pAssemblyName2)
- {
- return pAssemblyName1->Equals(pAssemblyName2, AssemblyName::INCLUDE_DEFAULT);
- }
- static count_t Hash(key_t pAssemblyName)
- {
- return pAssemblyName->Hash(AssemblyName::INCLUDE_DEFAULT);
- }
-
- static const bool s_DestructPerEntryCleanupAction = true;
- static void OnDestructPerEntryCleanupAction(element_t elem)
- {
- elem->Release();
- }
- };
-};
-
-#endif
diff --git a/src/coreclr/binder/inc/bindertracing.h b/src/coreclr/binder/inc/bindertracing.h
index d4442086ffcfc..d6efc028b69af 100644
--- a/src/coreclr/binder/inc/bindertracing.h
+++ b/src/coreclr/binder/inc/bindertracing.h
@@ -13,7 +13,6 @@ class PEAssembly;
namespace BINDER_SPACE
{
- class Assembly;
class AssemblyName;
}
@@ -92,53 +91,6 @@ namespace BinderTracing
public: // static
static void TraceAppDomainAssemblyResolve(AssemblySpec *spec, PEAssembly *resultAssembly, Exception *exception = nullptr);
- public:
- // One of native bindContext or managedALC is expected to be non-zero. If the managed ALC is set, bindContext is ignored.
- ResolutionAttemptedOperation(BINDER_SPACE::AssemblyName *assemblyName, AssemblyBinder* bindContext, INT_PTR managedALC, const HRESULT& hr);
-
- void TraceBindResult(const BINDER_SPACE::BindResult &bindResult, bool mvidMismatch = false);
-
- void SetFoundAssembly(BINDER_SPACE::Assembly *assembly)
- {
- m_pFoundAssembly = assembly;
- }
-
- void GoToStage(Stage stage)
- {
- assert(m_stage != stage);
- assert(stage != Stage::NotYetStarted);
-
- if (!m_tracingEnabled)
- return;
-
- // Going to a different stage should only happen if the current
- // stage failed (or if the binding process wasn't yet started).
- // Firing the event at this point not only helps timing each binding
- // stage, but avoids keeping track of which stages were reached to
- // resolve the assembly.
- TraceStage(m_stage, m_hr, m_pFoundAssembly);
- m_stage = stage;
- m_exceptionMessage.Clear();
- }
-
- void SetException(Exception *ex)
- {
- if (!m_tracingEnabled)
- return;
-
- ex->GetMessage(m_exceptionMessage);
- }
-
-#ifdef FEATURE_EVENT_TRACE
- ~ResolutionAttemptedOperation()
- {
- if (!m_tracingEnabled)
- return;
-
- TraceStage(m_stage, m_hr, m_pFoundAssembly);
- }
-#endif // FEATURE_EVENT_TRACE
-
private:
// This must match the ResolutionAttemptedResult value map in ClrEtwAll.man
@@ -151,25 +103,6 @@ namespace BinderTracing
Failure = 4,
Exception = 5,
};
-
- // A reference to an HRESULT stored in the same scope as this object lets
- // us determine if the last requested stage was successful or not, regardless
- // if it was set through a function call (e.g. BindAssemblyByNameWorker()), or
- // if an exception was thrown and captured by the EX_CATCH_HRESULT() macro.
- const HRESULT &m_hr;
-
- Stage m_stage;
-
- bool m_tracingEnabled;
-
- BINDER_SPACE::AssemblyName *m_assemblyNameObject;
- PathString m_assemblyName;
- SString m_assemblyLoadContextName;
-
- SString m_exceptionMessage;
- BINDER_SPACE::Assembly *m_pFoundAssembly;
-
- void TraceStage(Stage stage, HRESULT hr, BINDER_SPACE::Assembly *resultAssembly, const WCHAR *errorMessage = nullptr);
};
// This must match the BindingPathSource value map in ClrEtwAll.man
diff --git a/src/coreclr/binder/inc/bindertypes.hpp b/src/coreclr/binder/inc/bindertypes.hpp
index 8ec573f8040d5..8592f41b7dbb6 100644
--- a/src/coreclr/binder/inc/bindertypes.hpp
+++ b/src/coreclr/binder/inc/bindertypes.hpp
@@ -21,11 +21,6 @@ namespace BINDER_SPACE
{
class AssemblyVersion;
class AssemblyName;
- class Assembly;
-
- class ApplicationContext;
-
- class BindResult;
};
typedef enum __AssemblyContentType
diff --git a/src/coreclr/binder/inc/bindresult.hpp b/src/coreclr/binder/inc/bindresult.hpp
deleted file mode 100644
index 88d1a2f4b221c..0000000000000
--- a/src/coreclr/binder/inc/bindresult.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// BindResult.hpp
-//
-
-
-//
-// Defines the BindResult class
-//
-// ============================================================
-
-#ifndef __BINDER__BIND_RESULT_HPP__
-#define __BINDER__BIND_RESULT_HPP__
-
-#include "bindertypes.hpp"
-
-namespace BINDER_SPACE
-{
- class BindResult
- {
- public:
- inline BindResult();
-
- inline AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
- inline Assembly *GetAssembly(BOOL fAddRef = FALSE);
-
- inline BOOL GetIsContextBound();
-
- inline void SetResult(Assembly *pAssembly, bool isInContext = false);
- inline void SetResult(BindResult *pBindResult);
-
- inline void SetNoResult();
- inline BOOL HaveResult();
-
- inline void Reset();
-
- struct AttemptResult
- {
- HRESULT HResult;
- ReleaseHolder Assembly;
- bool Attempted = false;
-
- void Set(const AttemptResult *result);
-
- void Reset()
- {
- Assembly = nullptr;
- Attempted = false;
- }
- };
-
- // Set attempt result for binding to existing context entry or platform assemblies
- void SetAttemptResult(HRESULT hr, Assembly *pAssembly, bool isInContext = false);
-
- const AttemptResult* GetAttempt(bool foundInContext) const;
-
- protected:
- bool m_isContextBound;
- ReleaseHolder m_pAssembly;
-
- AttemptResult m_inContextAttempt;
- AttemptResult m_applicationAssembliesAttempt;
- };
-};
-
-#endif
diff --git a/src/coreclr/binder/inc/bindresult.inl b/src/coreclr/binder/inc/bindresult.inl
deleted file mode 100644
index ab4a61c24fbd4..0000000000000
--- a/src/coreclr/binder/inc/bindresult.inl
+++ /dev/null
@@ -1,125 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// BindResult.inl
-//
-
-
-//
-// Implements the inline methods of BindResult
-//
-// ============================================================
-
-#ifndef __BINDER__BIND_RESULT_INL__
-#define __BINDER__BIND_RESULT_INL__
-
-#include "assembly.hpp"
-
-namespace BINDER_SPACE
-{
-BindResult::BindResult()
-{
- m_isContextBound = false;
- m_pAssembly = NULL;
-}
-
-AssemblyName *BindResult::GetAssemblyName(BOOL fAddRef /* = FALSE */)
-{
- Assembly *pAssembly = m_pAssembly;
- if (pAssembly == NULL)
- return NULL;
-
- return pAssembly->GetAssemblyName(fAddRef);
-}
-
-Assembly *BindResult::GetAssembly(BOOL fAddRef /* = FALSE */)
-{
- Assembly* pAssembly = m_pAssembly;
-
- if (fAddRef && (pAssembly != NULL))
- {
- pAssembly->AddRef();
- }
-
- return pAssembly;
-}
-
-BOOL BindResult::GetIsContextBound()
-{
- return m_isContextBound;
-}
-
-void BindResult::SetResult(Assembly *pAssembly, bool isInContext)
-{
- _ASSERTE(pAssembly != NULL);
-
- pAssembly->AddRef();
- m_pAssembly = pAssembly;
- m_isContextBound = isInContext;
-}
-
-void BindResult::SetResult(BindResult *pBindResult)
-{
- _ASSERTE(pBindResult != NULL);
-
- m_isContextBound = pBindResult->m_isContextBound;
- m_pAssembly = pBindResult->GetAssembly(TRUE /* fAddRef */);
-
- const AttemptResult *attempt = pBindResult->GetAttempt(true /*foundInContext*/);
- if (attempt != nullptr)
- m_inContextAttempt.Set(attempt);
-
- attempt = pBindResult->GetAttempt(false /*foundInContext*/);
- if (attempt != nullptr)
- m_applicationAssembliesAttempt.Set(attempt);
-}
-
-void BindResult::SetNoResult()
-{
- m_pAssembly = NULL;
-}
-
-BOOL BindResult::HaveResult()
-{
- return m_pAssembly != NULL;
-}
-
-void BindResult::Reset()
-{
- m_pAssembly = NULL;
- m_isContextBound = false;
- m_inContextAttempt.Reset();
- m_applicationAssembliesAttempt.Reset();
-}
-
-void BindResult::SetAttemptResult(HRESULT hr, Assembly *pAssembly, bool isInContext)
-{
- if (pAssembly != nullptr)
- pAssembly->AddRef();
-
- BindResult::AttemptResult &result = isInContext ? m_inContextAttempt : m_applicationAssembliesAttempt;
- result.Assembly = pAssembly;
- result.HResult = hr;
- result.Attempted = true;
-}
-
-const BindResult::AttemptResult* BindResult::GetAttempt(bool foundInContext) const
-{
- const BindResult::AttemptResult &result = foundInContext ? m_inContextAttempt : m_applicationAssembliesAttempt;
- return result.Attempted ? &result : nullptr;
-}
-
-void BindResult::AttemptResult::Set(const BindResult::AttemptResult *result)
-{
- BINDER_SPACE::Assembly *assembly = result->Assembly;
- if (assembly != nullptr)
- assembly->AddRef();
-
- Assembly = assembly;
- HResult = result->HResult;
- Attempted = result->Attempted;
-}
-
-}
-#endif
diff --git a/src/coreclr/binder/inc/customassemblybinder.h b/src/coreclr/binder/inc/customassemblybinder.h
index 7a89c5033b9e5..1e6c9bda1bfef 100644
--- a/src/coreclr/binder/inc/customassemblybinder.h
+++ b/src/coreclr/binder/inc/customassemblybinder.h
@@ -5,7 +5,6 @@
#ifndef __CUSTOM_ASSEMBLY_BINDER_H__
#define __CUSTOM_ASSEMBLY_BINDER_H__
-#include "applicationcontext.hpp"
#include "defaultassemblybinder.h"
#if !defined(DACCESS_COMPILE)
@@ -17,13 +16,6 @@ class CustomAssemblyBinder final : public AssemblyBinder
{
public:
- HRESULT BindUsingPEImage(PEImage* pPEImage,
- bool excludeAppPaths,
- BINDER_SPACE::Assembly** ppAssembly) override;
-
- HRESULT BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName,
- BINDER_SPACE::Assembly** ppAssembly) override;
-
AssemblyLoaderAllocator* GetLoaderAllocator() override;
bool IsDefault() override
@@ -48,8 +40,6 @@ class CustomAssemblyBinder final : public AssemblyBinder
void ReleaseLoadContext();
private:
- HRESULT BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName, BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly);
-
DefaultAssemblyBinder *m_pDefaultBinder;
// A strong GC handle to the managed AssemblyLoadContext. This handle is set when the unload of the AssemblyLoadContext is initiated
diff --git a/src/coreclr/binder/inc/defaultassemblybinder.h b/src/coreclr/binder/inc/defaultassemblybinder.h
index 3d35854e09f3f..420fc6b9e332e 100644
--- a/src/coreclr/binder/inc/defaultassemblybinder.h
+++ b/src/coreclr/binder/inc/defaultassemblybinder.h
@@ -5,7 +5,6 @@
#ifndef __DEFAULT_ASSEMBLY_BINDER_H__
#define __DEFAULT_ASSEMBLY_BINDER_H__
-#include "applicationcontext.hpp"
#include "assemblybinder.h"
class PEAssembly;
@@ -15,13 +14,6 @@ class DefaultAssemblyBinder final : public AssemblyBinder
{
public:
- HRESULT BindUsingPEImage(PEImage* pPEImage,
- bool excludeAppPaths,
- BINDER_SPACE::Assembly** ppAssembly) override;
-
- HRESULT BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName,
- BINDER_SPACE::Assembly** ppAssembly) override;
-
AssemblyLoaderAllocator* GetLoaderAllocator() override
{
// Not supported by this binder
@@ -32,21 +24,6 @@ class DefaultAssemblyBinder final : public AssemblyBinder
{
return true;
}
-
-public:
-
- HRESULT SetupBindingPaths(SString &sTrustedPlatformAssemblies,
- SString &sPlatformResourceRoots,
- SString &sAppPaths);
-
- HRESULT BindToSystem(BINDER_SPACE::Assembly **ppSystemAssembly);
-
-private:
-
- HRESULT BindAssemblyByNameWorker(
- BINDER_SPACE::AssemblyName *pAssemblyName,
- BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
- bool excludeAppPaths);
};
#endif // __DEFAULT_ASSEMBLY_BINDER_H__
diff --git a/src/coreclr/binder/inc/failurecache.hpp b/src/coreclr/binder/inc/failurecache.hpp
deleted file mode 100644
index bce67b33c50c6..0000000000000
--- a/src/coreclr/binder/inc/failurecache.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// FailureCache.hpp
-//
-
-
-//
-// Defines the FailureCache class
-//
-// ============================================================
-
-
-#ifndef __BINDER__FAILURE_CACHE_HPP__
-#define __BINDER__FAILURE_CACHE_HPP__
-
-#include "failurecachehashtraits.hpp"
-
-namespace BINDER_SPACE
-{
- class FailureCache : protected SHash
- {
- private:
- typedef SHash Hash;
- public:
- FailureCache();
- ~FailureCache();
-
- HRESULT Add(/* in */ SString &assemblyNameorPath,
- /* in */ HRESULT hrBindResult);
- HRESULT Lookup(/* in */ SString &assemblyNameorPath);
- void Remove(/* in */ SString &assemblyName);
- };
-};
-
-#endif
diff --git a/src/coreclr/binder/inc/failurecachehashtraits.hpp b/src/coreclr/binder/inc/failurecachehashtraits.hpp
deleted file mode 100644
index 1ffa96f56b198..0000000000000
--- a/src/coreclr/binder/inc/failurecachehashtraits.hpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// ============================================================
-//
-// FailureCache.hpp
-//
-
-
-//
-// Defines the FailureCache class
-//
-// ============================================================
-
-#ifndef __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
-#define __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
-
-#include "bindertypes.hpp"
-#include "sstring.h"
-#include "shash.h"
-
-namespace BINDER_SPACE
-{
- class FailureCacheEntry
- {
- public:
- inline FailureCacheEntry()
- {
- m_hrBindingResult = S_OK;
- }
- inline ~FailureCacheEntry()
- {
- // Nothing to do here
- }
-
- // Getters/Setters
- inline SString &GetAssemblyNameOrPath()
- {
- return m_assemblyNameOrPath;
- }
- inline HRESULT GetBindingResult()
- {
- return m_hrBindingResult;
- }
- inline void SetBindingResult(HRESULT hrBindingResult)
- {
- m_hrBindingResult = hrBindingResult;
- }
-
- protected:
- SString m_assemblyNameOrPath;
- HRESULT m_hrBindingResult;
- };
-
- class FailureCacheHashTraits : public DefaultSHashTraits
- {
- public:
- typedef SString& key_t;
-
- // GetKey, Equals, and Hash can throw due to SString
- static const bool s_NoThrow = false;
-
- static key_t GetKey(element_t pFailureCacheEntry)
- {
- return pFailureCacheEntry->GetAssemblyNameOrPath();
- }
- static BOOL Equals(key_t pAssemblyNameOrPath1, key_t pAssemblyNameOrPath2)
- {
- return pAssemblyNameOrPath1.EqualsCaseInsensitive(pAssemblyNameOrPath2);
- }
- static count_t Hash(key_t pAssemblyNameOrPath)
- {
- return pAssemblyNameOrPath.HashCaseInsensitive();
- }
- static element_t Null()
- {
- return NULL;
- }
- static bool IsNull(const element_t &propertyEntry)
- {
- return (propertyEntry == NULL);
- }
-
- };
-};
-
-#endif
diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def
index 7f94e9e0996a8..30a3e3ef0c37c 100644
--- a/src/coreclr/inc/CrstTypes.def
+++ b/src/coreclr/inc/CrstTypes.def
@@ -87,6 +87,7 @@ End
Crst AssemblyLoader
AcquiredBefore DeadlockDetection UniqueStack DebuggerMutex
+ ThreadStore GlobalStrLiteralMap LoaderAllocatorReferences
End
Crst AvailableClass
diff --git a/src/coreclr/inc/assemblybinderutil.h b/src/coreclr/inc/assemblybinderutil.h
index 4d6a6bcce71f7..841fa4cf34654 100644
--- a/src/coreclr/inc/assemblybinderutil.h
+++ b/src/coreclr/inc/assemblybinderutil.h
@@ -8,11 +8,6 @@
#ifndef __ASSEMBLY_BINDER_UTIL_H__
#define __ASSEMBLY_BINDER_UTIL_H__
-//=====================================================================================================================
-// Forward declarations
-typedef DPTR(BINDER_SPACE::Assembly) PTR_BINDER_SPACE_Assembly;
-typedef DPTR(AssemblyBinder) PTR_AssemblyBinder;
-
//=====================================================================================================================
#define VALIDATE_CONDITION(condition, fail_op) \
do { \
diff --git a/src/coreclr/inc/crsttypes_generated.h b/src/coreclr/inc/crsttypes_generated.h
index 79864b97db018..ed8b92d17fd8a 100644
--- a/src/coreclr/inc/crsttypes_generated.h
+++ b/src/coreclr/inc/crsttypes_generated.h
@@ -147,7 +147,7 @@ int g_rgCrstLevelMap[] =
10, // CrstAppDomainCache
3, // CrstArgBasedStubCache
3, // CrstAssemblyList
- 14, // CrstAssemblyLoader
+ 19, // CrstAssemblyLoader
4, // CrstAvailableClass
5, // CrstAvailableParamTypes
7, // CrstBaseDomain
@@ -240,7 +240,7 @@ int g_rgCrstLevelMap[] =
5, // CrstSingleUseLock
0, // CrstSpecialStatics
0, // CrstStackSampler
- 15, // CrstStaticBoxInit
+ 20, // CrstStaticBoxInit
-1, // CrstStressLog
5, // CrstStubCache
0, // CrstStubDispatchCache
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index 489f2ebc22806..963be04a7061a 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -1177,6 +1177,43 @@ void SystemDomain::Init()
#endif // _DEBUG
}
+void SystemDomain::PostStartInit()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM(););
+ }
+ CONTRACTL_END;
+
+ GCX_COOP();
+
+ // AdHoc setting logic for CoreLib, since managed code isn't available during CoreLib bootstrap
+
+ // Initialize managed default binder and set binder assembly for CoreLib
+ MethodDescCallSite initializeDefault(METHOD__ASSEMBLYLOADCONTEXT__INITIALIZE_DEFAULT);
+ ARG_SLOT arg = PtrToArgSlot(m_pSystemAssembly);
+ OBJECTREF coreLibHostAssembly = initializeDefault.Call_RetOBJECTREF(&arg);
+
+ // Default binder should be initialized
+ _ASSERTE(GetAppDomain()->GetDefaultBinder()->GetManagedAssemblyLoadContext() != NULL);
+
+ m_pSystemPEAssembly->SetHostAssemblyAdHoc(CreateHandle(coreLibHostAssembly));
+
+ m_pSystemAssembly->GetDomainAssembly()->RegisterWithHostAssembly();
+
+ // Managed and unmanaged representations of CoreLib should be correctly linked
+ _ASSERTE(((BINDERASSEMBLYREF)coreLibHostAssembly)->m_pDomainAssembly == m_pSystemAssembly->GetDomainAssembly());
+ _ASSERTE(ObjectFromHandle(m_pSystemPEAssembly->GetHostAssembly()) == coreLibHostAssembly);
+
+ // Add CoreLib to AssemblyBindingCache
+ AssemblySpec spec;
+ spec.InitializeSpec(m_pSystemPEAssembly);
+ GetAppDomain()->AddAssemblyToCache(&spec, m_pSystemAssembly->GetDomainAssembly());
+}
+
void SystemDomain::LazyInitGlobalStringLiteralMap()
{
CONTRACTL
@@ -2738,10 +2775,15 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
{
LoaderAllocator *pLoaderAllocator = NULL;
- AssemblyBinder *pAssemblyBinder = pPEAssembly->GetAssemblyBinder();
- // Assemblies loaded with CustomAssemblyBinder need to use a different LoaderAllocator if
- // marked as collectible
- pLoaderAllocator = pAssemblyBinder->GetLoaderAllocator();
+ // AssemblyBinder isn't set for CoreLib during bootstrap
+ if (!pPEAssembly->IsSystem())
+ {
+ AssemblyBinder *pAssemblyBinder = pPEAssembly->GetAssemblyBinder();
+ // Assemblies loaded with CustomAssemblyBinder need to use a different LoaderAllocator if
+ // marked as collectible
+ pLoaderAllocator = pAssemblyBinder->GetLoaderAllocator();
+ }
+
if (pLoaderAllocator == NULL)
{
pLoaderAllocator = this->GetLoaderAllocator();
@@ -2795,24 +2837,45 @@ DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
result->EnsureLoadLevel(targetLevel);
}
- if (registerNewAssembly)
+ if (registerNewAssembly && !pDomainAssembly->GetAssembly()->IsSystem()) // CoreLib bootstrap
{
- pPEAssembly->GetAssemblyBinder()->AddLoadedAssembly(pDomainAssembly->GetAssembly());
+ // Ensure to call AddLoadedAssembly under load lock
+ BaseDomain::LoadLockHolder lock(AppDomain::GetCurrentDomain());
+
+ GCX_COOP();
+
+ ASSEMBLYLOADCONTEXTREF managedALC = (ASSEMBLYLOADCONTEXTREF)ObjectFromHandle((OBJECTHANDLE)(pPEAssembly->GetAssemblyBinder()->GetManagedAssemblyLoadContext()));
+
+ GCPROTECT_BEGIN(managedALC);
+
+ MethodDescCallSite methAddLoadedAssem(METHOD__ASSEMBLYLOADCONTEXT__ADD_LOADED_EDASSEMBLY);
+ ARG_SLOT args[2] =
+ {
+ ObjToArgSlot(managedALC),
+ PtrToArgSlot(pDomainAssembly->GetAssembly())
+ };
+ methAddLoadedAssem.Call(args);
+
+ GCPROTECT_END();
}
}
else
result->EnsureLoadLevel(targetLevel);
// Cache result in all cases, since found pPEAssembly could be from a different AssemblyRef than pIdentity
- if (pIdentity == NULL)
+ if (!result->IsSystem())
{
- AssemblySpec spec;
- spec.InitializeSpec(result->GetPEAssembly());
- GetAppDomain()->AddAssemblyToCache(&spec, result);
- }
- else
- {
- GetAppDomain()->AddAssemblyToCache(pIdentity, result);
+ // CoreLib bootstrap: this method is called before managed binder available
+ if (pIdentity == NULL)
+ {
+ AssemblySpec spec;
+ spec.InitializeSpec(result->GetPEAssembly());
+ GetAppDomain()->AddAssemblyToCache(&spec, result);
+ }
+ else
+ {
+ GetAppDomain()->AddAssemblyToCache(pIdentity, result);
+ }
}
RETURN result;
@@ -3086,7 +3149,9 @@ DomainAssembly * AppDomain::FindAssembly(PEAssembly * pPEAssembly, FindAssemblyO
if (pPEAssembly->HasHostAssembly())
{
- DomainAssembly * pDA = pPEAssembly->GetHostAssembly()->GetDomainAssembly();
+ GCX_COOP();
+
+ DomainAssembly * pDA = ((BINDERASSEMBLYREF)ObjectFromHandle(pPEAssembly->GetHostAssembly()))->m_pDomainAssembly;
if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
{
return pDA;
@@ -3519,7 +3584,7 @@ PEAssembly * AppDomain::BindAssemblySpec(
PRECONDITION(pSpec->GetAppDomain() == this);
PRECONDITION(this==::GetAppDomain());
- GCX_PREEMP();
+ GCX_COOP();
BOOL fForceReThrow = FALSE;
@@ -3536,12 +3601,14 @@ PEAssembly * AppDomain::BindAssemblySpec(
{
{
- ReleaseHolder boundAssembly;
+ BINDERASSEMBLYREF boundAssembly = NULL;
+ GCPROTECT_BEGIN(boundAssembly);
+
hrBindResult = pSpec->Bind(this, &boundAssembly);
- if (boundAssembly)
+ if (boundAssembly != NULL)
{
- if (SystemDomain::SystemPEAssembly() && boundAssembly->GetAssemblyName()->IsCoreLib())
+ if (SystemDomain::SystemPEAssembly() && boundAssembly->m_isCoreLib)
{
// Avoid rebinding to another copy of CoreLib
result = SystemDomain::SystemPEAssembly();
@@ -3585,6 +3652,8 @@ PEAssembly * AppDomain::BindAssemblySpec(
}
}
}
+
+ GCPROTECT_END();
}
}
}
@@ -4862,234 +4931,6 @@ AppDomain::AssemblyIterator::Next_Unlocked(
return FALSE;
} // AppDomain::AssemblyIterator::Next_Unlocked
-#if !defined(DACCESS_COMPILE)
-
-// Returns S_OK if the assembly was successfully loaded
-HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, BINDER_SPACE::AssemblyName *pAssemblyName, DefaultAssemblyBinder *pDefaultBinder, AssemblyBinder *pBinder, BINDER_SPACE::Assembly **ppLoadedAssembly)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(pAssemblyName != NULL);
- PRECONDITION(ppLoadedAssembly != NULL);
- }
- CONTRACTL_END;
-
- HRESULT hr = E_FAIL;
-
- // Switch to COOP mode since we are going to work with managed references
- GCX_COOP();
-
- struct
- {
- ASSEMBLYNAMEREF oRefAssemblyName;
- ASSEMBLYREF oRefLoadedAssembly;
- } _gcRefs;
-
- ZeroMemory(&_gcRefs, sizeof(_gcRefs));
-
- GCPROTECT_BEGIN(_gcRefs);
-
- BINDER_SPACE::Assembly *pResolvedAssembly = NULL;
-
- bool fResolvedAssembly = false;
- BinderTracing::ResolutionAttemptedOperation tracer{pAssemblyName, 0 /*binderID*/, pManagedAssemblyLoadContextToBindWithin, hr};
-
- // Allocate an AssemblyName managed object
- _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(CoreLibBinder::GetClass(CLASS__ASSEMBLY_NAME));
-
- // Initialize the AssemblyName object
- AssemblySpec::InitializeAssemblyNameRef(pAssemblyName, &_gcRefs.oRefAssemblyName);
-
- bool isSatelliteAssemblyRequest = !pAssemblyName->IsNeutralCulture();
-
- EX_TRY
- {
- if (pDefaultBinder != NULL)
- {
- // Step 2 (of CustomAssemblyBinder::BindAssemblyByName) - Invoke Load method
- // This is not invoked for TPA Binder since it always returns NULL.
- tracer.GoToStage(BinderTracing::ResolutionAttemptedOperation::Stage::AssemblyLoadContextLoad);
-
- // Finally, setup arguments for invocation
- MethodDescCallSite methLoadAssembly(METHOD__ASSEMBLYLOADCONTEXT__RESOLVE);
-
- // Setup the arguments for the call
- ARG_SLOT args[2] =
- {
- PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
- ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
- };
-
- // Make the call
- _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
- if (_gcRefs.oRefLoadedAssembly != NULL)
- {
- fResolvedAssembly = true;
- }
-
- hr = fResolvedAssembly ? S_OK : COR_E_FILENOTFOUND;
-
- // Step 3 (of CustomAssemblyBinder::BindAssemblyByName)
- if (!fResolvedAssembly && !isSatelliteAssemblyRequest)
- {
- tracer.GoToStage(BinderTracing::ResolutionAttemptedOperation::Stage::DefaultAssemblyLoadContextFallback);
-
- // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
- // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
- //
- // Switch to pre-emp mode before calling into the binder
- GCX_PREEMP();
- BINDER_SPACE::Assembly *pCoreCLRFoundAssembly = NULL;
- hr = pDefaultBinder->BindUsingAssemblyName(pAssemblyName, &pCoreCLRFoundAssembly);
- if (SUCCEEDED(hr))
- {
- _ASSERTE(pCoreCLRFoundAssembly != NULL);
- pResolvedAssembly = pCoreCLRFoundAssembly;
- fResolvedAssembly = true;
- }
- }
- }
-
- if (!fResolvedAssembly && isSatelliteAssemblyRequest)
- {
- // Step 4 (of CustomAssemblyBinder::BindAssemblyByName)
- //
- // Attempt to resolve it using the ResolveSatelliteAssembly method.
- // Finally, setup arguments for invocation
- tracer.GoToStage(BinderTracing::ResolutionAttemptedOperation::Stage::ResolveSatelliteAssembly);
-
- MethodDescCallSite methResolveSateliteAssembly(METHOD__ASSEMBLYLOADCONTEXT__RESOLVESATELLITEASSEMBLY);
-
- // Setup the arguments for the call
- ARG_SLOT args[2] =
- {
- PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
- ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
- };
-
- // Make the call
- _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methResolveSateliteAssembly.Call_RetOBJECTREF(args);
- if (_gcRefs.oRefLoadedAssembly != NULL)
- {
- // Set the flag indicating we found the assembly
- fResolvedAssembly = true;
- }
-
- hr = fResolvedAssembly ? S_OK : COR_E_FILENOTFOUND;
- }
-
- if (!fResolvedAssembly)
- {
- // Step 5 (of CustomAssemblyBinder::BindAssemblyByName)
- //
- // If we couldn't resolve the assembly using TPA LoadContext as well, then
- // attempt to resolve it using the Resolving event.
- // Finally, setup arguments for invocation
- tracer.GoToStage(BinderTracing::ResolutionAttemptedOperation::Stage::AssemblyLoadContextResolvingEvent);
-
- MethodDescCallSite methResolveUsingEvent(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT);
-
- // Setup the arguments for the call
- ARG_SLOT args[2] =
- {
- PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
- ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
- };
-
- // Make the call
- _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methResolveUsingEvent.Call_RetOBJECTREF(args);
- if (_gcRefs.oRefLoadedAssembly != NULL)
- {
- // Set the flag indicating we found the assembly
- fResolvedAssembly = true;
- }
-
- hr = fResolvedAssembly ? S_OK : COR_E_FILENOTFOUND;
- }
-
- if (fResolvedAssembly && pResolvedAssembly == NULL)
- {
- // If we are here, assembly was successfully resolved via Load or Resolving events.
- _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
-
- // We were able to get the assembly loaded. Now, get its name since the host could have
- // performed the resolution using an assembly with different name.
- DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
- PEAssembly *pLoadedPEAssembly = NULL;
- bool fFailLoad = false;
- if (!pDomainAssembly)
- {
- // Reflection emitted assemblies will not have a domain assembly.
- fFailLoad = true;
- }
- else
- {
- pLoadedPEAssembly = pDomainAssembly->GetPEAssembly();
- if (!pLoadedPEAssembly->HasHostAssembly())
- {
- // Reflection emitted assemblies will not have a domain assembly.
- fFailLoad = true;
- }
- }
-
- // The loaded assembly's BINDER_SPACE::Assembly* is saved as HostAssembly in PEAssembly
- if (fFailLoad)
- {
- PathString name;
- pAssemblyName->GetDisplayName(name, BINDER_SPACE::AssemblyName::INCLUDE_ALL);
- COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
- }
-
- // For collectible assemblies, ensure that the parent loader allocator keeps the assembly's loader allocator
- // alive for all its lifetime.
- if (pDomainAssembly->IsCollectible())
- {
- LoaderAllocator *pResultAssemblyLoaderAllocator = pDomainAssembly->GetLoaderAllocator();
- LoaderAllocator *pParentLoaderAllocator = pBinder->GetLoaderAllocator();
- if (pParentLoaderAllocator == NULL)
- {
- // The AssemblyLoadContext for which we are resolving the Assembly is not collectible.
- COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
- }
-
- _ASSERTE(pResultAssemblyLoaderAllocator);
- pParentLoaderAllocator->EnsureReference(pResultAssemblyLoaderAllocator);
- }
-
- pResolvedAssembly = pLoadedPEAssembly->GetHostAssembly();
- }
-
- if (fResolvedAssembly)
- {
- _ASSERTE(pResolvedAssembly != NULL);
-
- // Get the BINDER_SPACE::Assembly reference to return back to.
- *ppLoadedAssembly = clr::SafeAddRef(pResolvedAssembly);
- hr = S_OK;
-
- tracer.SetFoundAssembly(static_cast(pResolvedAssembly));
- }
- else
- {
- hr = COR_E_FILENOTFOUND;
- }
- }
- EX_HOOK
- {
- Exception* ex = GET_EXCEPTION();
- tracer.SetException(ex);
- }
- EX_END_HOOK
-
- GCPROTECT_END();
-
- return hr;
-}
-#endif // !defined(DACCESS_COMPILE)
-
//approximate size of loader data
//maintained for each assembly
#define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp
index e72080f914e9a..ceea8d35b82d3 100644
--- a/src/coreclr/vm/appdomain.hpp
+++ b/src/coreclr/vm/appdomain.hpp
@@ -2363,6 +2363,7 @@ class SystemDomain : public BaseDomain
void operator delete(void *pMem);
#endif
void Init();
+ void PostStartInit();
void Stop();
static void LazyInitGlobalStringLiteralMap();
static void LazyInitFrozenObjectsHeap();
diff --git a/src/coreclr/vm/assemblybinder.cpp b/src/coreclr/vm/assemblybinder.cpp
index 36c07df10b2f4..2ffc7b97d6e78 100644
--- a/src/coreclr/vm/assemblybinder.cpp
+++ b/src/coreclr/vm/assemblybinder.cpp
@@ -8,25 +8,6 @@
#ifndef DACCESS_COMPILE
-HRESULT AssemblyBinder::BindAssemblyByName(AssemblyNameData* pAssemblyNameData,
- BINDER_SPACE::Assembly** ppAssembly)
-{
- _ASSERTE(pAssemblyNameData != nullptr && ppAssembly != nullptr);
-
- HRESULT hr = S_OK;
- *ppAssembly = nullptr;
-
- ReleaseHolder pAssemblyName;
- SAFE_NEW(pAssemblyName, BINDER_SPACE::AssemblyName);
- IF_FAIL_GO(pAssemblyName->Init(*pAssemblyNameData));
-
- hr = BindUsingAssemblyName(pAssemblyName, ppAssembly);
-
-Exit:
- return hr;
-}
-
-
NativeImage* AssemblyBinder::LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName)
{
STANDARD_VM_CONTRACT;
@@ -41,131 +22,6 @@ NativeImage* AssemblyBinder::LoadNativeImage(Module* componentModule, LPCUTF8 na
return nativeImage;
}
-#ifdef FEATURE_READYTORUN
-static void MvidMismatchFatalError(GUID mvidActual, GUID mvidExpected, LPCUTF8 simpleName, bool compositeComponent, LPCUTF8 assemblyRequirementName)
-{
- CHAR assemblyMvidText[GUID_STR_BUFFER_LEN];
- GuidToLPSTR(mvidActual, assemblyMvidText);
-
- CHAR componentMvidText[GUID_STR_BUFFER_LEN];
- GuidToLPSTR(mvidExpected, componentMvidText);
-
- SString message;
- if (compositeComponent)
- {
- message.Printf("MVID mismatch between loaded assembly '%s' (MVID = %s) and an assembly with the same simple name embedded in the native image '%s' (MVID = %s)",
- simpleName,
- assemblyMvidText,
- assemblyRequirementName,
- componentMvidText);
- }
- else
- {
- message.Printf("MVID mismatch between loaded assembly '%s' (MVID = %s) and version of assembly '%s' expected by assembly '%s' (MVID = %s)",
- simpleName,
- assemblyMvidText,
- simpleName,
- assemblyRequirementName,
- componentMvidText);
- }
-
- EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_FAILFAST, message.GetUnicode());
-}
-
-void AssemblyBinder::DeclareDependencyOnMvid(LPCUTF8 simpleName, GUID mvid, bool compositeComponent, LPCUTF8 imageName)
-{
- _ASSERTE(imageName != NULL);
-
- // If the table is empty, then we didn't fill it with all the loaded assemblies as they were loaded. Record this detail, and fix after adding the dependency
- bool addAllLoadedModules = false;
- if (m_assemblySimpleNameMvidCheckHash.GetCount() == 0)
- {
- addAllLoadedModules = true;
- }
-
- SimpleNameToExpectedMVIDAndRequiringAssembly* foundElem = (SimpleNameToExpectedMVIDAndRequiringAssembly*)m_assemblySimpleNameMvidCheckHash.LookupPtr(simpleName);
- if (foundElem == NULL)
- {
- SimpleNameToExpectedMVIDAndRequiringAssembly newElem(simpleName, mvid, compositeComponent, imageName);
- m_assemblySimpleNameMvidCheckHash.Add(newElem);
- }
- else
- {
- // Elem already exists. Determine if the existing elem is another one with the same mvid, in which case just record that a dependency is in play.
- // If the existing elem has a different mvid, fail.
- if (IsEqualGUID(mvid, foundElem->Mvid))
- {
- // Mvid matches exactly.
- if (foundElem->AssemblyRequirementName == NULL)
- {
- foundElem->AssemblyRequirementName = imageName;
- foundElem->CompositeComponent = compositeComponent;
- }
- }
- else
- {
- MvidMismatchFatalError(foundElem->Mvid, mvid, simpleName, compositeComponent, imageName);
- }
- }
-
- if (addAllLoadedModules)
- {
- for (COUNT_T assemblyIndex = 0; assemblyIndex < m_loadedAssemblies.GetCount(); assemblyIndex++)
- {
- DeclareLoadedAssembly(m_loadedAssemblies[assemblyIndex]);
- }
- }
-}
-
-void AssemblyBinder::DeclareLoadedAssembly(Assembly* loadedAssembly)
-{
- // If table is empty, then no mvid dependencies have been declared, so we don't need to record this information
- if (m_assemblySimpleNameMvidCheckHash.GetCount() == 0)
- return;
-
- GUID mvid;
- loadedAssembly->GetMDImport()->GetScopeProps(NULL, &mvid);
-
- LPCUTF8 simpleName = loadedAssembly->GetSimpleName();
-
- SimpleNameToExpectedMVIDAndRequiringAssembly* foundElem = (SimpleNameToExpectedMVIDAndRequiringAssembly*)m_assemblySimpleNameMvidCheckHash.LookupPtr(simpleName);
- if (foundElem == NULL)
- {
- SimpleNameToExpectedMVIDAndRequiringAssembly newElem(simpleName, mvid, false, NULL);
- m_assemblySimpleNameMvidCheckHash.Add(newElem);
- }
- else
- {
- // Elem already exists. Determine if the existing elem is another one with the same mvid, in which case do nothing. Everything is fine here.
- // If the existing elem has a different mvid, but isn't a dependency on exact mvid elem, then set the mvid to all 0.
- // If the existing elem has a different mvid, and is a dependency on exact mvid elem, then we've hit a fatal error.
- if (IsEqualGUID(mvid, foundElem->Mvid))
- {
- // Mvid matches exactly.
- }
- else if (foundElem->AssemblyRequirementName == NULL)
- {
- // Another loaded assembly, set the stored Mvid to all zeroes to indicate that it isn't a unique mvid
- memset(&foundElem->Mvid, 0, sizeof(GUID));
- }
- else
- {
- MvidMismatchFatalError(mvid, foundElem->Mvid, simpleName, foundElem->CompositeComponent, foundElem->AssemblyRequirementName);
- }
- }
-}
-#endif // FEATURE_READYTORUN
-
-void AssemblyBinder::AddLoadedAssembly(Assembly* loadedAssembly)
-{
- BaseDomain::LoadLockHolder lock(AppDomain::GetCurrentDomain());
- m_loadedAssemblies.Append(loadedAssembly);
-
-#ifdef FEATURE_READYTORUN
- DeclareLoadedAssembly(loadedAssembly);
-#endif // FEATURE_READYTORUN
-}
-
void AssemblyBinder::GetNameForDiagnosticsFromManagedALC(INT_PTR managedALC, /* out */ SString& alcName)
{
if (managedALC == GetAppDomain()->GetDefaultBinder()->GetManagedAssemblyLoadContext())
diff --git a/src/coreclr/vm/assemblybinder.h b/src/coreclr/vm/assemblybinder.h
index 8fa57302cfa40..3d157edbb4ce2 100644
--- a/src/coreclr/vm/assemblybinder.h
+++ b/src/coreclr/vm/assemblybinder.h
@@ -5,7 +5,6 @@
#define _ASSEMBLYBINDER_H
#include
-#include "../binder/inc/applicationcontext.hpp"
class PEImage;
class NativeImage;
@@ -18,10 +17,6 @@ class AssemblyBinder
{
public:
- HRESULT BindAssemblyByName(AssemblyNameData* pAssemblyNameData, BINDER_SPACE::Assembly** ppAssembly);
- virtual HRESULT BindUsingPEImage(PEImage* pPEImage, bool excludeAppPaths, BINDER_SPACE::Assembly** ppAssembly) = 0;
- virtual HRESULT BindUsingAssemblyName(BINDER_SPACE::AssemblyName* pAssemblyName, BINDER_SPACE::Assembly** ppAssembly) = 0;
-
///
/// Get LoaderAllocator for binders that contain it. For other binders, return NULL.
///
@@ -32,11 +27,6 @@ class AssemblyBinder
///
virtual bool IsDefault() = 0;
- inline BINDER_SPACE::ApplicationContext* GetAppContext()
- {
- return &m_appContext;
- }
-
INT_PTR GetManagedAssemblyLoadContext()
{
return m_ptrManagedAssemblyLoadContext;
@@ -48,86 +38,17 @@ class AssemblyBinder
}
NativeImage* LoadNativeImage(Module* componentModule, LPCUTF8 nativeImageName);
- void AddLoadedAssembly(Assembly* loadedAssembly);
void GetNameForDiagnostics(/*out*/ SString& alcName);
static void GetNameForDiagnosticsFromManagedALC(INT_PTR managedALC, /* out */ SString& alcName);
static void GetNameForDiagnosticsFromSpec(AssemblySpec* spec, /*out*/ SString& alcName);
-#ifdef FEATURE_READYTORUN
- // Must be called under the LoadLock
- void DeclareDependencyOnMvid(LPCUTF8 simpleName, GUID mvid, bool compositeComponent, LPCUTF8 imageName);
-#endif // FEATURE_READYTORUN
-
private:
-#ifdef FEATURE_READYTORUN
- // Must be called under the LoadLock
- void DeclareLoadedAssembly(Assembly* loadedAssembly);
-
- struct SimpleNameToExpectedMVIDAndRequiringAssembly
- {
- LPCUTF8 SimpleName;
-
- // When an assembly is loaded, this Mvid value will be set to the mvid of the assembly. If there are multiple assemblies
- // with different mvid's loaded with the same simple name, then the Mvid value will be set to all zeroes.
- GUID Mvid;
-
- // If an assembly of this simple name is not yet loaded, but a depedency on an exact mvid is registered, then this field will
- // be filled in with the simple assembly name of the first assembly loaded with an mvid dependency.
- LPCUTF8 AssemblyRequirementName;
-
- // To disambiguate between component images of a composite image and requirements from a non-composite --inputbubble assembly, use this bool
- bool CompositeComponent;
-
- SimpleNameToExpectedMVIDAndRequiringAssembly() :
- SimpleName(NULL),
- Mvid({0}),
- AssemblyRequirementName(NULL),
- CompositeComponent(false)
- {
- }
-
- SimpleNameToExpectedMVIDAndRequiringAssembly(LPCUTF8 simpleName, GUID mvid, bool compositeComponent, LPCUTF8 AssemblyRequirementName) :
- SimpleName(simpleName),
- Mvid(mvid),
- AssemblyRequirementName(AssemblyRequirementName),
- CompositeComponent(compositeComponent)
- {}
-
- static SimpleNameToExpectedMVIDAndRequiringAssembly GetNull() { return SimpleNameToExpectedMVIDAndRequiringAssembly(); }
- bool IsNull() const { return SimpleName == NULL; }
- };
-
- class SimpleNameWithMvidHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits >
- {
- public:
- typedef LPCUTF8 key_t;
-
- static SimpleNameToExpectedMVIDAndRequiringAssembly Null() { return SimpleNameToExpectedMVIDAndRequiringAssembly::GetNull(); }
- static bool IsNull(const SimpleNameToExpectedMVIDAndRequiringAssembly& e) { return e.IsNull(); }
-
- static LPCUTF8 GetKey(const SimpleNameToExpectedMVIDAndRequiringAssembly& e) { return e.SimpleName; }
-
- static BOOL Equals(LPCUTF8 a, LPCUTF8 b) { return strcmp(a, b) == 0; } // Use a case senstive comparison here even though
- // assembly name matching should be case insensitive. Case insensitive
- // comparisons are slow and have throwing scenarios, and this hash table
- // provides a best-effort match to prevent problems, not perfection
-
- static count_t Hash(LPCUTF8 a) { return HashStringA(a); } // As above, this is a case sensitive hash
- };
-
- SHash m_assemblySimpleNameMvidCheckHash;
-#endif // FEATURE_READYTORUN
-
- BINDER_SPACE::ApplicationContext m_appContext;
-
// A GC handle to the managed AssemblyLoadContext.
// It is a long weak handle for collectible AssemblyLoadContexts and strong handle for non-collectible ones.
INT_PTR m_ptrManagedAssemblyLoadContext;
-
- SArray m_loadedAssemblies;
};
#endif
diff --git a/src/coreclr/vm/assemblynative.cpp b/src/coreclr/vm/assemblynative.cpp
index b7fdcd6a21bff..5357b9d7ca038 100644
--- a/src/coreclr/vm/assemblynative.cpp
+++ b/src/coreclr/vm/assemblynative.cpp
@@ -135,7 +135,6 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma
CONTRACT_END;
Assembly *pLoadedAssembly = NULL;
- ReleaseHolder pAssembly;
// Set the caller's assembly to be CoreLib
DomainAssembly *pCallersAssembly = SystemDomain::System()->SystemAssembly()->GetDomainAssembly();
@@ -149,7 +148,30 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma
HRESULT hr = S_OK;
PTR_AppDomain pCurDomain = GetAppDomain();
- hr = pBinder->BindUsingPEImage(pImage, excludeAppPaths, &pAssembly);
+
+ GCX_COOP();
+
+ struct {
+ OBJECTREF pBinder;
+ BINDERASSEMBLYREF pAssembly;
+ } gc;
+
+ gc.pBinder = ObjectFromHandle((OBJECTHANDLE)(pBinder->GetManagedAssemblyLoadContext()));
+ gc.pAssembly = NULL;
+
+ GCPROTECT_BEGIN(gc);
+
+ MethodDescCallSite methBind(METHOD__ASSEMBLYLOADCONTEXT__BIND_USING_PEIMAGE, &gc.pBinder);
+ ARG_SLOT args[4] =
+ {
+ ObjToArgSlot(gc.pBinder),
+ PtrToArgSlot(pImage),
+ BoolToArgSlot(excludeAppPaths),
+ PtrToArgSlot(&gc.pAssembly)
+ };
+ hr = methBind.Call_RetHR(args);
+
+ GCPROTECT_END();
if (hr != S_OK)
{
@@ -171,7 +193,7 @@ Assembly* AssemblyNative::LoadFromPEImage(AssemblyBinder* pBinder, PEImage *pIma
}
}
- PEAssemblyHolder pPEAssembly(PEAssembly::Open(pAssembly->GetPEImage(), pAssembly));
+ PEAssemblyHolder pPEAssembly(PEAssembly::Open(gc.pAssembly->m_peImage, gc.pAssembly));
bindOperation.SetResult(pPEAssembly.GetValue());
DomainAssembly *pDomainAssembly = pCurDomain->LoadDomainAssembly(&spec, pPEAssembly, FILE_LOADED);
@@ -1379,13 +1401,33 @@ extern "C" void QCALLTYPE AssemblyNative_TraceAssemblyLoadFromResolveHandlerInvo
}
// static
-extern "C" void QCALLTYPE AssemblyNative_TraceSatelliteSubdirectoryPathProbed(LPCWSTR filePath, HRESULT hr)
+extern "C" void QCALLTYPE AssemblyNative_TracePathProbed(LPCWSTR filePath, uint16_t source, HRESULT hr)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ BinderTracing::PathProbed(filePath, static_cast(source), hr);
+
+ END_QCALL;
+}
+
+// static
+extern "C" void QCALLTYPE AssemblyNative_TraceResolutionAttempted(LPCWSTR assemblyName, uint16_t stage, LPCWSTR assemblyLoadContextName, uint16_t result, LPCWSTR resultAssemblyName, LPCWSTR resultAssemblyPath, LPCWSTR errorMsg)
{
QCALL_CONTRACT;
BEGIN_QCALL;
- BinderTracing::PathProbed(filePath, BinderTracing::PathSource::SatelliteSubdirectory, hr);
+ FireEtwResolutionAttempted(
+ GetClrInstanceId(),
+ assemblyName,
+ stage,
+ assemblyLoadContextName,
+ result,
+ resultAssemblyName,
+ resultAssemblyPath,
+ errorMsg);
END_QCALL;
}
@@ -1453,3 +1495,257 @@ extern "C" BOOL QCALLTYPE AssemblyNative_IsApplyUpdateSupported()
return result;
}
+
+extern "C" IMDInternalImport * QCALLTYPE AssemblyNative_GetMDImport(Assembly * pAssembly)
+{
+ QCALL_CONTRACT;
+
+ IMDInternalImport* result = NULL;
+
+ BEGIN_QCALL;
+
+ result = pAssembly->GetMDImport();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" LPCUTF8 QCALLTYPE AssemblyNative_GetSimpleNameNative(Assembly * pAssembly)
+{
+ QCALL_CONTRACT;
+
+ LPCUTF8 result = NULL;
+
+ BEGIN_QCALL;
+
+ result = pAssembly->GetSimpleName();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" void QCALLTYPE AssemblyNative_GetExposedObject(Assembly * pAssembly, QCall::ObjectHandleOnStack rtAssembly)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ GCX_COOP();
+ rtAssembly.Set(pAssembly->GetExposedObject());
+
+ END_QCALL;
+}
+
+extern "C" PEImage * QCALLTYPE AssemblyNative_GetPEImage(Assembly * pAssembly)
+{
+ QCALL_CONTRACT;
+
+ PEImage* result = NULL;
+
+ BEGIN_QCALL;
+
+ result = pAssembly->GetPEAssembly()->GetPEImage();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" void QCALLTYPE AssemblyNative_SetSymbolBytes(Assembly * pAssembly, BYTE* ptrSymbolArray, int32_t cbSymbolArrayLength)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pAssembly->GetModule()->SetSymbolBytes(ptrSymbolArray, (DWORD)cbSymbolArrayLength);
+
+ END_QCALL;
+}
+
+extern "C" IMDInternalImport * QCALLTYPE PEImage_BinderAcquireImport(PEImage * pPEImage, DWORD * pdwPAFlags)
+{
+ QCALL_CONTRACT;
+
+ IMDInternalImport* ret = NULL;
+
+ BEGIN_QCALL;
+
+ // The same logic of BinderAcquireImport
+
+ PEImageLayout* pLayout = pPEImage->GetOrCreateLayout(PEImageLayout::LAYOUT_ANY);
+
+ // CheckCorHeader includes check of NT headers too
+ if (!pLayout->CheckCorHeader())
+ ThrowHR(COR_E_ASSEMBLYEXPECTED);
+
+ if (!pLayout->CheckFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ pPEImage->GetPEKindAndMachine(&pdwPAFlags[0], &pdwPAFlags[1]);
+
+ ret = pPEImage->GetMDImport();
+ if (!ret)
+ {
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+
+ // No AddRef
+
+ END_QCALL;
+
+ return ret;
+}
+
+extern "C" HRESULT QCALLTYPE PEImage_BinderAcquirePEImage(LPCWSTR wszAssemblyPath, PEImage * *ppPEImage, BundleFileLocation bundleFileLocation)
+{
+ QCALL_CONTRACT;
+
+ HRESULT hr = S_OK;
+
+ BEGIN_QCALL;
+
+ *ppPEImage = NULL;
+
+ EX_TRY
+ {
+ PEImageHolder pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default, bundleFileLocation);
+
+ // Make sure that the IL image can be opened.
+ hr = pImage->TryOpenFile();
+ if (SUCCEEDED(hr))
+ {
+ *ppPEImage = pImage.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ END_QCALL;
+
+ return hr;
+}
+
+extern "C" void QCALLTYPE PEImage_Release(PEImage * pPEImage)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pPEImage->Release();
+
+ END_QCALL;
+}
+
+extern "C" void QCALLTYPE PEImage_GetMVID(PEImage * pPEImage, GUID* pMVID)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ pPEImage->GetMVID(pMVID);
+
+ END_QCALL;
+}
+
+extern "C" LPCWSTR QCALLTYPE PEImage_GetPath(PEImage * pPEImage)
+{
+ QCALL_CONTRACT;
+
+ LPCWSTR result = NULL;
+
+ BEGIN_QCALL;
+
+ result = pPEImage->GetPath().GetUnicode();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" PEAssembly * QCALLTYPE DomainAssembly_GetPEAssembly(DomainAssembly * pDomainAssembly)
+{
+ QCALL_CONTRACT;
+
+ PEAssembly* result = NULL;
+
+ BEGIN_QCALL;
+
+ result = pDomainAssembly->GetPEAssembly();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" void QCALLTYPE DomainAssembly_EnsureReferenceBinder(DomainAssembly * pDomainAssembly, AssemblyBinder * pBinder)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ LoaderAllocator *pResultAssemblyLoaderAllocator = pDomainAssembly->GetLoaderAllocator();
+ LoaderAllocator *pParentLoaderAllocator = pBinder->GetLoaderAllocator();
+ if (pParentLoaderAllocator == NULL)
+ {
+ // The AssemblyLoadContext for which we are resolving the Assembly is not collectible.
+ COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
+ }
+
+ _ASSERTE(pResultAssemblyLoaderAllocator);
+ pParentLoaderAllocator->EnsureReference(pResultAssemblyLoaderAllocator);
+
+ END_QCALL;
+}
+
+extern "C" INT_PTR QCALLTYPE PEAssembly_GetHostAssembly(PEAssembly * pPEAssembly)
+{
+ QCALL_CONTRACT;
+
+ INT_PTR result = NULL;
+
+ BEGIN_QCALL;
+
+ result = (INT_PTR)pPEAssembly->GetHostAssembly();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" BOOL QCALLTYPE Bundle_AppIsBundle()
+{
+ QCALL_CONTRACT;
+
+ BOOL result = FALSE;
+
+ BEGIN_QCALL;
+
+ result = Bundle::AppIsBundle();
+
+ END_QCALL;
+
+ return result;
+}
+
+extern "C" void QCALLTYPE Bundle_ProbeAppBundle(LPCWSTR path, BOOL pathIsBundleRelative, BundleFileLocation* result)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ *result = Bundle::ProbeAppBundle(SString(path), pathIsBundleRelative);
+
+ END_QCALL;
+}
+
+extern "C" void QCALLTYPE Bundle_GetAppBundleBasePath(QCall::StringHandleOnStack path)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ path.Set(Bundle::AppBundle->BasePath().GetUnicode());
+
+ END_QCALL;
+}
diff --git a/src/coreclr/vm/assemblynative.hpp b/src/coreclr/vm/assemblynative.hpp
index 80ae3da8c2bd5..150b0943150d3 100644
--- a/src/coreclr/vm/assemblynative.hpp
+++ b/src/coreclr/vm/assemblynative.hpp
@@ -139,8 +139,9 @@ extern "C" void QCALLTYPE AssemblyNative_TraceAssemblyResolveHandlerInvoked(LPCW
extern "C" void QCALLTYPE AssemblyNative_TraceAssemblyLoadFromResolveHandlerInvoked(LPCWSTR assemblyName, bool isTrackedAssembly, LPCWSTR requestingAssemblyPath, LPCWSTR requestedAssemblyPath);
-extern "C" void QCALLTYPE AssemblyNative_TraceSatelliteSubdirectoryPathProbed(LPCWSTR filePath, HRESULT hr);
+extern "C" void QCALLTYPE AssemblyNative_TracePathProbed(LPCWSTR filePath, uint16_t source, HRESULT hr);
+extern "C" void QCALLTYPE AssemblyNative_TraceResolutionAttempted(LPCWSTR assemblyName, uint16_t stage, LPCWSTR assemblyLoadContextName, uint16_t result, LPCWSTR resultAssemblyName, LPCWSTR resultAssemblyPath, LPCWSTR errorMsg);
extern "C" void QCALLTYPE AssemblyNative_ApplyUpdate(QCall::AssemblyHandle assembly, UINT8* metadataDelta, INT32 metadataDeltaLength, UINT8* ilDelta, INT32 ilDeltaLength, UINT8* pdbDelta, INT32 pdbDeltaLength);
@@ -148,4 +149,35 @@ extern "C" BOOL QCALLTYPE AssemblyNative_IsApplyUpdateSupported();
extern "C" void QCALLTYPE AssemblyName_InitializeAssemblySpec(NativeAssemblyNameParts* pAssemblyNameParts, BaseAssemblySpec* pAssemblySpec);
+extern "C" IMDInternalImport * QCALLTYPE AssemblyNative_GetMDImport(Assembly * pAssembly);
+
+extern "C" LPCUTF8 QCALLTYPE AssemblyNative_GetSimpleNameNative(Assembly * pAssembly);
+
+extern "C" void QCALLTYPE AssemblyNative_GetExposedObject(Assembly * pAssembly, QCall::ObjectHandleOnStack rtAssembly);
+
+extern "C" PEImage * QCALLTYPE AssemblyNative_GetPEImage(Assembly * pAssembly);
+
+extern "C" void QCALLTYPE AssemblyNative_SetSymbolBytes(Assembly * pAssembly, BYTE* ptrSymbolArray, int32_t cbSymbolArrayLength);
+
+extern "C" IMDInternalImport * QCALLTYPE PEImage_BinderAcquireImport(PEImage * pPEImage, DWORD * pdwPAFlags);
+
+extern "C" HRESULT QCALLTYPE PEImage_BinderAcquirePEImage(LPCWSTR wszAssemblyPath, PEImage * *ppPEImage, BundleFileLocation bundleFileLocation);
+
+extern "C" void QCALLTYPE PEImage_Release(PEImage * pPEImage);
+
+extern "C" void QCALLTYPE PEImage_GetMVID(PEImage * pPEImage, GUID* pMVID);
+
+extern "C" LPCWSTR QCALLTYPE PEImage_GetPath(PEImage * pPEImage);
+
+extern "C" PEAssembly * QCALLTYPE DomainAssembly_GetPEAssembly(DomainAssembly * pDomainAssembly);
+
+extern "C" void QCALLTYPE DomainAssembly_EnsureReferenceBinder(DomainAssembly * pDomainAssembly, AssemblyBinder * pBinder);
+
+extern "C" INT_PTR QCALLTYPE PEAssembly_GetHostAssembly(PEAssembly * pPEAssembly);
+
+extern "C" BOOL QCALLTYPE Bundle_AppIsBundle();
+
+extern "C" void QCALLTYPE Bundle_ProbeAppBundle(LPCWSTR path, BOOL pathIsBundleRelative, BundleFileLocation* result);
+
+extern "C" void QCALLTYPE Bundle_GetAppBundleBasePath(QCall::StringHandleOnStack path);
#endif
diff --git a/src/coreclr/vm/assemblyspec.cpp b/src/coreclr/vm/assemblyspec.cpp
index a4872b732097b..867997c67690c 100644
--- a/src/coreclr/vm/assemblyspec.cpp
+++ b/src/coreclr/vm/assemblyspec.cpp
@@ -209,8 +209,12 @@ void AssemblySpec::InitializeSpec(PEAssembly * pFile)
{
AssemblyBinder* pExpectedBinder = pFile->GetAssemblyBinder();
// We should always have the binding context in the PEAssembly.
- _ASSERTE(pExpectedBinder != NULL);
- SetBinder(pExpectedBinder);
+ if (!IsCoreLib())
+ {
+ // Binder of CoreLib will be set afterwards.
+ _ASSERTE(pExpectedBinder != NULL);
+ SetBinder(pExpectedBinder);
+ }
}
}
diff --git a/src/coreclr/vm/assemblyspec.hpp b/src/coreclr/vm/assemblyspec.hpp
index 23a7c96e64756..25b8155ea3433 100644
--- a/src/coreclr/vm/assemblyspec.hpp
+++ b/src/coreclr/vm/assemblyspec.hpp
@@ -171,7 +171,7 @@ class AssemblySpec : public BaseAssemblySpec
HRESULT Bind(
AppDomain* pAppDomain,
- BINDER_SPACE::Assembly** ppAssembly);
+ BINDERASSEMBLYREF* ppAssembly);
Assembly *LoadAssembly(FileLoadLevel targetLevel,
BOOL fThrowOnFileNotFound = TRUE);
diff --git a/src/coreclr/vm/assemblyspecbase.h b/src/coreclr/vm/assemblyspecbase.h
index c9db2e04b9f83..113c3117c1c1c 100644
--- a/src/coreclr/vm/assemblyspecbase.h
+++ b/src/coreclr/vm/assemblyspecbase.h
@@ -15,7 +15,14 @@
#ifndef __ASSEMBLY_SPEC_BASE_H__
#define __ASSEMBLY_SPEC_BASE_H__
-#include "../binder/inc/assembly.hpp"
+#include "../binder/inc/assemblyname.hpp"
+#include "assemblybinder.h"
+
+#include "../binder/inc/defaultassemblybinder.h"
+
+#if !defined(DACCESS_COMPILE)
+#include "../binder/inc/customassemblybinder.h"
+#endif // !defined(DACCESS_COMPILE)
#include "baseassemblyspec.h"
#include "baseassemblyspec.inl"
diff --git a/src/coreclr/vm/baseassemblyspec.cpp b/src/coreclr/vm/baseassemblyspec.cpp
index 469535aa7f4db..4bbb2a1b0c33f 100644
--- a/src/coreclr/vm/baseassemblyspec.cpp
+++ b/src/coreclr/vm/baseassemblyspec.cpp
@@ -20,7 +20,7 @@ BOOL BaseAssemblySpec::IsCoreLib()
{
THROWS;
INSTANCE_CHECK;
- GC_TRIGGERS;
+ GC_NOTRIGGER;
MODE_ANY;
INJECT_FAULT(COMPlusThrowOM(););
}
diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp
index 5cb624d3d7b36..ee3e21bbf59a8 100644
--- a/src/coreclr/vm/ceeload.cpp
+++ b/src/coreclr/vm/ceeload.cpp
@@ -2990,7 +2990,7 @@ DomainAssembly * Module::LoadAssemblyImpl(mdAssemblyRef kAssemblyRef)
_ASSERTE(
pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find CoreLib (see AppDomain::FindCachedFile)
!pDomainAssembly->IsLoaded() || // GetAssemblyIfLoaded will not find not-yet-loaded assemblies
- GetAssemblyIfLoaded(kAssemblyRef, NULL, FALSE, pDomainAssembly->GetPEAssembly()->GetHostAssembly()->GetBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
+ GetAssemblyIfLoaded(kAssemblyRef, NULL, FALSE, pDomainAssembly->GetPEAssembly()->GetAssemblyBinder()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
if (pDomainAssembly->GetAssembly() != NULL)
{
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index f60d447f0b2ae..1b6176de2756d 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -968,6 +968,8 @@ void EEStartupHelper()
}
#endif // _DEBUG
+ // Initialize managed binder. Ensure g_fEEStarted and COM initialized before executing managed code.
+ SystemDomain::System()->PostStartInit();
ErrExit: ;
}
diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h
index 8b8ff9e842b3a..386aeecdb3e49 100644
--- a/src/coreclr/vm/common.h
+++ b/src/coreclr/vm/common.h
@@ -105,6 +105,7 @@ typedef VPTR(class AppDomain) PTR_AppDomain;
typedef DPTR(class ArrayBase) PTR_ArrayBase;
typedef DPTR(class Assembly) PTR_Assembly;
typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject;
+typedef DPTR(class BinderAssemblyObject) PTR_BinderAssemblyObject;
typedef DPTR(class AssemblyLoadContextBaseObject) PTR_AssemblyLoadContextBaseObject;
typedef DPTR(class AssemblyBinder) PTR_AssemblyBinder;
typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject;
diff --git a/src/coreclr/vm/coreassemblyspec.cpp b/src/coreclr/vm/coreassemblyspec.cpp
index 886df7e4afbe5..069dfff4e9d91 100644
--- a/src/coreclr/vm/coreassemblyspec.cpp
+++ b/src/coreclr/vm/coreassemblyspec.cpp
@@ -21,18 +21,18 @@
#include "strongnameinternal.h"
#include "../binder/inc/assemblyidentity.hpp"
-#include "../binder/inc/assembly.hpp"
#include "../binder/inc/assemblyname.hpp"
#include "../binder/inc/assemblybindercommon.hpp"
-#include "../binder/inc/applicationcontext.hpp"
-HRESULT AssemblySpec::Bind(AppDomain *pAppDomain, BINDER_SPACE::Assembly** ppAssembly)
+HRESULT AssemblySpec::Bind(AppDomain *pAppDomain, BINDERASSEMBLYREF* ppAssembly)
{
CONTRACTL
{
INSTANCE_CHECK;
- STANDARD_VM_CHECK;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
PRECONDITION(CheckPointer(ppAssembly));
PRECONDITION(CheckPointer(pAppDomain));
PRECONDITION(IsCoreLib() == FALSE); // This should never be called for CoreLib (explicit loading)
@@ -41,11 +41,21 @@ HRESULT AssemblySpec::Bind(AppDomain *pAppDomain, BINDER_SPACE::Assembly** ppAs
HRESULT hr=S_OK;
+ GCX_COOP();
+
+ struct
+ {
+ OBJECTREF pBinder;
+ BINDERASSEMBLYREF pPrivAsm;
+ } gc;
+
// Have a default binding context setup
- AssemblyBinder *pBinder = GetBinderFromParentAssembly(pAppDomain);
+ gc.pBinder = ObjectFromHandle((OBJECTHANDLE)GetBinderFromParentAssembly(pAppDomain)->GetManagedAssemblyLoadContext());
+ gc.pPrivAsm = NULL;
+
+ _ASSERTE(gc.pBinder != NULL);
- ReleaseHolder pPrivAsm;
- _ASSERTE(pBinder != NULL);
+ GCPROTECT_BEGIN(gc);
if (IsCoreLibSatellite())
{
@@ -57,21 +67,41 @@ HRESULT AssemblySpec::Bind(AppDomain *pAppDomain, BINDER_SPACE::Assembly** ppAs
if (m_context.szLocale != NULL)
SString(SString::Utf8Literal, m_context.szLocale).ConvertToUnicode(sCultureName);
- hr = BINDER_SPACE::AssemblyBinderCommon::BindToSystemSatellite(sSystemDirectory, sSimpleName, sCultureName, &pPrivAsm);
+ MethodDescCallSite methSatellite(METHOD__ASSEMBLYBINDERCOMMON__BIND_TO_SYSTEM_SATELLITE);
+ ARG_SLOT args[4] =
+ {
+ PtrToArgSlot(sSystemDirectory.GetUnicode()),
+ PtrToArgSlot(sSimpleName.GetUnicode()),
+ PtrToArgSlot(sCultureName.GetUnicode()),
+ PtrToArgSlot(&gc.pPrivAsm)
+ };
+
+ hr = methSatellite.Call_RetHR(args);
}
else
{
AssemblyNameData assemblyNameData = { 0 };
PopulateAssemblyNameData(assemblyNameData);
- hr = pBinder->BindAssemblyByName(&assemblyNameData, &pPrivAsm);
+
+ MethodDescCallSite methBindAssemblyByName(METHOD__ASSEMBLYLOADCONTEXT__BIND_ASSEMBLY_BY_NAME, &gc.pBinder);
+ ARG_SLOT args[3] =
+ {
+ ObjToArgSlot(gc.pBinder),
+ PtrToArgSlot(&assemblyNameData),
+ PtrToArgSlot(&gc.pPrivAsm)
+ };
+
+ hr = methBindAssemblyByName.Call_RetHR(args);
}
if (SUCCEEDED(hr))
{
- _ASSERTE(pPrivAsm != nullptr);
- *ppAssembly = pPrivAsm.Extract();
+ _ASSERTE(gc.pPrivAsm != NULL);
+ *ppAssembly = gc.pPrivAsm;
}
+ GCPROTECT_END();
+
return hr;
}
diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h
index 17f74503bdc28..8ab11a27d6fc2 100644
--- a/src/coreclr/vm/corelib.h
+++ b/src/coreclr/vm/corelib.h
@@ -865,11 +865,8 @@ DEFINE_FIELD_U(_id, AssemblyLoadContextBaseObject, _id)
DEFINE_FIELD_U(_state, AssemblyLoadContextBaseObject, _state)
DEFINE_FIELD_U(_isCollectible, AssemblyLoadContextBaseObject, _isCollectible)
DEFINE_CLASS(ASSEMBLYLOADCONTEXT, Loader, AssemblyLoadContext)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVE, Resolve, SM_IntPtr_AssemblyName_RetAssemblyBase)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLL, ResolveUnmanagedDll, SM_Str_IntPtr_RetIntPtr)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLLUSINGEVENT, ResolveUnmanagedDllUsingEvent, SM_Str_AssemblyBase_IntPtr_RetIntPtr)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUSINGEVENT, ResolveUsingResolvingEvent, SM_IntPtr_AssemblyName_RetAssemblyBase)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVESATELLITEASSEMBLY, ResolveSatelliteAssembly, SM_IntPtr_AssemblyName_RetAssemblyBase)
DEFINE_FIELD(ASSEMBLYLOADCONTEXT, ASSEMBLY_LOAD, AssemblyLoad)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ON_ASSEMBLY_LOAD, OnAssemblyLoad, SM_Assembly_RetVoid)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ON_RESOURCE_RESOLVE, OnResourceResolve, SM_Assembly_Str_RetAssembly)
@@ -877,7 +874,26 @@ DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ON_TYPE_RESOLVE, OnTypeResolve,
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ON_ASSEMBLY_RESOLVE, OnAssemblyResolve, SM_Assembly_Str_RetAssembly)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, START_ASSEMBLY_LOAD, StartAssemblyLoad, SM_RefGuid_RefGuid_RetVoid)
DEFINE_METHOD(ASSEMBLYLOADCONTEXT, STOP_ASSEMBLY_LOAD, StopAssemblyLoad, SM_RefGuid_RetVoid)
-DEFINE_METHOD(ASSEMBLYLOADCONTEXT, INITIALIZE_DEFAULT_CONTEXT, InitializeDefaultContext, SM_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, INITIALIZE_DEFAULT, InitializeDefault, SM_IntPtr_RetBinderAssembly)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, ADD_LOADED_EDASSEMBLY, AddLoadedAssembly, IM_IntPtr_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, BIND_USING_PEIMAGE, BindUsingPEImage, IM_IntPtr_Bool_RefBinderAssembly_RetInt)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, BIND_ASSEMBLY_BY_NAME, BindAssemblyByName, IM_PtrVoid_RefBinderAssembly_RetInt)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, DECLARE_DEPENDENCY_ON_MVID, DeclareDependencyOnMvid, IM_PtrByte_RefGuid_Bool_PtrByte_RetVoid)
+DEFINE_METHOD(ASSEMBLYLOADCONTEXT, SETUP_BINDING_PATHS, SetupBindingPaths, SM_PtrChar_PtrChar_PtrChar_RetVoid)
+
+DEFINE_CLASS(ASSEMBLYBINDERCOMMON, Loader, AssemblyBinderCommon)
+DEFINE_METHOD(ASSEMBLYBINDERCOMMON, BIND_TO_SYSTEM_SATELLITE, BindToSystemSatellite, SM_PtrChar_PtrChar_PtrChar_RefBinderAssembly_RetInt)
+
+// Managed binder types
+
+DEFINE_CLASS(BINDER_ASSEMBLY, Loader, BinderAssembly)
+DEFINE_CLASS_U(Loader, BinderAssembly, BinderAssemblyObject)
+DEFINE_FIELD_U(m_binder, BinderAssemblyObject, m_binder)
+DEFINE_FIELD_U(m_assemblyName, BinderAssemblyObject, m_assemblyName)
+DEFINE_FIELD_U(m_peImage, BinderAssemblyObject, m_peImage)
+DEFINE_FIELD_U(m_pDomainAssembly, BinderAssemblyObject, m_pDomainAssembly)
+DEFINE_FIELD_U(m_isInTPA, BinderAssemblyObject, m_isInTPA)
+DEFINE_FIELD_U(m_isCoreLib, BinderAssemblyObject, m_isCoreLib)
DEFINE_CLASS(VALUE_TYPE, System, ValueType)
DEFINE_METHOD(VALUE_TYPE, GET_HASH_CODE, GetHashCode, IM_RetInt)
diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index c0e4091af38a8..961d169db5e2e 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -627,16 +627,17 @@ HRESULT CorHost2::CreateAppDomainWithManager(
pDomain->SetNativeDllSearchDirectories(pwzNativeDllSearchDirectories);
{
- SString sTrustedPlatformAssemblies(pwzTrustedPlatformAssemblies);
- SString sPlatformResourceRoots(pwzPlatformResourceRoots);
- SString sAppPaths(pwzAppPaths);
-
- DefaultAssemblyBinder *pBinder = pDomain->GetDefaultBinder();
- _ASSERTE(pBinder != NULL);
- IfFailThrow(pBinder->SetupBindingPaths(
- sTrustedPlatformAssemblies,
- sPlatformResourceRoots,
- sAppPaths));
+ GCX_COOP();
+
+ MethodDescCallSite methSetupBindingPaths(METHOD__ASSEMBLYLOADCONTEXT__SETUP_BINDING_PATHS);
+ ARG_SLOT args[3] =
+ {
+ PtrToArgSlot(pwzTrustedPlatformAssemblies),
+ PtrToArgSlot(pwzPlatformResourceRoots),
+ PtrToArgSlot(pwzAppPaths)
+ };
+
+ methSetupBindingPaths.Call(args);
}
#if defined(TARGET_UNIX)
diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp
index 75995f477a32f..623bc24a0e054 100644
--- a/src/coreclr/vm/domainassembly.cpp
+++ b/src/coreclr/vm/domainassembly.cpp
@@ -721,7 +721,8 @@ void DomainAssembly::RegisterWithHostAssembly()
if (GetPEAssembly()->HasHostAssembly())
{
- GetPEAssembly()->GetHostAssembly()->SetDomainAssembly(this);
+ GCX_COOP();
+ ((BINDERASSEMBLYREF)ObjectFromHandle(GetPEAssembly()->GetHostAssembly()))->m_pDomainAssembly = this;
}
}
@@ -737,7 +738,8 @@ void DomainAssembly::UnregisterFromHostAssembly()
if (GetPEAssembly()->HasHostAssembly())
{
- GetPEAssembly()->GetHostAssembly()->SetDomainAssembly(nullptr);
+ GCX_COOP();
+ ((BINDERASSEMBLYREF)ObjectFromHandle(GetPEAssembly()->GetHostAssembly()))->m_pDomainAssembly = nullptr;
}
}
diff --git a/src/coreclr/vm/domainassembly.h b/src/coreclr/vm/domainassembly.h
index 40262412f4753..494c0b5c05c0e 100644
--- a/src/coreclr/vm/domainassembly.h
+++ b/src/coreclr/vm/domainassembly.h
@@ -308,6 +308,7 @@ class DomainAssembly final
friend class Assembly;
friend class Module;
friend class FileLoadLock;
+ friend class SystemDomain;
DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoaderAllocator);
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index 98a38b8603419..ac988be2c101a 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -180,6 +180,9 @@ FCFuncStart(gMetaDataImport)
FCFuncElement("GetPInvokeMap", MetaDataImport::GetPInvokeMap)
FCFuncElement("IsValidToken", MetaDataImport::IsValidToken)
FCFuncElement("GetMarshalAs", MetaDataImport::GetMarshalAs)
+
+ FCFuncElement("GetAssemblyFromScope", MetaDataImport::GetAssemblyFromScope)
+ FCFuncElement("GetAssemblyProps", MetaDataImport::GetAssemblyProps)
FCFuncEnd()
FCFuncStart(gSignatureNative)
diff --git a/src/coreclr/vm/managedmdimport.cpp b/src/coreclr/vm/managedmdimport.cpp
index 8ab00a85f5320..4e8d922726773 100644
--- a/src/coreclr/vm/managedmdimport.cpp
+++ b/src/coreclr/vm/managedmdimport.cpp
@@ -440,6 +440,32 @@ FCIMPL3(HRESULT, MetaDataImport::GetMemberRefProps,
}
FCIMPLEND
+FCIMPL2(HRESULT, MetaDataImport::GetAssemblyFromScope,
+ IMDInternalImport* pScope,
+ mdAssembly* ptkAssembly)
+{
+ FCALL_CONTRACT;
+
+ return pScope->GetAssemblyFromScope(ptkAssembly);
+}
+FCIMPLEND
+
+FCIMPL8(HRESULT, MetaDataImport::GetAssemblyProps,
+ IMDInternalImport* pScope,
+ mdAssembly mda,
+ const void** ppbPublicKey,
+ ULONG* pcbPublicKey,
+ ULONG* pulHashAlgId,
+ LPCSTR* pszName,
+ AssemblyMetaDataInternal* pMetaData,
+ DWORD* pdwAsselblyFlags)
+{
+ FCALL_CONTRACT;
+
+ return pScope->GetAssemblyProps(mda, ppbPublicKey, pcbPublicKey, pulHashAlgId, pszName, pMetaData, pdwAsselblyFlags);
+}
+FCIMPLEND
+
#if defined(_MSC_VER) && defined(TARGET_X86)
#pragma optimize("", on) // restore command line optimization defaults
#endif
diff --git a/src/coreclr/vm/managedmdimport.hpp b/src/coreclr/vm/managedmdimport.hpp
index 4db05291d6fd0..1968bdd1c6775 100644
--- a/src/coreclr/vm/managedmdimport.hpp
+++ b/src/coreclr/vm/managedmdimport.hpp
@@ -67,6 +67,17 @@ class MetaDataImport
LPUTF8* marshalType,
LPUTF8* marshalCookie,
INT32* iidParamIndex);
+
+ static FCDECL2(HRESULT, GetAssemblyFromScope, IMDInternalImport* pScope, mdAssembly* ptkAssembly);
+ static FCDECL8(HRESULT, GetAssemblyProps,
+ IMDInternalImport* pScope,
+ mdAssembly mda,
+ const void** ppbPublicKey,
+ ULONG* pcbPublicKey,
+ ULONG* pulHashAlgId,
+ LPCSTR* pszName,
+ AssemblyMetaDataInternal* pMetaData,
+ DWORD* pdwAsselblyFlags);
};
extern "C" void QCALLTYPE MetadataImport_Enum(
diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h
index 35e6472b4b8da..e97335255ea58 100644
--- a/src/coreclr/vm/metasig.h
+++ b/src/coreclr/vm/metasig.h
@@ -632,6 +632,14 @@ DEFINE_METASIG(SM(PtrByte_RetStr, P(b), s))
DEFINE_METASIG(SM(Str_RetPtrByte, s, P(b)))
DEFINE_METASIG(SM(PtrByte_RetVoid, P(b), v))
+DEFINE_METASIG(SM(PtrChar_PtrChar_PtrChar_RetVoid, P(u) P(u) P(u), v))
+DEFINE_METASIG_T(IM(IntPtr_Bool_RefBinderAssembly_RetInt, I F r(C(BINDER_ASSEMBLY)), i))
+DEFINE_METASIG_T(IM(PtrVoid_RefBinderAssembly_RetInt, P(v) r(C(BINDER_ASSEMBLY)), i))
+DEFINE_METASIG_T(SM(PtrChar_PtrChar_PtrChar_RefBinderAssembly_RetInt, P(u) P(u) P(u) r(C(BINDER_ASSEMBLY)), i))
+DEFINE_METASIG_T(IM(PtrByte_RefGuid_Bool_PtrByte_RetVoid, P(b) r(g(GUID)) F P(b), v))
+DEFINE_METASIG_T(IM(RetLoaderAllocator, ,C(LOADERALLOCATOR)))
+DEFINE_METASIG_T(SM(IntPtr_RetBinderAssembly, I, C(BINDER_ASSEMBLY)))
+
// Undefine macros in case we include the file again in the compilation unit
#undef DEFINE_METASIG
diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h
index a282dd867e94a..af78621d05810 100644
--- a/src/coreclr/vm/object.h
+++ b/src/coreclr/vm/object.h
@@ -1433,6 +1433,9 @@ class AssemblyLoadContextBaseObject : public Object
// Modifying the order or fields of this object may require other changes to the
// classlib class definition of this object.
#ifdef TARGET_64BIT
+ OBJECTREF _appContext;
+ OBJECTREF _assemblySimpleNameMvidCheckHash;
+ OBJECTREF _loadedAssemblies;
OBJECTREF _unloadLock;
OBJECTREF _resolvingUnmanagedDll;
OBJECTREF _resolving;
@@ -1444,6 +1447,9 @@ class AssemblyLoadContextBaseObject : public Object
CLR_BOOL _isCollectible;
#else // TARGET_64BIT
int64_t _id; // On 32-bit platforms this 64-bit value type is larger than a pointer so JIT places it first
+ OBJECTREF _appContext;
+ OBJECTREF _assemblySimpleNameMvidCheckHash;
+ OBJECTREF _loadedAssemblies;
OBJECTREF _unloadLock;
OBJECTREF _resolvingUnmanagedDll;
OBJECTREF _resolving;
@@ -1503,6 +1509,8 @@ typedef REF THREADBASEREF;
typedef REF ASSEMBLYREF;
+typedef REF BINDERASSEMBLYREF;
+
typedef REF ASSEMBLYLOADCONTEXTREF;
typedef REF ASSEMBLYNAMEREF;
@@ -1547,6 +1555,7 @@ typedef PTR_ReflectMethodObject REFLECTMETHODREF;
typedef PTR_ReflectFieldObject REFLECTFIELDREF;
typedef PTR_ThreadBaseObject THREADBASEREF;
typedef PTR_AssemblyBaseObject ASSEMBLYREF;
+typedef PTR_BinderAssemblyObject BINDERASSEMBLYREF;
typedef PTR_AssemblyLoadContextBaseObject ASSEMBLYLOADCONTEXTREF;
typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF;
@@ -1558,6 +1567,27 @@ typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF;
#endif //USE_CHECKED_OBJECTREFS
+class PEImage;
+
+#include
+// managed System.Runtime.Loader.BinderAssembly
+class BinderAssemblyObject : public Object
+{
+public:
+ OBJECTREF m_assemblyName;
+ AssemblyBinder* m_binder;
+ PEImage* m_peImage;
+ DomainAssembly* m_pDomainAssembly;
+ CLR_BOOL m_isInTPA;
+ CLR_BOOL m_isCoreLib;
+
+ PTR_AssemblyBinder GetBinder()
+ {
+ return PTR_AssemblyBinder(m_binder);
+ }
+};
+#include
+
#define PtrToArgSlot(ptr) ((ARG_SLOT)(SIZE_T)(ptr))
#define ArgSlotToPtr(s) ((LPVOID)(SIZE_T)(s))
diff --git a/src/coreclr/vm/peassembly.cpp b/src/coreclr/vm/peassembly.cpp
index c7c618b485283..6272b993a12a6 100644
--- a/src/coreclr/vm/peassembly.cpp
+++ b/src/coreclr/vm/peassembly.cpp
@@ -16,8 +16,8 @@
#include "peimagelayout.inl"
#include "invokeutil.h"
#include "strongnameinternal.h"
+#include "object.h"
-#include "../binder/inc/applicationcontext.hpp"
#include "../binder/inc/assemblybindercommon.hpp"
#include "sha1.h"
@@ -125,10 +125,12 @@ BOOL PEAssembly::Equals(PEAssembly *pPEAssembly)
// because another thread beats it; the losing thread will pick up the PEAssembly in the cache.
if (pPEAssembly->HasHostAssembly() && this->HasHostAssembly())
{
- AssemblyBinder* otherBinder = pPEAssembly->GetHostAssembly()->GetBinder();
- AssemblyBinder* thisBinder = this->GetHostAssembly()->GetBinder();
+ GCX_COOP();
- if (otherBinder != thisBinder || otherBinder == NULL)
+ BINDERASSEMBLYREF otherAssembly = (BINDERASSEMBLYREF)ObjectFromHandle(pPEAssembly->GetHostAssembly());
+ BINDERASSEMBLYREF thisAssembly = (BINDERASSEMBLYREF)ObjectFromHandle(this->GetHostAssembly());
+
+ if (otherAssembly->m_binder != thisAssembly->m_binder || otherAssembly->m_binder == NULL)
return FALSE;
}
@@ -653,18 +655,20 @@ ULONG PEAssembly::GetPEImageTimeDateStamp()
#ifndef DACCESS_COMPILE
PEAssembly::PEAssembly(
- BINDER_SPACE::Assembly* pBindResultInfo,
+ BINDERASSEMBLYREF pBindResultInfo,
IMetaDataEmit* pEmit,
BOOL isSystem,
PEImage * pPEImage /*= NULL*/,
- BINDER_SPACE::Assembly * pHostAssembly /*= NULL*/)
+ BINDERASSEMBLYREF pHostAssembly /*= NULL*/)
{
CONTRACTL
{
CONSTRUCTOR_CHECK;
PRECONDITION(CheckPointer(pEmit, NULL_OK));
- PRECONDITION(pBindResultInfo == NULL || pPEImage == NULL);
- STANDARD_VM_CHECK;
+ // PRECONDITION(pBindResultInfo == NULL || pPEImage == NULL); // disabled for corelib
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
}
CONTRACTL_END;
@@ -681,7 +685,7 @@ PEAssembly::PEAssembly(
m_pHostAssembly = nullptr;
m_pFallbackBinder = nullptr;
- pPEImage = pBindResultInfo ? pBindResultInfo->GetPEImage() : pPEImage;
+ pPEImage = (pBindResultInfo != NULL) ? pBindResultInfo->m_peImage : pPEImage;
if (pPEImage)
{
_ASSERTE(pPEImage->CheckUniqueInstance());
@@ -718,17 +722,16 @@ PEAssembly::PEAssembly(
// Set the host assembly and binding context as the AssemblySpec initialization
// for CoreCLR will expect to have it set.
- if (pHostAssembly != nullptr)
+ if (pHostAssembly != NULL)
{
- m_pHostAssembly = clr::SafeAddRef(pHostAssembly);
+ m_pHostAssembly = GetAppDomain()->CreateHandle(pHostAssembly);
}
- if(pBindResultInfo != nullptr)
+ if (pBindResultInfo != NULL)
{
// Cannot have both pHostAssembly and a coreclr based bind
- _ASSERTE(pHostAssembly == nullptr);
- pBindResultInfo = clr::SafeAddRef(pBindResultInfo);
- m_pHostAssembly = pBindResultInfo;
+ _ASSERTE(m_pHostAssembly == NULL);
+ m_pHostAssembly = GetAppDomain()->CreateHandle(pBindResultInfo);
}
#ifdef LOGGING
@@ -741,16 +744,22 @@ PEAssembly::PEAssembly(
PEAssembly *PEAssembly::Open(
PEImage * pPEImageIL,
- BINDER_SPACE::Assembly * pHostAssembly)
+ BINDERASSEMBLYREF pManagedHostAssembly)
{
- STANDARD_VM_CONTRACT;
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
PEAssembly * pPEAssembly = new PEAssembly(
- nullptr, // BindResult
+ NULL, // BindResult
nullptr, // IMetaDataEmit
FALSE, // isSystem
pPEImageIL,
- pHostAssembly);
+ pManagedHostAssembly);
return pPEAssembly;
}
@@ -791,7 +800,10 @@ PEAssembly::~PEAssembly()
m_PEImage->Release();
if (m_pHostAssembly != NULL)
- m_pHostAssembly->Release();
+ {
+ DestroyHandle(m_pHostAssembly);
+ m_pHostAssembly = NULL;
+ }
}
/* static */
@@ -830,15 +842,22 @@ PEAssembly *PEAssembly::DoOpenSystem()
CONTRACT_END;
ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1);
- ReleaseHolder pBoundAssembly;
- IfFailThrow(GetAppDomain()->GetDefaultBinder()->BindToSystem(&pBoundAssembly));
+ ReleaseHolder pBoundAssembly;
+
+ StackSString systemPath(SystemDomain::System()->SystemDirectory());
+ IfFailThrow(BINDER_SPACE::AssemblyBinderCommon::BindToSystem(systemPath, &pBoundAssembly));
+
+ {
+ GCX_COOP();
- RETURN new PEAssembly(pBoundAssembly, NULL, TRUE);
+ // HostAssembly is set afterwards for CoreLib
+ RETURN new PEAssembly(NULL, NULL, TRUE, pBoundAssembly);
+ }
}
-PEAssembly* PEAssembly::Open(BINDER_SPACE::Assembly* pBindResult)
+PEAssembly* PEAssembly::Open(BINDERASSEMBLYREF pManagedBindResult)
{
- return new PEAssembly(pBindResult,NULL,/*isSystem*/ false);
+ return new PEAssembly(pManagedBindResult,NULL,/*isSystem*/ false);
};
/* static */
@@ -856,7 +875,11 @@ PEAssembly *PEAssembly::Create(IMetaDataAssemblyEmit *pAssemblyEmit)
// we have.)
SafeComHolder pEmit;
pAssemblyEmit->QueryInterface(IID_IMetaDataEmit, (void **)&pEmit);
- RETURN new PEAssembly(NULL, pEmit, FALSE);
+
+ {
+ GCX_COOP();
+ RETURN new PEAssembly(NULL, pEmit, FALSE);
+ }
}
#endif // #ifndef DACCESS_COMPILE
@@ -1096,10 +1119,11 @@ PTR_AssemblyBinder PEAssembly::GetAssemblyBinder()
PTR_AssemblyBinder pBinder = NULL;
- PTR_BINDER_SPACE_Assembly pHostAssembly = GetHostAssembly();
+ OBJECTHANDLE pHostAssembly = GetHostAssembly();
if (pHostAssembly)
{
- pBinder = pHostAssembly->GetBinder();
+ GCX_COOP();
+ pBinder = ((BINDERASSEMBLYREF)ObjectFromHandle(pHostAssembly))->GetBinder();
}
else
{
diff --git a/src/coreclr/vm/peassembly.h b/src/coreclr/vm/peassembly.h
index 49a9a3ffc5b21..3a40ecf2f52ee 100644
--- a/src/coreclr/vm/peassembly.h
+++ b/src/coreclr/vm/peassembly.h
@@ -301,12 +301,19 @@ class PEAssembly final
}
// Returns a non-AddRef'ed BINDER_SPACE::Assembly*
- PTR_BINDER_SPACE_Assembly GetHostAssembly()
+ OBJECTHANDLE GetHostAssembly()
{
STATIC_CONTRACT_LIMITED_METHOD;
return m_pHostAssembly;
}
+ // Set host assembly after PEAssembly was created.
+ // Adhoc for CoreLib
+ void SetHostAssemblyAdHoc(OBJECTHANDLE pHostAssembly)
+ {
+ m_pHostAssembly = pHostAssembly;
+ }
+
// Returns the AssemblyBinder* instance associated with the PEAssembly
// which owns the context into which the current PEAssembly was loaded.
// For Dynamic assemblies this is the fallback binder.
@@ -334,12 +341,12 @@ class PEAssembly final
static PEAssembly* Open(
PEImage* pPEImageIL,
- BINDER_SPACE::Assembly* pHostAssembly);
+ BINDERASSEMBLYREF pHostAssembly);
// This opens the canonical System.Private.CoreLib.dll
static PEAssembly* OpenSystem();
- static PEAssembly* Open(BINDER_SPACE::Assembly* pBindResult);
+ static PEAssembly* Open(BINDERASSEMBLYREF pBindResult);
static PEAssembly* Create(IMetaDataAssemblyEmit* pEmit);
@@ -368,12 +375,13 @@ class PEAssembly final
~PEAssembly() {};
PEAssembly() = default;
#else
+
PEAssembly(
- BINDER_SPACE::Assembly* pBindResultInfo,
+ BINDERASSEMBLYREF pBindResultInfo,
IMetaDataEmit* pEmit,
BOOL isSystem,
PEImage* pPEImageIL = NULL,
- BINDER_SPACE::Assembly* pHostAssembly = NULL
+ BINDERASSEMBLYREF pHostAssembly = NULL
);
~PEAssembly();
@@ -424,7 +432,7 @@ class PEAssembly final
Volatile m_refCount;
bool m_isSystem;
- PTR_BINDER_SPACE_Assembly m_pHostAssembly;
+ OBJECTHANDLE m_pHostAssembly;
// For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder.
// An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies,
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 99e76824a5df9..32fbe60ba72f4 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -202,6 +202,11 @@ static const Entry s_QCall[] =
DllImportEntry(AssemblyNative_IsApplyUpdateSupported)
DllImportEntry(AssemblyNative_InitializeAssemblyLoadContext)
DllImportEntry(AssemblyNative_PrepareForAssemblyLoadContextRelease)
+ DllImportEntry(AssemblyNative_GetMDImport)
+ DllImportEntry(AssemblyNative_GetSimpleNameNative)
+ DllImportEntry(AssemblyNative_GetExposedObject)
+ DllImportEntry(AssemblyNative_GetPEImage)
+ DllImportEntry(AssemblyNative_SetSymbolBytes)
DllImportEntry(AssemblyNative_LoadFromPath)
DllImportEntry(AssemblyNative_LoadFromStream)
#ifdef TARGET_WINDOWS
@@ -211,11 +216,23 @@ static const Entry s_QCall[] =
DllImportEntry(AssemblyNative_TraceResolvingHandlerInvoked)
DllImportEntry(AssemblyNative_TraceAssemblyResolveHandlerInvoked)
DllImportEntry(AssemblyNative_TraceAssemblyLoadFromResolveHandlerInvoked)
- DllImportEntry(AssemblyNative_TraceSatelliteSubdirectoryPathProbed)
DllImportEntry(AssemblyNative_GetLoadedAssemblies)
+ DllImportEntry(AssemblyNative_TracePathProbed)
+ DllImportEntry(AssemblyNative_TraceResolutionAttempted)
DllImportEntry(AssemblyNative_GetAssemblyCount)
DllImportEntry(AssemblyNative_GetEntryAssembly)
DllImportEntry(AssemblyNative_GetExecutingAssembly)
+ DllImportEntry(PEImage_BinderAcquireImport)
+ DllImportEntry(PEImage_BinderAcquirePEImage)
+ DllImportEntry(PEImage_Release)
+ DllImportEntry(PEImage_GetMVID)
+ DllImportEntry(PEImage_GetPath)
+ DllImportEntry(DomainAssembly_GetPEAssembly)
+ DllImportEntry(DomainAssembly_EnsureReferenceBinder)
+ DllImportEntry(PEAssembly_GetHostAssembly)
+ DllImportEntry(Bundle_AppIsBundle)
+ DllImportEntry(Bundle_ProbeAppBundle)
+ DllImportEntry(Bundle_GetAppBundleBasePath)
#if defined(FEATURE_MULTICOREJIT)
DllImportEntry(MultiCoreJIT_InternalSetProfileRoot)
DllImportEntry(MultiCoreJIT_InternalStartProfile)
diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp
index 4facca3a37bfb..feafad1906bf6 100644
--- a/src/coreclr/vm/readytoruninfo.cpp
+++ b/src/coreclr/vm/readytoruninfo.cpp
@@ -758,7 +758,28 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, LoaderAllocator* pLoaderAllocat
LPCSTR assemblyName;
IfFailThrow(pNativeMDImport->GetAssemblyRefProps(assemblyRef, NULL, NULL, &assemblyName, NULL, NULL, NULL, NULL));
- binder->DeclareDependencyOnMvid(assemblyName, *componentMvid, pNativeImage != NULL, pModule != NULL ? pModule->GetSimpleName() : pNativeImage->GetFileName());
+ {
+ GCX_COOP();
+
+ OBJECTREF alc = ObjectFromHandle((OBJECTHANDLE)binder->GetManagedAssemblyLoadContext());
+
+ GCPROTECT_BEGIN(alc);
+
+ MethodDescCallSite methDeclareDependencyOnMvid(METHOD__ASSEMBLYLOADCONTEXT__DECLARE_DEPENDENCY_ON_MVID);
+ ARG_SLOT args[5] =
+ {
+ ObjToArgSlot(alc),
+ PtrToArgSlot(componentMvid),
+ PtrToArgSlot(assemblyName),
+ BoolToArgSlot(pNativeImage != NULL),
+ PtrToArgSlot(pModule != NULL ? pModule->GetSimpleName() : pNativeImage->GetFileName())
+ };
+
+ methDeclareDependencyOnMvid.Call(args);
+
+ GCPROTECT_END();
+ }
+
manifestAssemblyCount++;
}
}
diff --git a/src/coreclr/vm/util.cpp b/src/coreclr/vm/util.cpp
index d03ecb7326073..a765183746e80 100644
--- a/src/coreclr/vm/util.cpp
+++ b/src/coreclr/vm/util.cpp
@@ -1795,16 +1795,12 @@ int GetRandomInt(int maxVal)
// These wrap the SString:L:CompareCaseInsensitive function in a way that makes it
// easy to fix code that uses _stricmp. _stricmp should be avoided as it uses the current
// C-runtime locale rather than the invariance culture.
-//
-// Note that unlike the real _stricmp, these functions unavoidably have a throws/gc_triggers/inject_fault
-// contract. So if need a case-insensitive comparison in a place where you can't tolerate this contract,
-// you've got a problem.
int __cdecl stricmpUTF8(const char* szStr1, const char* szStr2)
{
CONTRACTL
{
THROWS;
- GC_TRIGGERS;
+ GC_NOTRIGGER;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END
diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp
index 3c5d82f73848c..94b0dffd0b82e 100644
--- a/src/coreclr/vm/vars.hpp
+++ b/src/coreclr/vm/vars.hpp
@@ -105,6 +105,7 @@ class OBJECTREF {
class ReflectClassBaseObject* m_asReflectClass;
class ExecutionContextObject* m_asExecutionContext;
class AssemblyLoadContextBaseObject* m_asAssemblyLoadContextBase;
+ class BinderAssemblyObject* m_asBinderAssembly;
};
public:
diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
index c4504f140527a..44d1859fbd04d 100644
--- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx
@@ -4319,4 +4319,13 @@
Emitting debug info is not supported for this member.
+
+ Could not load file or assembly '{0}'. {1}
+
+
+ Assembly with same name is already loaded
+
+
+ Dynamically emitted assemblies are unsupported during host-based resolution.
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs
index 7fb7a66815956..562acc8a68611 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameHelpers.StrongName.cs
@@ -10,11 +10,16 @@ internal static partial class AssemblyNameHelpers
{
public static byte[]? ComputePublicKeyToken(byte[]? publicKey)
{
- if (publicKey == null)
+ if (publicKey is null)
return null;
+ return ComputePublicKeyToken(publicKey.AsSpan());
+ }
+
+ public static byte[] ComputePublicKeyToken(ReadOnlySpan publicKey)
+ {
if (publicKey.Length == 0)
- return Array.Empty();
+ return [];
if (!IsValidPublicKey(publicKey))
throw new SecurityException(SR.Security_InvalidAssemblyPublicKey);
@@ -35,16 +40,14 @@ internal static partial class AssemblyNameHelpers
//
// This validation logic is a port of StrongNameIsValidPublicKey() from src\coreclr\md\runtime\strongnameinternal.cpp
//
- private static bool IsValidPublicKey(byte[] publicKey)
+ private static bool IsValidPublicKey(ReadOnlySpan publicKeyBlob)
{
- uint publicKeyLength = (uint)(publicKey.Length);
+ uint publicKeyLength = (uint)(publicKeyBlob.Length);
// The buffer must be at least as large as the public key structure (for compat with desktop, we actually compare with the size of the header + 4).
if (publicKeyLength < SizeOfPublicKeyBlob + 4)
return false;
- // Poor man's reinterpret_cast into the PublicKeyBlob structure.
- ReadOnlySpan publicKeyBlob = new ReadOnlySpan(publicKey);
uint sigAlgID = BinaryPrimitives.ReadUInt32LittleEndian(publicKeyBlob);
uint hashAlgID = BinaryPrimitives.ReadUInt32LittleEndian(publicKeyBlob.Slice(4));
uint cbPublicKey = BinaryPrimitives.ReadUInt32LittleEndian(publicKeyBlob.Slice(8));
@@ -71,7 +74,7 @@ private static bool IsValidPublicKey(byte[] publicKey)
return false;
// The key blob must indicate that it is a PUBLICKEYBLOB
- if (publicKey[SizeOfPublicKeyBlob] != PUBLICKEYBLOB)
+ if (publicKeyBlob[SizeOfPublicKeyBlob] != PUBLICKEYBLOB)
return false;
return true;
@@ -94,7 +97,7 @@ private static uint GetAlgSid(uint x)
private const uint ALG_CLASS_SIGNATURE = (1 << 13);
private const uint PUBLICKEYBLOB = 0x6;
- private const uint SizeOfPublicKeyBlob = 12;
+ private const int SizeOfPublicKeyBlob = 12;
private const int PublicKeyTokenLength = 8;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs
index 498aa1e4d4a9c..fe070d14f3efd 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs
@@ -822,7 +822,7 @@ internal IntPtr GetResolvedUnmanagedDll(Assembly assembly, string unmanagedDllNa
}
}
- internal sealed class DefaultAssemblyLoadContext : AssemblyLoadContext
+ internal sealed partial class DefaultAssemblyLoadContext : AssemblyLoadContext
{
internal static readonly AssemblyLoadContext s_loadContext = new DefaultAssemblyLoadContext();