Skip to content

Reference assemblies reachable from current module only#25955

Merged
cston merged 13 commits intodotnet:dev15.7.xfrom
cston:refs-only
Apr 23, 2018
Merged

Reference assemblies reachable from current module only#25955
cston merged 13 commits intodotnet:dev15.7.xfrom
cston:refs-only

Conversation

@cston
Copy link
Copy Markdown
Contributor

@cston cston commented Apr 5, 2018

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.

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Apr 5, 2018

@tmat, @ivanbasov please review.
cc @jinujoseph

{
previous = null;
}
if (previous != null && previous.ModuleVersionId != moduleVersionId)
Copy link
Copy Markdown
Contributor Author

@cston cston Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Contributor Author

@cston cston Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return highest version of assembly if exact version is missing and there is a higher version available. #Resolved

@jcouv jcouv added this to the 15.7 milestone Apr 7, 2018
{
Debug.Assert(referencesBuilder.Count == 0);
// CommonReferenceManager<TCompilation, TAssemblySymbol>.Bind()
// expects COR library to be included in the explicit assemblies (see bug #...).
Copy link
Copy Markdown
Contributor

@ivanbasov ivanbasov Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#... [](start = 90, length = 4)

Would you like to specify the bug #? #Closed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed see bug #.

out int methodOrTypeToken,
out int localSignatureToken,
Guid moduleVersionIdOpt = default,
MakeAssemblyReferencesKind kind = MakeAssemblyReferencesKind.AllAssemblies) // TODO: Revert this change. No need for MakeAssemblyReferencesKind here.
Copy link
Copy Markdown
Contributor

@ivanbasov ivanbasov Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown
Contributor

@ivanbasov ivanbasov Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO [](start = 19, length = 4)

Should this test be added now? #Closed


private static void VerifyAppDomainMetadataContext(AppDomain appDomain)
{
// TODO: Verify set of AssemblyMetadataContext instances.
Copy link
Copy Markdown
Contributor

@ivanbasov ivanbasov Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO [](start = 15, length = 4)

? #Closed

Copy link
Copy Markdown
Contributor

@ivanbasov ivanbasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Apr 10, 2018

cc @jaredpar

internal static bool GetBoolRegistryValue(string name)
{
var value = RegistryHelpers.GetRegistryValue(name);
if ((value != null) && (value is int))
Copy link
Copy Markdown
Member

@jaredpar jaredpar Apr 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ((value != null) && (value is int)) [](start = 12, length = 38)

Isn't the null check redundant here? #Resolved

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Apr 13, 2018

@tmat, please review.
@ivanbasov, please take a second look since there are a number of changes (caching in particular) since your review, thanks.

@ivanbasov
Copy link
Copy Markdown
Contributor

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)
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dictionary [](start = 88, length = 10)

IReadOnlyDictionary #Resolved

{
ImmutableArray<(AssemblyIdentity, MetadataReference)> references;
(AssemblyIdentity, MetadataReference) result = default;
if (_referencesByIdentity.TryGetValue(referenceIdentity.Name, out references))
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out r [](start = 57, length = 5)

out var? #Resolved

throw ExceptionUtilities.Unreachable;
}

private (AssemblyIdentity, MetadataReference) GetBestMatch(ImmutableArray<(AssemblyIdentity, MetadataReference)> references, AssemblyIdentity referenceIdentity)
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(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();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExpressionCompiler.GetUseReferencedAssembliesOnlySetting(); [](start = 43, length = 59)

Shouldn't this rather flow from the ExpressionCompiler instance?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, ideally. Added a comment for now.


In reply to: 181508668 [](ancestors = 181508668)

// 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>
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s [](start = 12, length = 2)

readonly struct #Resolved

}
}

internal struct MetadataContext<TAssemblyContext>
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[](start = 12, length = 1)

readonly struct #Resolved

throw ExceptionUtilities.UnexpectedValue(kind);
}
}
}
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to a separate file #Resolved

AllAssemblies,
AllReferences,
DirectReferencesOnly,
}
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to separate file #Resolved


// 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logged #26157.


In reply to: 181510450 [](ancestors = 181510450)

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;
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

referencesByIdentity [](start = 12, length = 20)

better name: referencesBySimpleName #Resolved

var identity = reader.ReadAssemblyIdentityOrThrow();
if (referencesByIdentity != null)
{
string identityKey = identity.Name;
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd inline this variable #Resolved

Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out [](start = 75, length = 3)

out var #Resolved

{
var reader = metadata.MetadataReader;
var identity = reader.ReadAssemblyIdentityOrThrow();
if (referencesByIdentity != null)
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(referencesByIdentity != null [](start = 23, length = 29)

Isn't this always true? #Resolved

@tmat
Copy link
Copy Markdown
Member

tmat commented Apr 13, 2018

    private static PortableExecutableReference MakeAssemblyMetadata(ModuleMetadata metadata, Dictionary<string, ModuleMetadata> modulesByName)

Rename to MakeAssemblyReference? #Resolved


Refers to: src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs:315 in 54ecd0f. [](commit_id = 54ecd0f, deletion_comment = False)

{
referencesBuilder.Add(targetReference);
}
}
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Member

@tmat tmat Apr 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

referencesByIdentity [](start = 112, length = 20)

referencesBySimpleName #Resolved

@tmat
Copy link
Copy Markdown
Member

tmat commented Apr 13, 2018

LGTM. Just some minor feedback.

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Apr 14, 2018

@MattGertz for 15.7 approval.
cc @jinujoseph

@jinujoseph
Copy link
Copy Markdown
Contributor

approved to merge via link for 15.7.Preview5

@jinujoseph
Copy link
Copy Markdown
Contributor

vendor test approval pending @richaverma1

@cston
Copy link
Copy Markdown
Contributor Author

cston commented Apr 19, 2018

@dotnet-bot test windows_debug_vs-integration_prtest

@cston cston merged commit 7bebbc7 into dotnet:dev15.7.x Apr 23, 2018
@cston cston deleted the refs-only branch April 23, 2018 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants