Reference assemblies reachable from current module only#25955
Reference assemblies reachable from current module only#25955cston merged 13 commits intodotnet:dev15.7.xfrom
Conversation
|
@tmat, @ivanbasov please review. |
| { | ||
| previous = null; | ||
| } | ||
| if (previous != null && previous.ModuleVersionId != moduleVersionId) |
There was a problem hiding this comment.
If the fix is disabled (if kind == AllAssemblies), we should not be setting or checking previous.ModuleVersionId. #Resolved
| #endif | ||
| MetadataReference reference; | ||
| _referencesByIdentity.TryGetValue(referenceIdentity, out reference); | ||
| return (PortableExecutableReference)reference; |
There was a problem hiding this comment.
Should return highest version of assembly if exact version is missing and there is a higher version available. #Resolved
| { | ||
| Debug.Assert(referencesBuilder.Count == 0); | ||
| // CommonReferenceManager<TCompilation, TAssemblySymbol>.Bind() | ||
| // expects COR library to be included in the explicit assemblies (see bug #...). |
There was a problem hiding this comment.
#... [](start = 90, length = 4)
Would you like to specify the bug #? #Closed
| out int methodOrTypeToken, | ||
| out int localSignatureToken, | ||
| Guid moduleVersionIdOpt = default, | ||
| MakeAssemblyReferencesKind kind = MakeAssemblyReferencesKind.AllAssemblies) // TODO: Revert this change. No need for MakeAssemblyReferencesKind here. |
There was a problem hiding this comment.
TODO: Revert this change. [](start = 91, length = 25)
Is it for now or a bug should be created for this TODO? #Closed
| }"); | ||
| VerifyResolutionRequests(context, (identityA1, identityA1, 1)); | ||
|
|
||
| // TODO: Test { A1.M, B1.M, C.M } with all assemblies. |
There was a problem hiding this comment.
TODO [](start = 19, length = 4)
Should this test be added now? #Closed
|
|
||
| private static void VerifyAppDomainMetadataContext(AppDomain appDomain) | ||
| { | ||
| // TODO: Verify set of AssemblyMetadataContext instances. |
There was a problem hiding this comment.
TODO [](start = 15, length = 4)
? #Closed
|
cc @jaredpar |
| internal static bool GetBoolRegistryValue(string name) | ||
| { | ||
| var value = RegistryHelpers.GetRegistryValue(name); | ||
| if ((value != null) && (value is int)) |
There was a problem hiding this comment.
if ((value != null) && (value is int)) [](start = 12, length = 38)
Isn't the null check redundant here? #Resolved
|
@tmat, please review. |
|
reviewed once again. LGTM. Thanks! |
| internal readonly Dictionary<AssemblyIdentity, (AssemblyIdentity Identity, int Count)> Requests = new Dictionary<AssemblyIdentity, (AssemblyIdentity Identity, int Count)>(); | ||
| #endif | ||
|
|
||
| internal EEMetadataReferenceResolver(AssemblyIdentityComparer identityComparer, Dictionary<string, ImmutableArray<(AssemblyIdentity, MetadataReference)>> referencesByIdentity) |
There was a problem hiding this comment.
Dictionary [](start = 88, length = 10)
IReadOnlyDictionary #Resolved
| { | ||
| ImmutableArray<(AssemblyIdentity, MetadataReference)> references; | ||
| (AssemblyIdentity, MetadataReference) result = default; | ||
| if (_referencesByIdentity.TryGetValue(referenceIdentity.Name, out references)) |
There was a problem hiding this comment.
references [](start = 78, length = 10)
nit: out var references #Resolved
| public override PortableExecutableReference ResolveMissingAssembly(MetadataReference definition, AssemblyIdentity referenceIdentity) | ||
| { | ||
| ImmutableArray<(AssemblyIdentity, MetadataReference)> references; | ||
| (AssemblyIdentity, MetadataReference) result = default; |
There was a problem hiding this comment.
AssemblyIdentity, MetadataReference [](start = 13, length = 35)
Perhaps we could name these so that we don't need to wonder what Item1 and Item2 are below #Resolved
| } | ||
| #if DEBUG | ||
| (AssemblyIdentity Identity, int Count) request; | ||
| if (!Requests.TryGetValue(referenceIdentity, out request)) |
There was a problem hiding this comment.
out r [](start = 57, length = 5)
out var? #Resolved
| throw ExceptionUtilities.Unreachable; | ||
| } | ||
|
|
||
| private (AssemblyIdentity, MetadataReference) GetBestMatch(ImmutableArray<(AssemblyIdentity, MetadataReference)> references, AssemblyIdentity referenceIdentity) |
There was a problem hiding this comment.
(AssemblyIdentity, MetadataReference) [](start = 82, length = 37)
Perhaps we could name these so that we don't need to wonder what Item1 and Item2 are below #Resolved
|
|
||
| internal InstructionDecoder() | ||
| { | ||
| _useReferencedAssembliesOnly = ExpressionCompiler.GetUseReferencedAssembliesOnlySetting(); |
There was a problem hiding this comment.
ExpressionCompiler.GetUseReferencedAssembliesOnlySetting(); [](start = 43, length = 59)
Shouldn't this rather flow from the ExpressionCompiler instance?
There was a problem hiding this comment.
| // Wrapper around Guid to ensure callers have asked for the correct id | ||
| // rather than simply using the ModuleVersionId (which is unnecessary | ||
| // when the Compilation references all loaded assemblies). | ||
| internal struct MetadataContextId : IEquatable<MetadataContextId> |
There was a problem hiding this comment.
s [](start = 12, length = 2)
readonly struct #Resolved
| } | ||
| } | ||
|
|
||
| internal struct MetadataContext<TAssemblyContext> |
There was a problem hiding this comment.
[](start = 12, length = 1)
readonly struct #Resolved
| throw ExceptionUtilities.UnexpectedValue(kind); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Move to a separate file #Resolved
| AllAssemblies, | ||
| AllReferences, | ||
| DirectReferencesOnly, | ||
| } |
|
|
||
| // We don't walk the references of winmd assemblies currently. (That would require | ||
| // walking references from the current module and also the winmd assemblies.) | ||
| // So if there are any winmd assemblies, we'll use all assemblies. |
There was a problem hiding this comment.
So if there are any winmd assemblies, we'll use all assemblies. [](start = 15, length = 63)
Should we have an issue for this? We might want to address this in 15.8
| var referencesBuilder = ArrayBuilder<MetadataReference>.GetInstance(); | ||
| var identitiesBuilder = (identityComparer == null) ? null : ArrayBuilder<AssemblyIdentity>.GetInstance(); | ||
| var identitiesBuilder = (kind == MakeAssemblyReferencesKind.DirectReferencesOnly) ? ArrayBuilder<AssemblyIdentity>.GetInstance() : null; | ||
| referencesByIdentity = (kind == MakeAssemblyReferencesKind.AllReferences) ? new Dictionary<string, ImmutableArray<(AssemblyIdentity, MetadataReference)>>(StringComparer.OrdinalIgnoreCase) : null; |
There was a problem hiding this comment.
referencesByIdentity [](start = 12, length = 20)
better name: referencesBySimpleName #Resolved
| var identity = reader.ReadAssemblyIdentityOrThrow(); | ||
| if (referencesByIdentity != null) | ||
| { | ||
| string identityKey = identity.Name; |
There was a problem hiding this comment.
I'd inline this variable #Resolved
There was a problem hiding this comment.
I think this would read better: referencesBySimpleName.TryGetValue(identity.Name, out references) #Resolved
| { | ||
| string identityKey = identity.Name; | ||
| ImmutableArray<(AssemblyIdentity, MetadataReference)> references; | ||
| if (!referencesByIdentity.TryGetValue(identityKey, out references)) |
There was a problem hiding this comment.
out [](start = 75, length = 3)
out var #Resolved
| { | ||
| var reader = metadata.MetadataReader; | ||
| var identity = reader.ReadAssemblyIdentityOrThrow(); | ||
| if (referencesByIdentity != null) |
There was a problem hiding this comment.
(referencesByIdentity != null [](start = 23, length = 29)
Isn't this always true? #Resolved
Rename to Refers to: src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs:315 in 54ecd0f. [](commit_id = 54ecd0f, deletion_comment = False) |
| { | ||
| referencesBuilder.Add(targetReference); | ||
| } | ||
| } |
There was a problem hiding this comment.
There seems to be 2 code paths here that are interwoven but almost entirely distinct. Kind == AllReferences and otherwise. Consider refactoring to two different methods or blocks. #Resolved
| internal static CSharpCompilation ToCompilation(this ImmutableArray<MetadataBlock> metadataBlocks, Guid moduleVersionId, MakeAssemblyReferencesKind kind) | ||
| { | ||
| Dictionary<string, ImmutableArray<(AssemblyIdentity, MetadataReference)>> referencesByIdentity; | ||
| var references = metadataBlocks.MakeAssemblyReferences(moduleVersionId, IdentityComparer, kind, out referencesByIdentity); |
There was a problem hiding this comment.
out [](start = 108, length = 4)
out var to avoid declaring the var with the very long type name #Resolved
| internal static CSharpCompilation ToCompilation(this ImmutableArray<MetadataBlock> metadataBlocks, Guid moduleVersionId, MakeAssemblyReferencesKind kind) | ||
| { | ||
| Dictionary<string, ImmutableArray<(AssemblyIdentity, MetadataReference)>> referencesByIdentity; | ||
| var references = metadataBlocks.MakeAssemblyReferences(moduleVersionId, IdentityComparer, kind, out referencesByIdentity); |
There was a problem hiding this comment.
referencesByIdentity [](start = 112, length = 20)
referencesBySimpleName #Resolved
|
LGTM. Just some minor feedback. |
|
@MattGertz for 15.7 approval. |
|
approved to merge via link for 15.7.Preview5 |
|
vendor test approval pending @richaverma1 |
|
@dotnet-bot test windows_debug_vs-integration_prtest |
Customer scenario
Evaluating expressions in the Locals, Watch, or Callstack windows is slow when the process contains a large number of modules and not all modules are referenced by the current module.
Bugs this fixes
591114
Workarounds, if any
None
Risk
Medium risk. The user must opt-in to the fix via a registry setting, but there are some changes required to maintain the existing behavior alongside the fix.
Performance impact
No performance impact unless opted-in.
Is this a regression from a previous update?
No.
How was the bug found?
Customer reported.