diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index fa2c9743ddc21..f19d7f8e9f6dd 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -613,9 +613,9 @@ private static void GetExportedTypes(NamespaceOrTypeSymbol symbol, int parentInd if (_lazyExportedTypes.IsDefault) { - _lazyExportedTypes = CalculateExportedTypes(); + var initialized = ImmutableInterlocked.InterlockedInitialize(ref _lazyExportedTypes, CalculateExportedTypes()); - if (_lazyExportedTypes.Length > 0) + if (initialized && _lazyExportedTypes.Length > 0) { ReportExportedTypeNameCollisions(_lazyExportedTypes, diagnostics); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs index 2d48c11209ee0..0d53c1bfe761d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/PEAttributeData.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection.Metadata; using System.Threading; +using Microsoft.CodeAnalysis.Collections; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -97,7 +98,7 @@ private void EnsureClassAndConstructorSymbolsAreLoaded() private void EnsureAttributeArgumentsAreLoaded() { - if (_lazyConstructorArguments.IsDefault || _lazyNamedArguments.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(in _lazyConstructorArguments).IsDefault || RoslynImmutableInterlocked.VolatileRead(in _lazyNamedArguments).IsDefault) { TypedConstant[]? lazyConstructorArguments = null; KeyValuePair[]? lazyNamedArguments = null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs index 427d4fb261044..05500ca014e0d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.cs @@ -13,6 +13,7 @@ using System.Linq; using System.Reflection.Metadata; using System; +using System.Threading; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -81,7 +82,7 @@ internal override ModuleSymbol ContainingModule protected override void EnsureAllMembersLoaded() { - if (lazyTypes == null || lazyNamespaces == null) + if (Volatile.Read(ref lazyTypes) == null || Volatile.Read(ref lazyNamespaces) == null) { IEnumerable> groups; diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 9629eda149760..ef0db5c0a96c1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -131,24 +131,24 @@ public MethodKind MethodKind public bool IsExplicitFinalizerOverride => (_bits & IsExplicitFinalizerOverrideBit) != 0; public bool IsExplicitClassOverride => (_bits & IsExplicitClassOverrideBit) != 0; public bool IsExplicitOverrideIsPopulated => (_bits & IsExplicitOverrideIsPopulatedBit) != 0; - public bool IsObsoleteAttributePopulated => (_bits & IsObsoleteAttributePopulatedBit) != 0; - public bool IsCustomAttributesPopulated => (_bits & IsCustomAttributesPopulatedBit) != 0; - public bool IsUseSiteDiagnosticPopulated => (_bits & IsUseSiteDiagnosticPopulatedBit) != 0; - public bool IsConditionalPopulated => (_bits & IsConditionalPopulatedBit) != 0; - public bool IsOverriddenOrHiddenMembersPopulated => (_bits & IsOverriddenOrHiddenMembersPopulatedBit) != 0; + public bool IsObsoleteAttributePopulated => (Volatile.Read(ref _bits) & IsObsoleteAttributePopulatedBit) != 0; + public bool IsCustomAttributesPopulated => (Volatile.Read(ref _bits) & IsCustomAttributesPopulatedBit) != 0; + public bool IsUseSiteDiagnosticPopulated => (Volatile.Read(ref _bits) & IsUseSiteDiagnosticPopulatedBit) != 0; + public bool IsConditionalPopulated => (Volatile.Read(ref _bits) & IsConditionalPopulatedBit) != 0; + public bool IsOverriddenOrHiddenMembersPopulated => (Volatile.Read(ref _bits) & IsOverriddenOrHiddenMembersPopulatedBit) != 0; public bool IsReadOnly => (_bits & IsReadOnlyBit) != 0; public bool IsReadOnlyPopulated => (_bits & IsReadOnlyPopulatedBit) != 0; public bool DoesNotReturn => (_bits & DoesNotReturnBit) != 0; public bool IsDoesNotReturnPopulated => (_bits & IsDoesNotReturnPopulatedBit) != 0; - public bool IsMemberNotNullPopulated => (_bits & IsMemberNotNullPopulatedBit) != 0; + public bool IsMemberNotNullPopulated => (Volatile.Read(ref _bits) & IsMemberNotNullPopulatedBit) != 0; public bool IsInitOnly => (_bits & IsInitOnlyBit) != 0; public bool IsInitOnlyPopulated => (_bits & IsInitOnlyPopulatedBit) != 0; - public bool IsUnmanagedCallersOnlyAttributePopulated => (_bits & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; + public bool IsUnmanagedCallersOnlyAttributePopulated => (Volatile.Read(ref _bits) & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; public bool HasSetsRequiredMembers => (_bits & HasSetsRequiredMembersBit) != 0; public bool HasSetsRequiredMembersPopulated => (_bits & HasSetsRequiredMembersPopulatedBit) != 0; public bool IsUnscopedRef => (_bits & IsUnscopedRefBit) != 0; public bool IsUnscopedRefPopulated => (_bits & IsUnscopedRefPopulatedBit) != 0; - public bool IsOverloadResolutionPriorityPopulated => (_bits & OverloadResolutionPriorityPopulatedBit) != 0; + public bool IsOverloadResolutionPriorityPopulated => (Volatile.Read(ref _bits) & OverloadResolutionPriorityPopulatedBit) != 0; #if DEBUG static PackedFlags() diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index ea2cd5b3dbaa5..97ccabb558fdb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -15,6 +15,7 @@ using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.DocumentationComments; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; @@ -1260,7 +1261,7 @@ private void EnsureEnumUnderlyingTypeIsLoaded(UncommonProperties uncommon) private void EnsureAllMembersAreLoaded() { - if (_lazyMembersByName == null) + if (Volatile.Read(ref _lazyMembersByName) == null) { LoadMembers(); } @@ -1270,7 +1271,7 @@ private void LoadMembers() { ArrayBuilder members = null; - if (_lazyMembersInDeclarationOrder.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyMembersInDeclarationOrder).IsDefault) { EnsureNestedTypesAreLoaded(); @@ -1440,7 +1441,7 @@ private void LoadMembers() } } - if (_lazyMembersByName == null) + if (Volatile.Read(ref _lazyMembersByName) == null) { if (members == null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs index 797c31a8e713f..926726b82aaa3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.cs @@ -125,11 +125,14 @@ internal override ModuleSymbol ContainingModule protected override void EnsureAllMembersLoaded() { - var typesByNS = _typesByNS; + var typesByNS = Volatile.Read(ref _typesByNS); - if (lazyTypes == null || lazyNamespaces == null) + if (typesByNS == null) + { + Debug.Assert(lazyNamespaces != null && lazyTypes != null); + } + else { - System.Diagnostics.Debug.Assert(typesByNS != null); LoadAllMembers(typesByNS); Interlocked.Exchange(ref _typesByNS, null); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index 0956462733b10..86e4c0dd8c549 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -128,28 +128,28 @@ public void SetUseSiteDiagnosticPopulated() ThreadSafeFlagOperations.Set(ref _bits, IsUseSiteDiagnosticPopulatedBit); } - public readonly bool IsUseSiteDiagnosticPopulated => (_bits & IsUseSiteDiagnosticPopulatedBit) != 0; + public bool IsUseSiteDiagnosticPopulated => (Volatile.Read(ref _bits) & IsUseSiteDiagnosticPopulatedBit) != 0; public void SetObsoleteAttributePopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsObsoleteAttributePopulatedBit); } - public readonly bool IsObsoleteAttributePopulated => (_bits & IsObsoleteAttributePopulatedBit) != 0; + public bool IsObsoleteAttributePopulated => (Volatile.Read(ref _bits) & IsObsoleteAttributePopulatedBit) != 0; public void SetCustomAttributesPopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsCustomAttributesPopulatedBit); } - public readonly bool IsCustomAttributesPopulated => (_bits & IsCustomAttributesPopulatedBit) != 0; + public bool IsCustomAttributesPopulated => (Volatile.Read(ref _bits) & IsCustomAttributesPopulatedBit) != 0; public void SetOverloadResolutionPriorityPopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsOverloadResolutionPriorityPopulatedBit); } - public readonly bool IsOverloadResolutionPriorityPopulated => (_bits & IsOverloadResolutionPriorityPopulatedBit) != 0; + public bool IsOverloadResolutionPriorityPopulated => (Volatile.Read(ref _bits) & IsOverloadResolutionPriorityPopulatedBit) != 0; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index ae6accbadf890..9a48e210bf529 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -12,6 +12,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -152,7 +153,7 @@ private ImmutableArray GetDeclaredConstraintTypes(ConsList< Debug.Assert(!inProgress.ContainsReference(this)); Debug.Assert(!inProgress.Any() || ReferenceEquals(inProgress.Head.ContainingSymbol, this.ContainingSymbol)); - if (_lazyDeclaredConstraintTypes.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyDeclaredConstraintTypes).IsDefault) { ImmutableArray declaredConstraintTypes; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 3c962f0b90f64..42e505bfe480d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Threading; using Microsoft.Cci; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -181,7 +182,7 @@ public override ImmutableArray Parameters private void ComputeParameters() { - if (_lazyParameters != null) + if (!RoslynImmutableInterlocked.VolatileRead(in _lazyParameters).IsDefault) { return; } @@ -211,7 +212,7 @@ private void ComputeParameters() lock (_declarationDiagnostics) { - if (_lazyParameters != null) + if (!_lazyParameters.IsDefault) { diagnostics.Free(); return; @@ -221,7 +222,7 @@ private void ComputeParameters() _declarationDependencies.AddAll(diagnostics.DependenciesBag); diagnostics.Free(); _lazyIsVarArg = isVararg; - _lazyParameters = parameters; + RoslynImmutableInterlocked.VolatileWrite(ref _lazyParameters, parameters); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs index 45b0527c8d466..8887c4520419b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedMethodSymbol.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -99,7 +100,7 @@ public sealed override ImmutableArray TypeParameters private void EnsureMapAndTypeParameters() { - if (!_lazyTypeParameters.IsDefault) + if (!RoslynImmutableInterlocked.VolatileRead(ref _lazyTypeParameters).IsDefault) { return; } diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs index d22f7e120c75b..914ab75c586a0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -96,7 +97,7 @@ public sealed override ImmutableArray TypeParameters private void EnsureMapAndTypeParameters() { - if (!_lazyTypeParameters.IsDefault) + if (!RoslynImmutableInterlocked.VolatileRead(ref _lazyTypeParameters).IsDefault) { return; } diff --git a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs index 6e9655d6fcf14..0f51cba9942bd 100644 --- a/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs +++ b/src/Compilers/Core/Portable/Syntax/SyntaxTree.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -369,11 +370,11 @@ internal int GetDisplayLineNumber(TextSpan span) /// internal Cci.DebugSourceInfo GetDebugSourceInfo() { - if (_lazyChecksum.IsDefault) + if (RoslynImmutableInterlocked.VolatileRead(ref _lazyChecksum).IsDefault) { var text = this.GetText(); - _lazyChecksum = text.GetChecksum(); _lazyHashAlgorithm = text.ChecksumAlgorithm; + ImmutableInterlocked.InterlockedInitialize(ref _lazyChecksum, text.GetChecksum()); } Debug.Assert(!_lazyChecksum.IsDefault); diff --git a/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb b/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb index 973c68d5ce6b4..c9f0bab9b7d3a 100644 --- a/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb +++ b/src/Compilers/VisualBasic/Portable/BoundTree/BoundMethodGroup.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Runtime.InteropServices Imports System.Threading +Imports Microsoft.CodeAnalysis.Collections Namespace Microsoft.CodeAnalysis.VisualBasic @@ -55,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Debug.Assert(group.PendingExtensionMethodsOpt Is Me) Debug.Assert(Not useSiteInfo.AccumulatesDependencies OrElse _withDependencies) - If _lazyMethods.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyMethods).IsDefault Then Dim receiverOpt As BoundExpression = group.ReceiverOpt Dim methods As ImmutableArray(Of MethodSymbol) = ImmutableArray(Of MethodSymbol).Empty Dim localUseSiteInfo = If(_withDependencies, New CompoundUseSiteInfo(Of AssemblySymbol)(_lookupBinder.Compilation.Assembly), CompoundUseSiteInfo(Of AssemblySymbol).DiscardedDependencies) diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index 37bc77ab98fe6..c8a52432fcef3 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -386,9 +386,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Debug.Assert(HaveDeterminedTopLevelTypes) If _lazyExportedTypes.IsDefault Then - _lazyExportedTypes = CalculateExportedTypes() + Dim initialized = ImmutableInterlocked.InterlockedInitialize(_lazyExportedTypes, CalculateExportedTypes()) - If _lazyExportedTypes.Length > 0 Then + If initialized AndAlso _lazyExportedTypes.Length > 0 Then ReportExportedTypeNameCollisions(_lazyExportedTypes, diagnostics) End If End If diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb index 49d368b35393f..16c6e01fcdfd1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Attributes/PEAttributeData.vb @@ -120,7 +120,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Sub EnsureLazyMembersAreLoaded() - If _lazyConstructorArguments Is Nothing Then + If Volatile.Read(_lazyConstructorArguments) Is Nothing Then Dim constructorArgs As TypedConstant() = Nothing Dim namedArgs As KeyValuePair(Of String, TypedConstant)() = Nothing diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb index 008058c1912b4..f8d33217132f5 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEGlobalNamespaceSymbol.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Reflection.Metadata +Imports System.Threading Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -61,7 +62,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Protected Overrides Sub EnsureAllMembersLoaded() - If m_lazyTypes Is Nothing OrElse m_lazyMembers Is Nothing Then + If Volatile.Read(m_lazyTypes) Is Nothing OrElse Volatile.Read(m_lazyMembers) Is Nothing Then Dim groups As IEnumerable(Of IGrouping(Of String, TypeDefinitionHandle)) Try diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb index ab330becff378..40f251bd074d6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb @@ -113,25 +113,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Public ReadOnly Property IsObsoleteAttributePopulated As Boolean Get - Return (_bits And s_isObsoleteAttributePopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isObsoleteAttributePopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsCustomAttributesPopulated As Boolean Get - Return (_bits And s_isCustomAttributesPopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isCustomAttributesPopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsUseSiteDiagnosticPopulated As Boolean Get - Return (_bits And s_isUseSiteDiagnosticPopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isUseSiteDiagnosticPopulatedBit) <> 0 End Get End Property Public ReadOnly Property IsConditionalPopulated As Boolean Get - Return (_bits And s_isConditionalAttributePopulatedBit) <> 0 + Return (Volatile.Read(_bits) And s_isConditionalAttributePopulatedBit) <> 0 End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb index 7f75caa280d6a..3f2ff1e388873 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb @@ -649,7 +649,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private Sub EnsureNonTypeMembersAreLoaded() - If _lazyMembers Is Nothing Then + If Volatile.Read(_lazyMembers) Is Nothing Then ' A method may be referenced as an accessor by one or more properties. And, ' any of those properties may be "bogus" if one of the property accessors ' does not match the property signature. If the method is referenced by at diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb index 00c6f1ffb132a..606f94044b031 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENestedNamespaceSymbol.vb @@ -118,10 +118,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Protected Overrides Sub EnsureAllMembersLoaded() - Dim typesByNS = _typesByNS + Dim typesByNS = Volatile.Read(_typesByNS) - If m_lazyTypes Is Nothing OrElse m_lazyMembers Is Nothing Then - Debug.Assert(typesByNS IsNot Nothing) + If typesByNS Is Nothing Then + Debug.Assert(m_lazyTypes IsNot Nothing AndAlso m_lazyMembers IsNot Nothing) + Else LoadAllMembers(typesByNS) Interlocked.Exchange(_typesByNS, Nothing) End If diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb index e1d387a2b4924..055fb569b2251 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Reflection Imports System.Reflection.Metadata.Ecma335 Imports System.Runtime.InteropServices +Imports Microsoft.CodeAnalysis.Collections Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -312,7 +313,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Property Friend Overrides Sub EnsureAllConstraintsAreResolved() - If _lazyConstraintTypes.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then Dim typeParameters = If(_containingSymbol.Kind = SymbolKind.Method, DirectCast(_containingSymbol, PEMethodSymbol).TypeParameters, DirectCast(_containingSymbol, PENamedTypeSymbol).TypeParameters) @@ -324,7 +325,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Debug.Assert(Not inProgress.Contains(Me)) Debug.Assert(Not inProgress.Any() OrElse inProgress.Head.ContainingSymbol Is ContainingSymbol) - If _lazyConstraintTypes.IsDefault Then + If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance() Dim inherited = (_containingSymbol.Kind = SymbolKind.Method) AndAlso DirectCast(_containingSymbol, MethodSymbol).IsOverrides Dim hasUnmanagedModreqPattern As Boolean = False diff --git a/src/Dependencies/Collections/RoslynImmutableInterlocked.cs b/src/Dependencies/Collections/RoslynImmutableInterlocked.cs index a96084a0bab16..6e5e8742d30c7 100644 --- a/src/Dependencies/Collections/RoslynImmutableInterlocked.cs +++ b/src/Dependencies/Collections/RoslynImmutableInterlocked.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Threading; namespace Microsoft.CodeAnalysis.Collections { @@ -605,5 +606,32 @@ public static bool TryRemove(ref ImmutableSegmentedDictionary + /// Reads from an ImmutableArray location, ensuring that a read barrier is inserted to prevent any subsequent reads from being reordered before this read. + /// + /// + /// This method is not intended to be used to provide write barriers. + /// + public static ImmutableArray VolatileRead(ref readonly ImmutableArray location) + { + var value = location; + // When Volatile.ReadBarrier() is available in .NET 10, it can be used here. + Interlocked.MemoryBarrier(); + return value; + } + + /// + /// Writes to an ImmutableArray location, ensuring that a write barrier is inserted to prevent any prior writes from being reordered after this write. + /// + /// + /// This method is not intended to be used to provide read barriers. + /// + public static void VolatileWrite(ref ImmutableArray location, ImmutableArray value) + { + // When Volatile.WriteBarrier() is available in .NET 10, it can be used here. + Interlocked.MemoryBarrier(); + location = value; + } } }