Skip to content

Commit 70384b5

Browse files
authored
ExtensionGroupingInfo - reduce consumed memory and delay creation of Cci adapter instances until emit (#79755)
1 parent 3e5a856 commit 70384b5

File tree

1 file changed

+51
-43
lines changed

1 file changed

+51
-43
lines changed

src/Compilers/CSharp/Portable/Symbols/Source/ExtensionGroupingInfo.cs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,13 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
2121
{
2222
internal sealed class ExtensionGroupingInfo
2323
{
24-
/// <summary>
25-
/// Extension block symbols declared in a class are grouped by their corresponding grouping type metadata name (top level key),
26-
/// then grouped by their corresponding extension marker type metadata name (the secondary key used by MultiDictionary).
27-
/// <see cref="SourceNamedTypeSymbol"/>s are the extension blocks.
28-
/// </summary>
29-
private readonly Dictionary<string, MultiDictionary<string, SourceNamedTypeSymbol>> _groupingMap;
30-
private ImmutableArray<ExtensionGroupingType> _lazyGroupingTypes;
24+
private readonly ImmutableArray<ExtensionGroupingType> _groupingTypes;
3125

3226
public ExtensionGroupingInfo(SourceMemberContainerTypeSymbol container)
3327
{
28+
// Extension block symbols declared in a class are grouped by their corresponding grouping type metadata name (top level key),
29+
// then grouped by their corresponding extension marker type metadata name (the secondary key used by MultiDictionary).
30+
// SourceNamedTypeSymbols are the extension blocks.
3431
var groupingMap = new Dictionary<string, MultiDictionary<string, SourceNamedTypeSymbol>>(EqualityComparer<string>.Default);
3532

3633
foreach (var type in container.GetTypeMembers(""))
@@ -54,7 +51,16 @@ public ExtensionGroupingInfo(SourceMemberContainerTypeSymbol container)
5451
markerMap.Add(sourceNamedType.ExtensionMarkerName, sourceNamedType);
5552
}
5653

57-
_groupingMap = groupingMap;
54+
var builder = ArrayBuilder<ExtensionGroupingType>.GetInstance(groupingMap.Count);
55+
56+
foreach (KeyValuePair<string, MultiDictionary<string, SourceNamedTypeSymbol>> pair in groupingMap)
57+
{
58+
builder.Add(new ExtensionGroupingType(pair.Key, pair.Value));
59+
}
60+
61+
builder.Sort();
62+
63+
_groupingTypes = builder.ToImmutableAndFree();
5864
AssertInvariants(container);
5965
}
6066

@@ -94,21 +100,7 @@ private void AssertInvariants(SourceMemberContainerTypeSymbol container)
94100

95101
public ImmutableArray<Cci.INestedTypeDefinition> GetGroupingTypes()
96102
{
97-
if (_lazyGroupingTypes.IsDefault)
98-
{
99-
var builder = ArrayBuilder<ExtensionGroupingType>.GetInstance(_groupingMap.Count);
100-
101-
foreach (KeyValuePair<string, MultiDictionary<string, SourceNamedTypeSymbol>> pair in _groupingMap)
102-
{
103-
builder.Add(new ExtensionGroupingType(pair.Key, pair.Value));
104-
}
105-
106-
builder.Sort();
107-
108-
ImmutableInterlocked.InterlockedInitialize(ref _lazyGroupingTypes, builder.ToImmutableAndFree());
109-
}
110-
111-
return ImmutableArray<Cci.INestedTypeDefinition>.CastUp(_lazyGroupingTypes);
103+
return ImmutableArray<Cci.INestedTypeDefinition>.CastUp(_groupingTypes);
112104
}
113105

114106
public Cci.ITypeDefinition GetCorrespondingMarkerType(SynthesizedExtensionMarker markerMethod)
@@ -119,13 +111,12 @@ public Cci.ITypeDefinition GetCorrespondingMarkerType(SynthesizedExtensionMarker
119111
private ExtensionMarkerType GetCorrespondingMarkerType(SourceNamedTypeSymbol extension)
120112
{
121113
Debug.Assert(extension.IsExtension);
122-
GetGroupingTypes();
123114

124115
// Tracked by https://github.com/dotnet/roslyn/issues/78827 : Optimize lookup with side dictionaries?
125116
var groupingName = extension.ExtensionGroupingName;
126117
var markerName = extension.ExtensionMarkerName;
127118

128-
foreach (var groupingType in _lazyGroupingTypes)
119+
foreach (var groupingType in _groupingTypes)
129120
{
130121
if (groupingType.Name != groupingName)
131122
{
@@ -180,12 +171,11 @@ public Cci.TypeMemberVisibility GetCorrespondingMarkerMethodVisibility(Synthesiz
180171
public Cci.ITypeDefinition GetCorrespondingGroupingType(SourceNamedTypeSymbol extension)
181172
{
182173
Debug.Assert(extension.IsExtension);
183-
GetGroupingTypes();
184174

185175
// Tracked by https://github.com/dotnet/roslyn/issues/78827 : Optimize lookup with a side dictionary?
186176
var groupingName = extension.ExtensionGroupingName;
187177

188-
foreach (var groupingType in _lazyGroupingTypes)
178+
foreach (var groupingType in _groupingTypes)
189179
{
190180
if (groupingType.Name == groupingName)
191181
{
@@ -210,8 +200,7 @@ internal ImmutableArray<SourceNamedTypeSymbol> GetMergedExtensions(SourceNamedTy
210200
/// </summary>
211201
internal IEnumerable<ImmutableArray<SourceNamedTypeSymbol>> EnumerateMergedExtensionBlocks()
212202
{
213-
GetGroupingTypes();
214-
foreach (var groupingType in _lazyGroupingTypes)
203+
foreach (var groupingType in _groupingTypes)
215204
{
216205
foreach (var markerType in groupingType.ExtensionMarkerTypes)
217206
{
@@ -436,10 +425,9 @@ static void substituteConstraintTypes(ImmutableArray<TypeWithAnnotations> types,
436425
/// </summary>
437426
internal void CheckSignatureCollisions(BindingDiagnosticBag diagnostics)
438427
{
439-
GetGroupingTypes();
440428
PooledHashSet<SourceNamedTypeSymbol>? alreadyReportedExtensions = null;
441429

442-
foreach (ExtensionGroupingType groupingType in _lazyGroupingTypes)
430+
foreach (ExtensionGroupingType groupingType in _groupingTypes)
443431
{
444432
checkCollisions(enumerateExtensionsInGrouping(groupingType), HaveSameILSignature, ref alreadyReportedExtensions, diagnostics);
445433
}
@@ -691,7 +679,7 @@ private sealed class ExtensionGroupingType : ExtensionGroupingOrMarkerType, ICom
691679
{
692680
private readonly string _name;
693681
public readonly ImmutableArray<ExtensionMarkerType> ExtensionMarkerTypes;
694-
private readonly ImmutableArray<ExtensionGroupingTypeTypeParameter> _typeParameters;
682+
private ImmutableArray<ExtensionGroupingTypeTypeParameter> _lazyTypeParameters;
695683

696684
public ExtensionGroupingType(string name, MultiDictionary<string, SourceNamedTypeSymbol> extensionMarkerTypes)
697685
{
@@ -706,10 +694,6 @@ public ExtensionGroupingType(string name, MultiDictionary<string, SourceNamedTyp
706694

707695
builder.Sort();
708696
ExtensionMarkerTypes = builder.ToImmutableAndFree();
709-
710-
_typeParameters = ExtensionMarkerTypes[0].UnderlyingExtensions[0].Arity != 0 ?
711-
((INestedTypeDefinition)ExtensionMarkerTypes[0].UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new ExtensionGroupingTypeTypeParameter(@this, p), this) :
712-
[];
713697
}
714698

715699
int IComparable<ExtensionGroupingType>.CompareTo(ExtensionGroupingType? other)
@@ -718,7 +702,21 @@ int IComparable<ExtensionGroupingType>.CompareTo(ExtensionGroupingType? other)
718702
return ExtensionMarkerTypes[0].CompareTo(other.ExtensionMarkerTypes[0]);
719703
}
720704

721-
protected override IEnumerable<IGenericTypeParameter> GenericParameters => _typeParameters;
705+
protected override IEnumerable<IGenericTypeParameter> GenericParameters
706+
{
707+
get
708+
{
709+
if (_lazyTypeParameters.IsDefault)
710+
{
711+
var typeParameters = ExtensionMarkerTypes[0].UnderlyingExtensions[0].Arity != 0 ?
712+
((INestedTypeDefinition)ExtensionMarkerTypes[0].UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new ExtensionGroupingTypeTypeParameter(@this, p), this) :
713+
[];
714+
ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameters, typeParameters);
715+
}
716+
717+
return _lazyTypeParameters;
718+
}
719+
}
722720

723721
protected override ushort GenericParameterCount => (ushort)ExtensionMarkerTypes[0].UnderlyingExtensions[0].Arity;
724722

@@ -841,7 +839,7 @@ private sealed class ExtensionMarkerType : ExtensionGroupingOrMarkerType, ICompa
841839
public readonly ExtensionGroupingType GroupingType;
842840
private readonly string _name;
843841
public readonly ImmutableArray<SourceNamedTypeSymbol> UnderlyingExtensions;
844-
private readonly ImmutableArray<InheritedTypeParameter> _typeParameters;
842+
private ImmutableArray<InheritedTypeParameter> _lazyTypeParameters;
845843

846844
public ExtensionMarkerType(ExtensionGroupingType groupingType, string name, MultiDictionary<string, SourceNamedTypeSymbol>.ValueSet extensions)
847845
{
@@ -852,10 +850,6 @@ public ExtensionMarkerType(ExtensionGroupingType groupingType, string name, Mult
852850
builder.AddRange(extensions);
853851
builder.Sort(LexicalOrderSymbolComparer.Instance);
854852
UnderlyingExtensions = builder.ToImmutableAndFree();
855-
856-
_typeParameters = UnderlyingExtensions[0].Arity != 0 ?
857-
((INestedTypeDefinition)UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new InheritedTypeParameter(p.Index, @this, p), this) :
858-
[];
859853
}
860854

861855
public int CompareTo(ExtensionMarkerType? other)
@@ -864,7 +858,21 @@ public int CompareTo(ExtensionMarkerType? other)
864858
return LexicalOrderSymbolComparer.Instance.Compare(UnderlyingExtensions[0], other.UnderlyingExtensions[0]);
865859
}
866860

867-
protected override IEnumerable<IGenericTypeParameter> GenericParameters => _typeParameters;
861+
protected override IEnumerable<IGenericTypeParameter> GenericParameters
862+
{
863+
get
864+
{
865+
if (_lazyTypeParameters.IsDefault)
866+
{
867+
var typeParameters = UnderlyingExtensions[0].Arity != 0 ?
868+
((INestedTypeDefinition)UnderlyingExtensions[0].GetCciAdapter()).GenericParameters.SelectAsArray(static (p, @this) => new InheritedTypeParameter(p.Index, @this, p), this) :
869+
[];
870+
ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameters, typeParameters);
871+
}
872+
873+
return _lazyTypeParameters;
874+
}
875+
}
868876

869877
protected override ushort GenericParameterCount => (ushort)UnderlyingExtensions[0].Arity;
870878

0 commit comments

Comments
 (0)