-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a managed implementation of assembly binder #91400
Closed
Closed
Changes from all commits
Commits
Show all changes
143 commits
Select commit
Hold shift + click to select a range
dcecbdc
Definition of AssemblyVersion and AssemblyIdentity
huoyaoyuan c946228
Port logic body of AssemblyName.Init
huoyaoyuan b4c0ba8
Port HashCode and Equals for AssemblyName
huoyaoyuan a6bf121
AssemblyName.GetDisplayName
huoyaoyuan bf85741
Assembly
huoyaoyuan 61143ce
Some methods in AssemblyBinderCommon and BindReseult
huoyaoyuan 5fdf8a7
ApplicationContext
huoyaoyuan 7175e30
Basic assembly binder wrapper
huoyaoyuan 6cfdc44
Refactor FailureCache
huoyaoyuan 52dae46
BindLocked
huoyaoyuan e7789cd
FindInExecutionContext
huoyaoyuan c32ec98
BindByTpaList
huoyaoyuan 9a47f75
RegisterAndGetHostChosen
huoyaoyuan 21ea3e1
BindAssemblyByProbingPaths
huoyaoyuan 93b4b10
Use HResult instead of exception
huoyaoyuan a7de55a
GetAssembly
huoyaoyuan 9c77d7e
BindUsingPEImage
huoyaoyuan 116f7bf
Guard behind feature switch
huoyaoyuan 9fff7e2
Reuse IsPathFullyQualified
huoyaoyuan b092474
Reuse ComputePublicKeyToken
huoyaoyuan 6ceb626
Merge branch 'main' into managed-binder
huoyaoyuan b4dbcea
Revert "Guard behind feature switch"
huoyaoyuan 6d71c26
Satisfy sealed analyzer
huoyaoyuan a85d223
Tracing ResolutionAttemptedOperation
huoyaoyuan 18da994
Event source qcall
huoyaoyuan fb8f831
GetClrInstanceId
huoyaoyuan f71b175
KnownPathProbed event
huoyaoyuan 1390d93
Fix compilation
huoyaoyuan e13468a
MdImport for AssemblyName
huoyaoyuan 6196fbe
AssemblyNameData
huoyaoyuan c459c76
Basic AssemblyBinder
huoyaoyuan be6ec57
DefaultAssemblyBinder and BindUsingHostAssemblyResolver
huoyaoyuan 0c74a2a
Complete most of DefaltAssemblyBinder
huoyaoyuan d6cbc65
CustomAssemblyBinder
huoyaoyuan bfff7c2
Fix ALC compilation
huoyaoyuan 4e29ef7
Interop with LoaderAllocator
huoyaoyuan cd37220
Fix CollectionsMarshal usage
huoyaoyuan 167be6c
Name tracing for binder
huoyaoyuan a426eac
Store default binder in AppDomain
huoyaoyuan 6f4de1b
Store custom assembly binder in ALC
huoyaoyuan 20593a2
Fix compilation
huoyaoyuan e959600
Use managed binder in ALC
huoyaoyuan e073323
PEImage QCalls
huoyaoyuan 57039c7
Make BinderAcquireImport and BinderAcquirePEImage QCall.
huoyaoyuan 8eb96cf
Move QCalls to assemblynative and fix compilation
huoyaoyuan 163b51c
Store managed binder in PEAssembly
huoyaoyuan 6a693d0
Call GetLoaderAllocator
huoyaoyuan 6cf329f
Set DomainAssembly
huoyaoyuan 1449079
Use binder in native
huoyaoyuan 0a021ed
Use more in native
huoyaoyuan 1fecd66
Use more in native
huoyaoyuan c37ec2e
AssemblySpec
huoyaoyuan fc91661
BindToSystemSatellite
huoyaoyuan f3795d0
Compilation of casting
huoyaoyuan 8ea0e39
Remaining in appdomainnative and assemblynative
huoyaoyuan c0b851e
NativeImage and DeclareDependencyOnMvid
huoyaoyuan 25b6187
Make native part compiling
huoyaoyuan 7aa42e0
Merge branch 'main' into managed-binder
huoyaoyuan 85acdca
Fullfill PEAssembly QCalls
huoyaoyuan b157302
QCall for VMAssembly
huoyaoyuan 9073bc3
AssemblyNative_LoadFromPEImage
huoyaoyuan 38aee24
Refine corelib metasig
huoyaoyuan 2ac9719
CoreLib bootstrap
huoyaoyuan 77276c7
Managed binder initialization
huoyaoyuan ef2786e
Revert ALC.Load* to be native
huoyaoyuan 148df35
Revert QCalls for ALC.Load*
huoyaoyuan 791c478
Create assembly object for corelib
huoyaoyuan c323031
Fix some compilation and assert during corelib loading
huoyaoyuan 8f6fde9
Fix more asserts during loading
huoyaoyuan 754a81c
Fix calls to BindUsingPEImage
huoyaoyuan 6ee05b2
Assembly object layout
huoyaoyuan 9884e7b
Load application assembly
huoyaoyuan 2ae3cd1
AssemblyBinder layout
huoyaoyuan 4458280
Fix BinderAcquirePEImage usage
huoyaoyuan 9a2df4f
Enable AssemblySpecBindingCache
huoyaoyuan 38736bc
Merge branch 'main' into managed-binder
huoyaoyuan 20c1347
StartProfileOptimization
huoyaoyuan db8c08c
AppBundle support
huoyaoyuan ef3f57b
Implement BindSatelliteResource
huoyaoyuan d6972b5
Delete unused QCalls
huoyaoyuan 244aedd
Make ProbeAppBundle compatible to extern "C"
huoyaoyuan f954fea
Register managed binder to native LoaderAllocator
huoyaoyuan e8efdea
Fix IsNeutralCulture
huoyaoyuan 62995fb
Restore AssemblyBinder usage in AppDomain
huoyaoyuan 26c8224
Restore native binder lifetime
huoyaoyuan 5e412b8
Restore AssemblyBinder usage in AssemblySpec
huoyaoyuan 1bdcf2f
Restore AssemblyBinder usage in PEAssembly
huoyaoyuan 7c233c6
Restore some more binder usage
huoyaoyuan e5dbd2e
Delete unused HashIdentity
huoyaoyuan 2d7acad
Typo
huoyaoyuan f5376c1
Update CoreLib bootstrap to use PEImage
huoyaoyuan f0ebbcf
Restore native binder in native ALC object
huoyaoyuan 68a6918
Get managed ALC object from native binder
huoyaoyuan 2c981b9
Restore usages in AssemblyNative
huoyaoyuan 219e9e6
Restore lifetime management with LoaderAllocator
huoyaoyuan 37702da
Fix some compilation
huoyaoyuan 4f20259
Fix more usage
huoyaoyuan b832f39
Give up exposing ALC ref in AssemblyBinder
huoyaoyuan 51decaa
Fold managed AssemblyBinder into ALC
huoyaoyuan 82ec2ac
Resolve the gap between managed and native ALC
huoyaoyuan 680b6bc
Move LoaderAllocator usage to native side
huoyaoyuan 0686653
Move BindUsingHostAssemblyResolver to ALC
huoyaoyuan 5567e6b
Move to S.R.Loader folder
huoyaoyuan a73f546
Move namespace and rename. Allows usage of System.Reflection.
huoyaoyuan 82fe458
Remove unused QCall and accessibility change, arrange QCall
huoyaoyuan ce4204c
Update the structure of BindUsingHostAssemblyResolver
huoyaoyuan 2dc24bd
Cleanup unused binder implementation
huoyaoyuan 7108a48
Redo CoreLib bootstrap changes
huoyaoyuan 3f7c634
Remove BinderAssemblyObject and reorder vm to corelib call to ALC
huoyaoyuan d37aabf
Merge branch 'main'
huoyaoyuan 6836892
Uncomment remaining native binder related code
huoyaoyuan 55975ce
Cleanup AppContext
huoyaoyuan e75e644
Delete BindResult and FailureCache
huoyaoyuan 5cf324e
Delete BINDER_SPACE::Assembly
huoyaoyuan 485ed02
Cleanup remaining tracing and assembly code
huoyaoyuan dc3f5fc
Fill managed tracer
huoyaoyuan fd58a10
Cleanup indent changes
huoyaoyuan 87a89e4
Fix
huoyaoyuan 258b857
Align tracing with existing ALC tracing
huoyaoyuan e83e472
Fix GC mode for an assert
huoyaoyuan ce07241
Cleanup
huoyaoyuan 354c359
SourceGen can't generate for ref struct
huoyaoyuan e5487b3
Remove usage of record struct
huoyaoyuan e35aa05
Load lock cleanup
huoyaoyuan 5af68d7
Cleanup exception
huoyaoyuan 1f53d77
Fix callsite compiling
huoyaoyuan 65b2198
Fix GC mode in CreateDynamic
huoyaoyuan 8098ff4
Move CoreLib binder setup after g_fEEStarted
huoyaoyuan 5363aec
Fix AssemblyName equality
huoyaoyuan f50c271
Fix binder tracing
huoyaoyuan 55e2b6c
Simplify AttemptResult tracing
huoyaoyuan f74c57d
Update Crst level
huoyaoyuan ab91f17
Fix
huoyaoyuan 5b1b5e1
Unloadability
huoyaoyuan 106333a
Fix BindSatelliteResourceByProbingPaths
huoyaoyuan cc74f32
Merge branch 'main' into managed-binder
jkotas 77ff24e
Merge branch 'main'
huoyaoyuan 146c0f7
Use separated helper to handle nullable array
huoyaoyuan 8afeb7d
Don't use InvariantCulture
huoyaoyuan 8ee2a01
Merge branch 'main'
huoyaoyuan dfeaf1b
Update MDImport to latest pattern
huoyaoyuan 22a25ba
Use class to reduce a generic instantiation
huoyaoyuan dbb3a20
Remove more generic instantiation on Dictionary
huoyaoyuan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
301 changes: 301 additions & 0 deletions
301
src/coreclr/System.Private.CoreLib/src/System/Runtime/Loader/ApplicationContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<FailureCacheKey> | ||
{ | ||
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<BinderAssemblyName, BinderAssembly> ExecutionContext { get; } = new Dictionary<BinderAssemblyName, BinderAssembly>(); | ||
|
||
public Dictionary<FailureCacheKey, int> FailureCache { get; } = new Dictionary<FailureCacheKey, int>(); | ||
|
||
public object ContextCriticalSection { get; } = new object(); | ||
|
||
public List<string> PlatformResourceRoots { get; } = new List<string>(); | ||
|
||
public List<string> AppPaths { get; } = new List<string>(); | ||
|
||
public Dictionary<string, TPAEntry>? 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<char> 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<string, TPAEntry>(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(); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
ni.dll
still a thing? I remember it's output of NGen.Even if it's still a thing, we should probably remove this too because the shared framework (TPA) does not contain any ni files.
The performance difference is negligible though.