提交 9f2c1635 编写于 作者: T TomasMatousek

We stored a CorLib assembly symbol (one that doesn't have any references and...

We stored a CorLib assembly symbol (one that doesn't have any references and defines System.Object) on ReferenceManager. The instance of the manager is shared across compilations derived via Clone() or WithXxx() unless the metadata reference binding changes.
     If the compilation itself was CorLib we shared its source assembly symbol as a CorLib assembly with the derived compilations, which broke symbol equality.

     This change replaces an explicit CorLib reference in the ReferenceManager with null if the CorLib is the compilation being compiled. We have the assembly CorLib symbol in hand when reading the state so we can fill the right symbol in.
     Also refactors VB code in ReferenceManager to exactly match C# implementation.

     Resolves #43. (changeset 1227802)
上级 ba2cf89c
......@@ -4,15 +4,11 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.Instrumentation;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
......@@ -232,6 +228,9 @@ public PEAssemblySymbol CreatePEAssemblyForAssemblyMetadata(AssemblyMetadata met
{
AssertBound();
// If the compilation has a reference from metadata to source assembly we can't share the referenced PE symbols.
Debug.Assert(!HasCircularReference);
var referencedAssembliesByIdentity = new Dictionary<AssemblyIdentity, AssemblySymbol>();
foreach (var symbol in this.ReferencedAssemblies)
{
......@@ -267,14 +266,13 @@ private void CreateAndSetSourceAssemblyReuseData(CSharpCompilation compilation)
{
AssertBound();
// If the compilation has a reference from metadata to source assembly
// we can't share the referenced PE symbols.
// If the compilation has a reference from metadata to source assembly we can't share the referenced PE symbols.
Debug.Assert(!HasCircularReference);
string moduleName = compilation.MakeSourceModuleName();
var assemblySymbol = new SourceAssemblySymbol(compilation, this.SimpleAssemblyName, moduleName, this.ReferencedModules);
InitializeAssemblyReuseData(assemblySymbol);
InitializeAssemblyReuseData(assemblySymbol, this.ReferencedAssemblies, this.UnifiedAssemblies);
if ((object)compilation.lazyAssemblySymbol == null)
{
......@@ -289,16 +287,11 @@ private void CreateAndSetSourceAssemblyReuseData(CSharpCompilation compilation)
}
}
private void InitializeAssemblyReuseData(AssemblySymbol assemblySymbol)
{
InitializeAssemblyReuseData(assemblySymbol, this.ReferencedAssemblies, this.UnifiedAssemblies);
}
private void InitializeAssemblyReuseData(AssemblySymbol assemblySymbol, ImmutableArray<AssemblySymbol> referencedAssemblies, ImmutableArray<UnifiedAssembly<AssemblySymbol>> unifiedAssemblies)
{
AssertBound();
assemblySymbol.SetCorLibrary(this.CorLibrary);
assemblySymbol.SetCorLibrary(this.CorLibraryOpt ?? assemblySymbol);
var sourceModuleReferences = new ModuleReferences<AssemblySymbol>(referencedAssemblies.SelectAsArray(a => a.Identity), referencedAssemblies, unifiedAssemblies);
assemblySymbol.Modules[0].SetReferences(sourceModuleReferences);
......@@ -329,9 +322,10 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
ImmutableArray<PEModule> modules; // To make sure the modules are not collected ahead of time.
ImmutableArray<MetadataReference> references;
DiagnosticBag diagnostics = DiagnosticBag.GetInstance();
bool exception = true;
var resolutionDiagnostics = default(ImmutableArray<Diagnostic>);
var referenceMap = default(ImmutableArray<ResolvedReference>);
var diagnostics = DiagnosticBag.GetInstance();
try
{
referenceMap = ResolveMetadataReferences(
......@@ -342,19 +336,14 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
out referencedAssemblies,
out modules,
diagnostics);
exception = false;
resolutionDiagnostics = diagnostics.ToReadOnly();
}
finally
{
if (exception)
{
// Prevent a leak report in the unit test output.
diagnostics.Free();
}
diagnostics.Free();
}
ImmutableArray<Diagnostic> resolutionDiagnostics = diagnostics.ToReadOnlyAndFree();
var assemblyBeingBuiltData = new AssemblyDataForAssemblyBeingBuilt(new AssemblyIdentity(name: SimpleAssemblyName), referencedAssemblies, modules);
var assembliesArray = new AssemblyData[referencedAssemblies.Length + 1];
......@@ -490,7 +479,7 @@ private bool CreateAndSetSourceAssemblyFullBind(CSharpCompilation compilation)
boundReferenceDirectives,
hasCircularReference,
resolutionDiagnostics,
corLibrary,
ReferenceEquals(corLibrary, assemblySymbol) ? null : corLibrary,
modules,
moduleReferences,
referencedAssemblySymbols,
......
......@@ -2175,5 +2175,19 @@ public void ReferenceWithNoMetadataSection()
// error CS0009: Metadata file 'NativeApp.exe' could not be opened -- PE image doesn't contain managed metadata.
Diagnostic(ErrorCode.FTL_MetadataCantOpenFile).WithArguments(@"NativeApp.exe", "PE image doesn't contain managed metadata."));
}
[Fact, WorkItem(43)]
public void ReusingCorLibManager()
{
var corlib1 = CreateCompilation("");
var assembly1 = corlib1.Assembly;
var corlib2 = corlib1.Clone();
var assembly2 = corlib2.Assembly;
Assert.Same(assembly1.CorLibrary, assembly1);
Assert.Same(assembly2.CorLibrary, assembly2);
Assert.True(corlib1.ReferenceManagerEquals(corlib2));
}
}
}
......@@ -141,9 +141,14 @@ public bool DeclarationsAccessibleWithoutAlias()
private ImmutableArray<Diagnostic> lazyDiagnostics;
/// <summary>
/// COR library symbol.
/// COR library symbol, or null if the compilation itself is the COR library.
/// </summary>
private TAssemblySymbol lazyCorLibrary;
/// <remarks>
/// If the compilation being built is the COR library we don't want to store its source assembly symbol
/// here since we wouldn't be able to share the state among subsequent compilations that are derived from it
/// (each of them has its own source assembly symbol).
/// </remarks>
private TAssemblySymbol lazyCorLibraryOpt;
/// <summary>
/// Standalone modules referenced by the compilation (doesn't include the manifest module of the compilation).
......@@ -237,12 +242,12 @@ internal ImmutableArray<MetadataReference> DirectiveReferences
#region Symbols necessary to set up source assembly and module
internal TAssemblySymbol CorLibrary
internal TAssemblySymbol CorLibraryOpt
{
get
{
AssertBound();
return lazyCorLibrary;
return lazyCorLibraryOpt;
}
}
......@@ -296,11 +301,11 @@ internal void AssertUnbound()
Debug.Assert(lazyReferencedModuleIndexMap == null);
Debug.Assert(lazyReferenceDirectiveMap == null);
Debug.Assert(lazyDirectiveReferences.IsDefault);
Debug.Assert(lazyCorLibrary == null);
Debug.Assert(lazyReferencedModules.IsDefault);
Debug.Assert(lazyReferencedModulesReferences.IsDefault);
Debug.Assert(lazyReferencedAssemblies.IsDefault);
Debug.Assert(lazyUnifiedAssemblies.IsDefault);
Debug.Assert(lazyCorLibraryOpt == null);
}
[Conditional("DEBUG")]
......@@ -312,11 +317,13 @@ internal void AssertBound()
Debug.Assert(lazyReferencedModuleIndexMap != null);
Debug.Assert(lazyReferenceDirectiveMap != null);
Debug.Assert(!lazyDirectiveReferences.IsDefault);
Debug.Assert(lazyCorLibrary != null);
Debug.Assert(!lazyReferencedModules.IsDefault);
Debug.Assert(!lazyReferencedModulesReferences.IsDefault);
Debug.Assert(!lazyReferencedAssemblies.IsDefault);
Debug.Assert(!lazyUnifiedAssemblies.IsDefault);
// lazyCorLibrary is null if the compilation is corlib
Debug.Assert(lazyReferencedAssemblies.Length == 0 || lazyCorLibraryOpt != null);
}
[Conditional("DEBUG")]
......@@ -343,7 +350,7 @@ internal bool IsBound
ImmutableArray<MetadataReference> boundReferenceDirectives,
bool containsCircularReferences,
ImmutableArray<Diagnostic> diagnostics,
TAssemblySymbol corLibrary,
TAssemblySymbol corLibraryOpt,
ImmutableArray<PEModule> referencedModules,
ImmutableArray<ModuleReferences<TAssemblySymbol>> referencedModulesReferences,
ImmutableArray<TAssemblySymbol> referencedAssemblies,
......@@ -360,7 +367,7 @@ internal bool IsBound
this.lazyReferenceDirectiveMap = boundReferenceDirectiveMap;
this.lazyDirectiveReferences = boundReferenceDirectives;
this.lazyCorLibrary = corLibrary;
this.lazyCorLibraryOpt = corLibraryOpt;
this.lazyReferencedModules = referencedModules;
this.lazyReferencedModulesReferences = referencedModulesReferences;
this.lazyReferencedAssemblies = referencedAssemblies;
......
......@@ -2,6 +2,7 @@
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis.Instrumentation
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
Imports MetadataOrDiagnostic = System.Object
......@@ -61,53 +62,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return refs.ToArray()
End Function
Friend Function CreatePEAssemblyForAssemblyMetadata(metadata As AssemblyMetadata, importOptions As MetadataImportOptions) As PEAssemblySymbol
AssertBound()
Dim referencedAssembliesByIdentity = New Dictionary(Of AssemblyIdentity, AssemblySymbol)()
For Each symbol In Me.ReferencedAssemblies
referencedAssembliesByIdentity.Add(symbol.Identity, symbol)
Next
Dim assembly = metadata.Assembly
Dim peReferences = assembly.AssemblyReferences.SelectAsArray(AddressOf MapAssemblyIdentityToResolvedSymbol, referencedAssembliesByIdentity)
Dim assemblySymbol = New PEAssemblySymbol(assembly, DocumentationProvider.Default, isLinked:=False, importOptions:=importOptions)
Dim unifiedAssemblies = Me.UnifiedAssemblies.WhereAsArray(Function(unified) referencedAssembliesByIdentity.ContainsKey(unified.OriginalReference))
InitializeAssemblyReuseData(assemblySymbol, peReferences, unifiedAssemblies)
If assembly.ContainsNoPiaLocalTypes() Then
assemblySymbol.SetNoPiaResolutionAssemblies(Me.ReferencedAssemblies)
End If
Return assemblySymbol
End Function
Private Shared Function MapAssemblyIdentityToResolvedSymbol(identity As AssemblyIdentity, map As Dictionary(Of AssemblyIdentity, AssemblySymbol)) As AssemblySymbol
Dim symbol As AssemblySymbol = Nothing
If map.TryGetValue(identity, symbol) Then
Return symbol
End If
Return New MissingAssemblySymbol(identity)
End Function
Private Sub InitializeAssemblyReuseData(assemblySymbol As AssemblySymbol, referencedAssemblies As ImmutableArray(Of AssemblySymbol), unifiedAssemblies As ImmutableArray(Of UnifiedAssembly(Of AssemblySymbol)))
AssertBound()
assemblySymbol.SetCorLibrary(Me.CorLibrary)
Dim sourceModuleReferences = New ModuleReferences(Of AssemblySymbol)(referencedAssemblies.SelectAsArray(Function(a) a.Identity), referencedAssemblies, unifiedAssemblies)
assemblySymbol.Modules(0).SetReferences(sourceModuleReferences)
Dim assemblyModules = assemblySymbol.Modules
Dim ReferencedModulesReferences = Me.ReferencedModulesReferences
Debug.Assert(assemblyModules.Length = ReferencedModulesReferences.Length + 1)
For i = 1 To assemblyModules.Length - 1
assemblyModules(i).SetReferences(ReferencedModulesReferences(i - 1))
Next
End Sub
Protected Overrides Function GetNoPiaResolutionAssemblies(candidateAssembly As AssemblySymbol) As ImmutableArray(Of AssemblySymbol)
If TypeOf candidateAssembly Is SourceAssemblySymbol Then
' This is an optimization, if candidateAssembly links something or explicitly declares local type,
......@@ -198,7 +152,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' already bound its references and produced tables that we can use to construct
' source assembly symbol faster.
CreateSourceAssemblyReuseData(compilation)
CreateAndSetSourceAssemblyReuseData(compilation)
Else
' We encountered a circular reference while binding the previous compilation.
' This compilation can't share bound references with other compilations. Create a new manager.
......@@ -220,34 +174,59 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Using
End Sub
Private Sub CreateSourceAssemblyReuseData(compilation As VisualBasicCompilation)
''' <summary>
''' Creates a <see cref="PEAssemblySymbol"/> from specified metadata.
''' </summary>
''' <remarks>
''' Used by EnC to create symbols for emit baseline. The PE symbols are used by <see cref="SymbolMatcher"/>.
'''
''' The assembly references listed in the metadata AssemblyRef table are matched to the resolved references
''' stored on this <see cref="ReferenceManager"/>. Each AssemblyRef is matched against the assembly identities
''' using an exact equality comparison. No unification Or further resolution is performed.
''' </remarks>
Friend Function CreatePEAssemblyForAssemblyMetadata(metadata As AssemblyMetadata, importOptions As MetadataImportOptions) As PEAssemblySymbol
AssertBound()
' If the compilation has a reference from metadata to source assembly
' we can't share the referenced PE symbols.
' If the compilation has a reference from metadata to source assembly we can't share the referenced PE symbols.
Debug.Assert(Not HasCircularReference)
Dim moduleName As String = compilation.MakeSourceModuleName()
Dim assemblySymbol = New SourceAssemblySymbol(compilation, Me.SimpleAssemblyName, moduleName, Me.ReferencedModules)
Dim referencedAssembliesByIdentity = New Dictionary(Of AssemblyIdentity, AssemblySymbol)()
For Each symbol In Me.ReferencedAssemblies
referencedAssembliesByIdentity.Add(symbol.Identity, symbol)
Next
assemblySymbol.SetCorLibrary(Me.CorLibrary)
Dim assembly = metadata.Assembly
Dim peReferences = assembly.AssemblyReferences.SelectAsArray(AddressOf MapAssemblyIdentityToResolvedSymbol, referencedAssembliesByIdentity)
Dim assemblySymbol = New PEAssemblySymbol(assembly, DocumentationProvider.Default, isLinked:=False, importOptions:=importOptions)
Dim referencedAssemblies = Me.ReferencedAssemblies
Dim identities = New AssemblyIdentity(referencedAssemblies.Length - 1) {}
For i = 0 To identities.Length - 1
identities(i) = referencedAssemblies(i).Identity
Next
Dim unifiedAssemblies = Me.UnifiedAssemblies.WhereAsArray(Function(unified) referencedAssembliesByIdentity.ContainsKey(unified.OriginalReference))
InitializeAssemblyReuseData(assemblySymbol, peReferences, unifiedAssemblies)
Dim sourceModuleReferences As New ModuleReferences(Of AssemblySymbol)(identities.AsImmutableOrNull(), referencedAssemblies, Me.UnifiedAssemblies)
assemblySymbol.SourceModule.SetReferences(sourceModuleReferences)
If assembly.ContainsNoPiaLocalTypes() Then
assemblySymbol.SetNoPiaResolutionAssemblies(Me.ReferencedAssemblies)
End If
Dim assemblyModules = assemblySymbol.Modules
Dim referencedModulesReferences = Me.ReferencedModulesReferences
Debug.Assert(assemblyModules.Length = referencedModulesReferences.Length + 1)
Return assemblySymbol
End Function
For i = 1 To assemblyModules.Length - 1
assemblyModules(i).SetReferences(referencedModulesReferences(i - 1))
Next
Private Shared Function MapAssemblyIdentityToResolvedSymbol(identity As AssemblyIdentity, map As Dictionary(Of AssemblyIdentity, AssemblySymbol)) As AssemblySymbol
Dim symbol As AssemblySymbol = Nothing
If map.TryGetValue(identity, symbol) Then
Return symbol
End If
Return New MissingAssemblySymbol(identity)
End Function
Private Sub CreateAndSetSourceAssemblyReuseData(compilation As VisualBasicCompilation)
AssertBound()
' If the compilation has a reference from metadata to source assembly we can't share the referenced PE symbols.
Debug.Assert(Not HasCircularReference)
Dim moduleName As String = compilation.MakeSourceModuleName()
Dim assemblySymbol = New SourceAssemblySymbol(compilation, Me.SimpleAssemblyName, moduleName, Me.ReferencedModules)
InitializeAssemblyReuseData(assemblySymbol, Me.ReferencedAssemblies, Me.UnifiedAssemblies)
If compilation.m_lazyAssemblySymbol Is Nothing Then
SyncLock SymbolCacheAndReferenceManagerStateGuard
......@@ -259,6 +238,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
End Sub
Private Sub InitializeAssemblyReuseData(assemblySymbol As AssemblySymbol, referencedAssemblies As ImmutableArray(Of AssemblySymbol), unifiedAssemblies As ImmutableArray(Of UnifiedAssembly(Of AssemblySymbol)))
AssertBound()
assemblySymbol.SetCorLibrary(If(Me.CorLibraryOpt, assemblySymbol))
Dim sourceModuleReferences = New ModuleReferences(Of AssemblySymbol)(referencedAssemblies.SelectAsArray(Function(a) a.Identity), referencedAssemblies, unifiedAssemblies)
assemblySymbol.Modules(0).SetReferences(sourceModuleReferences)
Dim assemblyModules = assemblySymbol.Modules
Dim referencedModulesReferences = Me.ReferencedModulesReferences
Debug.Assert(assemblyModules.Length = referencedModulesReferences.Length + 1)
For i = 1 To assemblyModules.Length - 1
assemblyModules(i).SetReferences(referencedModulesReferences(i - 1))
Next
End Sub
' Returns false if another compilation sharing this manager finished binding earlier and we should reuse its results.
Friend Function CreateSourceAssemblyFullBind(compilation As VisualBasicCompilation) As Boolean
Dim assemblySymbol As SourceAssemblySymbol
......@@ -273,17 +270,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim modules As ImmutableArray(Of PEModule) = Nothing ' To make sure the modules are not collected ahead of time.
Dim references As ImmutableArray(Of MetadataReference) = Nothing
Dim resolutionDiagnostics As ImmutableArray(Of Diagnostic) = Nothing
Dim referenceMap As ImmutableArray(Of ResolvedReference) = Nothing
Dim diagnostics = DiagnosticBag.GetInstance()
Dim referenceMap As ImmutableArray(Of ResolvedReference) = ResolveMetadataReferences(
compilation,
references,
boundReferenceDirectiveMap,
boundReferenceDirectives,
referencedAssemblies,
modules,
diagnostics)
Dim resolutionDiagnostics = diagnostics.ToReadOnlyAndFree()
Try
referenceMap = ResolveMetadataReferences(
compilation,
references,
boundReferenceDirectiveMap,
boundReferenceDirectives,
referencedAssemblies,
modules,
diagnostics)
resolutionDiagnostics = diagnostics.ToReadOnly()
Finally
diagnostics.Free()
End Try
Dim assemblyBeingBuiltData As New AssemblyDataForAssemblyBeingBuilt(New AssemblyIdentity(name:=SimpleAssemblyName), referencedAssemblies, modules)
......@@ -403,7 +407,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
boundReferenceDirectives,
hasCircularReference,
resolutionDiagnostics,
corLibrary,
If(corLibrary Is assemblySymbol, Nothing, corLibrary),
modules,
moduleReferences,
referencedAssemblySymbols,
......
......@@ -1641,5 +1641,18 @@ End Class
c.VerifyDiagnostics(
Diagnostic(ERRID.ERR_BadMetaDataReference1).WithArguments("NativeApp.exe", "PE image doesn't contain managed metadata."))
End Sub
<Fact, WorkItem(43)>
Public Sub ReusingCorLibManager()
Dim corlib1 = VisualBasicCompilation.Create("Comp")
Dim assembly1 = corlib1.Assembly
Dim corlib2 = corlib1.Clone()
Dim assembly2 = corlib2.Assembly
Assert.Same(assembly1.CorLibrary, assembly1)
Assert.Same(assembly2.CorLibrary, assembly2)
Assert.True(corlib1.ReferenceManagerEquals(corlib2))
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册