From 987c5bfff0f554f23315e53ad42be3787e3de177 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 11:22:16 -0700 Subject: [PATCH 01/11] Use a singleton for empty type-parameters for named types --- .../Symbols/Source/SourceNamedTypeSymbol.cs | 68 +++++++++++++++---- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 01950c5021b6d..54ae640a08c20 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; @@ -19,23 +20,47 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - // This is a type symbol associated with a type definition in source code. - // That is, for a generic type C this is the instance type C. - internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeSymbol, IAttributeTargetSymbol + internal sealed class SourceNamedTypeSymbolTypeParameterInfo { - private ImmutableArray _lazyTypeParameters; + public readonly ImmutableArray TypeParameters; /// /// A collection of type parameter constraint types, populated when /// constraint types for the first type parameter are requested. /// - private ImmutableArray> _lazyTypeParameterConstraintTypes; + public ImmutableArray> LazyTypeParameterConstraintTypes; /// /// A collection of type parameter constraint kinds, populated when /// constraint kinds for the first type parameter are requested. /// - private ImmutableArray _lazyTypeParameterConstraintKinds; + public ImmutableArray LazyTypeParameterConstraintKinds; + + public static readonly SourceNamedTypeSymbolTypeParameterInfo Empty = new SourceNamedTypeSymbolTypeParameterInfo( + ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); + + private SourceNamedTypeSymbolTypeParameterInfo( + ImmutableArray typeParameters, + ImmutableArray> typeParameterConstraintTypes, + ImmutableArray typeParameterConstraintKinds) + { + TypeParameters = typeParameters; + LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; + LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; + } + + public static SourceNamedTypeSymbolTypeParameterInfo Create(ImmutableArray typeParameters) + { + // If we have no type parameters (common case), we can just point at the singleton empty instance. + return typeParameters.IsEmpty ? Empty : new SourceNamedTypeSymbolTypeParameterInfo(typeParameters, default, default); + } + } + + // This is a type symbol associated with a type definition in source code. + // That is, for a generic type C this is the instance type C. + internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeSymbol, IAttributeTargetSymbol + { + private SourceNamedTypeSymbolTypeParameterInfo _lazyTypeParameterInfo; private CustomAttributesBag _lazyCustomAttributesBag; @@ -277,18 +302,24 @@ internal ImmutableArray GetTypeParameterConstraintTypes(int private ImmutableArray> GetTypeParameterConstraintTypes() { - var constraintTypes = _lazyTypeParameterConstraintTypes; + var constraintTypes = _lazyTypeParameterInfo?.LazyTypeParameterConstraintTypes ?? default; if (constraintTypes.IsDefault) { GetTypeParameterConstraintKinds(); var diagnostics = BindingDiagnosticBag.GetInstance(); - if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintTypes, MakeTypeParameterConstraintTypes(diagnostics))) + var localConstraintTypes = MakeTypeParameterConstraintTypes(diagnostics); + Debug.Assert(_lazyTypeParameterInfo != null); + + if (ImmutableInterlocked.InterlockedInitialize( + ref _lazyTypeParameterInfo.LazyTypeParameterConstraintTypes, + localConstraintTypes)) { this.AddDeclarationDiagnostics(diagnostics); } + diagnostics.Free(); - constraintTypes = _lazyTypeParameterConstraintTypes; + constraintTypes = _lazyTypeParameterInfo.LazyTypeParameterConstraintTypes; } return constraintTypes; @@ -305,11 +336,15 @@ internal TypeParameterConstraintKind GetTypeParameterConstraintKind(int ordinal) private ImmutableArray GetTypeParameterConstraintKinds() { - var constraintKinds = _lazyTypeParameterConstraintKinds; + var constraintKinds = _lazyTypeParameterInfo?.LazyTypeParameterConstraintKinds ?? default; if (constraintKinds.IsDefault) { - ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintKinds, MakeTypeParameterConstraintKinds()); - constraintKinds = _lazyTypeParameterConstraintKinds; + var localConstraintKinds = MakeTypeParameterConstraintKinds(); + Debug.Assert(_lazyTypeParameterInfo != null); + + ImmutableInterlocked.InterlockedInitialize( + ref _lazyTypeParameterInfo.LazyTypeParameterConstraintKinds, localConstraintKinds); + constraintKinds = _lazyTypeParameterInfo.LazyTypeParameterConstraintKinds; } return constraintKinds; @@ -749,10 +784,13 @@ public override ImmutableArray TypeParameters { get { - if (_lazyTypeParameters.IsDefault) + if (_lazyTypeParameterInfo is null) { var diagnostics = BindingDiagnosticBag.GetInstance(); - if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameters, MakeTypeParameters(diagnostics))) + if (Interlocked.CompareExchange( + ref _lazyTypeParameterInfo, + SourceNamedTypeSymbolTypeParameterInfo.Create(MakeTypeParameters(diagnostics)), + comparand: null) is null) { AddDeclarationDiagnostics(diagnostics); } @@ -760,7 +798,7 @@ public override ImmutableArray TypeParameters diagnostics.Free(); } - return _lazyTypeParameters; + return _lazyTypeParameterInfo.TypeParameters; } } From f54b27543634747ddb99b00ab136959764ab29e7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 12:22:03 -0700 Subject: [PATCH 02/11] move type parameters down --- .../Source/SourceOrdinaryMethodSymbol.cs | 23 ++++++++++--------- .../Source/SourceOrdinaryMethodSymbolBase.cs | 12 +--------- .../SynthesizedRecordOrdinaryMethod.cs | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 55127be6d829e..ab1936aaea049 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -25,6 +25,8 @@ internal sealed class SourceOrdinaryMethodSymbol : SourceOrdinaryMethodSymbolBas private readonly RefKind _refKind; private bool _lazyIsVararg; + private readonly ImmutableArray _typeParameters; + /// /// A collection of type parameter constraint types, populated when /// constraint types for the first type parameter is requested. @@ -92,6 +94,8 @@ private SourceOrdinaryMethodSymbol( { Debug.Assert(diagnostics.DiagnosticBag is object); + _typeParameters = MakeTypeParameters(syntax, diagnostics); + _explicitInterfaceType = explicitInterfaceType; bool hasBlockBody = syntax.Body != null; @@ -105,18 +109,9 @@ private SourceOrdinaryMethodSymbol( syntax.Body, syntax.ExpressionBody, syntax, diagnostics); } - protected override ImmutableArray MakeTypeParameters(CSharpSyntaxNode node, BindingDiagnosticBag diagnostics) + public override ImmutableArray TypeParameters { - var syntax = (MethodDeclarationSyntax)node; - if (syntax.Arity == 0) - { - ReportErrorIfHasConstraints(syntax.ConstraintClauses, diagnostics.DiagnosticBag); - return ImmutableArray.Empty; - } - else - { - return MakeTypeParameters(syntax, diagnostics); - } + get { return _typeParameters; } } protected override (TypeWithAnnotations ReturnType, ImmutableArray Parameters, bool IsVararg, ImmutableArray DeclaredConstraintsForOverrideOrImplementation) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics) @@ -530,6 +525,12 @@ protected override DeclarationModifiers MakeDeclarationModifiers(DeclarationModi private ImmutableArray MakeTypeParameters(MethodDeclarationSyntax syntax, BindingDiagnosticBag diagnostics) { + if (syntax.Arity == 0) + { + ReportErrorIfHasConstraints(syntax.ConstraintClauses, diagnostics.DiagnosticBag); + return ImmutableArray.Empty; + } + Debug.Assert(syntax.TypeParameterList != null); MessageID.IDS_FeatureGenerics.CheckFeatureAvailability(diagnostics, syntax.TypeParameterList.LessThanToken); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs index 9769624caabcf..58fe98c0a9c90 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs @@ -23,7 +23,6 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// internal abstract class SourceOrdinaryMethodSymbolBase : SourceOrdinaryMethodOrUserDefinedOperatorSymbol { - private readonly ImmutableArray _typeParameters; private readonly string _name; protected SourceOrdinaryMethodSymbolBase( @@ -62,8 +61,6 @@ protected SourceOrdinaryMethodSymbolBase( this.MakeFlags(methodKind, declarationModifiers, returnsVoid, isExtensionMethod: isExtensionMethod, isNullableAnalysisEnabled: isNullableAnalysisEnabled, isMetadataVirtualIgnoringModifiers: isMetadataVirtualIgnoringModifiers); - _typeParameters = MakeTypeParameters(syntax, diagnostics); - CheckFeatureAvailabilityAndRuntimeSupport(syntax, location, hasBody, diagnostics); if (hasBody) @@ -74,8 +71,6 @@ protected SourceOrdinaryMethodSymbolBase( ModifierUtils.CheckAccessibility(this.DeclarationModifiers, this, isExplicitInterfaceImplementation: isExplicitInterfaceImplementation, diagnostics, location); } - protected abstract ImmutableArray MakeTypeParameters(CSharpSyntaxNode node, BindingDiagnosticBag diagnostics); - #nullable enable protected override void MethodChecks(BindingDiagnosticBag diagnostics) { @@ -89,7 +84,7 @@ protected override void MethodChecks(BindingDiagnosticBag diagnostics) { for (int i = 0; i < declaredConstraints.Length; i++) { - var typeParameter = _typeParameters[i]; + var typeParameter = this.TypeParameters[i]; ErrorCode report; switch (declaredConstraints[i].Constraints & (TypeParameterConstraintKind.ReferenceType | TypeParameterConstraintKind.ValueType | TypeParameterConstraintKind.Default)) @@ -171,11 +166,6 @@ private void CompleteAsyncMethodChecks(BindingDiagnosticBag diagnosticsOpt, Canc protected abstract void CompleteAsyncMethodChecksBetweenStartAndFinish(); - public override ImmutableArray TypeParameters - { - get { return _typeParameters; } - } - public abstract override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)); public override string Name diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs index c497dbc226869..f063d89aa6ca9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordOrdinaryMethod.cs @@ -39,7 +39,7 @@ protected SynthesizedRecordOrdinaryMethod(SourceMemberContainerTypeSymbol contai internal sealed override LexicalSortKey GetLexicalSortKey() => LexicalSortKey.GetSynthesizedMemberKey(_memberOffset); - protected sealed override ImmutableArray MakeTypeParameters(CSharpSyntaxNode node, BindingDiagnosticBag diagnostics) => ImmutableArray.Empty; + public sealed override ImmutableArray TypeParameters => ImmutableArray.Empty; public sealed override ImmutableArray> GetTypeParameterConstraintTypes() => ImmutableArray>.Empty; From 8f7e812da1c20579ba8eb37bc21523bdea892941 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 12:27:38 -0700 Subject: [PATCH 03/11] Optimize methods as well --- .../Symbols/Source/SourceNamedTypeSymbol.cs | 17 ++++----- .../Source/SourceOrdinaryMethodSymbol.cs | 36 +++++++------------ 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 54ae640a08c20..0e4ef400a1168 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; @@ -20,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class SourceNamedTypeSymbolTypeParameterInfo + internal sealed class TypeParameterInfo { public readonly ImmutableArray TypeParameters; @@ -36,10 +35,10 @@ internal sealed class SourceNamedTypeSymbolTypeParameterInfo /// public ImmutableArray LazyTypeParameterConstraintKinds; - public static readonly SourceNamedTypeSymbolTypeParameterInfo Empty = new SourceNamedTypeSymbolTypeParameterInfo( + public static readonly TypeParameterInfo Empty = new TypeParameterInfo( ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); - private SourceNamedTypeSymbolTypeParameterInfo( + private TypeParameterInfo( ImmutableArray typeParameters, ImmutableArray> typeParameterConstraintTypes, ImmutableArray typeParameterConstraintKinds) @@ -49,10 +48,10 @@ private SourceNamedTypeSymbolTypeParameterInfo( LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; } - public static SourceNamedTypeSymbolTypeParameterInfo Create(ImmutableArray typeParameters) + public static TypeParameterInfo Create(ImmutableArray typeParameters) { // If we have no type parameters (common case), we can just point at the singleton empty instance. - return typeParameters.IsEmpty ? Empty : new SourceNamedTypeSymbolTypeParameterInfo(typeParameters, default, default); + return typeParameters.IsEmpty ? Empty : new TypeParameterInfo(typeParameters, default, default); } } @@ -60,7 +59,9 @@ public static SourceNamedTypeSymbolTypeParameterInfo Create(ImmutableArray this is the instance type C. internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeSymbol, IAttributeTargetSymbol { - private SourceNamedTypeSymbolTypeParameterInfo _lazyTypeParameterInfo; +#nullable enable + private TypeParameterInfo? _lazyTypeParameterInfo; +#nullable disable private CustomAttributesBag _lazyCustomAttributesBag; @@ -789,7 +790,7 @@ public override ImmutableArray TypeParameters var diagnostics = BindingDiagnosticBag.GetInstance(); if (Interlocked.CompareExchange( ref _lazyTypeParameterInfo, - SourceNamedTypeSymbolTypeParameterInfo.Create(MakeTypeParameters(diagnostics)), + TypeParameterInfo.Create(MakeTypeParameters(diagnostics)), comparand: null) is null) { AddDeclarationDiagnostics(diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index ab1936aaea049..a00c38d878231 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -25,21 +25,7 @@ internal sealed class SourceOrdinaryMethodSymbol : SourceOrdinaryMethodSymbolBas private readonly RefKind _refKind; private bool _lazyIsVararg; - private readonly ImmutableArray _typeParameters; - - /// - /// A collection of type parameter constraint types, populated when - /// constraint types for the first type parameter is requested. - /// Initialized in two steps. Hold a copy if accessing during initialization. - /// - private ImmutableArray> _lazyTypeParameterConstraintTypes; - - /// - /// A collection of type parameter constraint kinds, populated when - /// constraint kinds for the first type parameter is requested. - /// Initialized in two steps. Hold a copy if accessing during initialization. - /// - private ImmutableArray _lazyTypeParameterConstraintKinds; + private readonly TypeParameterInfo _typeParameterInfo; /// /// If this symbol represents a partial method definition or implementation part, its other part (if any). @@ -94,7 +80,7 @@ private SourceOrdinaryMethodSymbol( { Debug.Assert(diagnostics.DiagnosticBag is object); - _typeParameters = MakeTypeParameters(syntax, diagnostics); + _typeParameterInfo = TypeParameterInfo.Create(MakeTypeParameters(syntax, diagnostics)); _explicitInterfaceType = explicitInterfaceType; @@ -111,7 +97,7 @@ private SourceOrdinaryMethodSymbol( public override ImmutableArray TypeParameters { - get { return _typeParameters; } + get { return _typeParameterInfo.TypeParameters; } } protected override (TypeWithAnnotations ReturnType, ImmutableArray Parameters, bool IsVararg, ImmutableArray DeclaredConstraintsForOverrideOrImplementation) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics) @@ -303,7 +289,7 @@ protected override void CompleteAsyncMethodChecksBetweenStartAndFinish() public override ImmutableArray> GetTypeParameterConstraintTypes() { - if (_lazyTypeParameterConstraintTypes.IsDefault) + if (_typeParameterInfo.LazyTypeParameterConstraintTypes.IsDefault) { GetTypeParameterConstraintKinds(); @@ -319,19 +305,21 @@ public override ImmutableArray> GetTypeParam syntax.TypeParameterList, syntax.ConstraintClauses, diagnostics); - if (ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintTypes, constraints)) + if (ImmutableInterlocked.InterlockedInitialize( + ref _typeParameterInfo.LazyTypeParameterConstraintTypes, + constraints)) { this.AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); } - return _lazyTypeParameterConstraintTypes; + return _typeParameterInfo.LazyTypeParameterConstraintTypes; } public override ImmutableArray GetTypeParameterConstraintKinds() { - if (_lazyTypeParameterConstraintKinds.IsDefault) + if (_typeParameterInfo.LazyTypeParameterConstraintKinds.IsDefault) { var syntax = GetSyntax(); var withTypeParametersBinder = @@ -344,10 +332,12 @@ public override ImmutableArray GetTypeParameterCons syntax.TypeParameterList, syntax.ConstraintClauses); - ImmutableInterlocked.InterlockedInitialize(ref _lazyTypeParameterConstraintKinds, constraints); + ImmutableInterlocked.InterlockedInitialize( + ref _typeParameterInfo.LazyTypeParameterConstraintKinds, + constraints); } - return _lazyTypeParameterConstraintKinds; + return _typeParameterInfo.LazyTypeParameterConstraintKinds; } public override bool IsVararg From 83aadc9e4c0a02be59282086060fd3df9840d083 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 12:35:12 -0700 Subject: [PATCH 04/11] Always create indirection --- .../Symbols/Source/SourceNamedTypeSymbol.cs | 53 +++++++++---------- .../Source/SourceOrdinaryMethodSymbol.cs | 7 ++- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 0e4ef400a1168..42a096c93331c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class TypeParameterInfo { - public readonly ImmutableArray TypeParameters; + public ImmutableArray LazyTypeParameters; /// /// A collection of type parameter constraint types, populated when @@ -38,12 +38,16 @@ internal sealed class TypeParameterInfo public static readonly TypeParameterInfo Empty = new TypeParameterInfo( ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); + public TypeParameterInfo() : this(default, default, default) + { + } + private TypeParameterInfo( ImmutableArray typeParameters, ImmutableArray> typeParameterConstraintTypes, ImmutableArray typeParameterConstraintKinds) { - TypeParameters = typeParameters; + LazyTypeParameters = typeParameters; LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; } @@ -59,9 +63,7 @@ public static TypeParameterInfo Create(ImmutableArray typeP // That is, for a generic type C this is the instance type C. internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeSymbol, IAttributeTargetSymbol { -#nullable enable - private TypeParameterInfo? _lazyTypeParameterInfo; -#nullable disable + private readonly TypeParameterInfo _typeParameterInfo; private CustomAttributesBag _lazyCustomAttributesBag; @@ -130,6 +132,10 @@ internal SourceNamedTypeSymbol(NamespaceOrTypeSymbol containingSymbol, MergedTyp // Nested types are never unified. _lazyIsExplicitDefinitionOfNoPiaLocalType = ThreeState.False; } + + _typeParameterInfo = declaration.Arity == 0 + ? TypeParameterInfo.Empty + : new TypeParameterInfo(); } protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) @@ -303,27 +309,24 @@ internal ImmutableArray GetTypeParameterConstraintTypes(int private ImmutableArray> GetTypeParameterConstraintTypes() { - var constraintTypes = _lazyTypeParameterInfo?.LazyTypeParameterConstraintTypes ?? default; - if (constraintTypes.IsDefault) + if (_typeParameterInfo.LazyTypeParameterConstraintTypes.IsDefault) { GetTypeParameterConstraintKinds(); var diagnostics = BindingDiagnosticBag.GetInstance(); - var localConstraintTypes = MakeTypeParameterConstraintTypes(diagnostics); - Debug.Assert(_lazyTypeParameterInfo != null); if (ImmutableInterlocked.InterlockedInitialize( - ref _lazyTypeParameterInfo.LazyTypeParameterConstraintTypes, - localConstraintTypes)) + ref _typeParameterInfo.LazyTypeParameterConstraintTypes, + MakeTypeParameterConstraintTypes(diagnostics))) { this.AddDeclarationDiagnostics(diagnostics); } diagnostics.Free(); - constraintTypes = _lazyTypeParameterInfo.LazyTypeParameterConstraintTypes; } - return constraintTypes; + Debug.Assert(!_typeParameterInfo.LazyTypeParameterConstraintTypes.IsDefault); + return _typeParameterInfo.LazyTypeParameterConstraintTypes; } /// @@ -337,18 +340,15 @@ internal TypeParameterConstraintKind GetTypeParameterConstraintKind(int ordinal) private ImmutableArray GetTypeParameterConstraintKinds() { - var constraintKinds = _lazyTypeParameterInfo?.LazyTypeParameterConstraintKinds ?? default; - if (constraintKinds.IsDefault) + if (_typeParameterInfo.LazyTypeParameterConstraintKinds.IsDefault) { - var localConstraintKinds = MakeTypeParameterConstraintKinds(); - Debug.Assert(_lazyTypeParameterInfo != null); - ImmutableInterlocked.InterlockedInitialize( - ref _lazyTypeParameterInfo.LazyTypeParameterConstraintKinds, localConstraintKinds); - constraintKinds = _lazyTypeParameterInfo.LazyTypeParameterConstraintKinds; + ref _typeParameterInfo.LazyTypeParameterConstraintKinds, + MakeTypeParameterConstraintKinds()); } - return constraintKinds; + Debug.Assert(!_typeParameterInfo.LazyTypeParameterConstraintKinds.IsDefault); + return _typeParameterInfo.LazyTypeParameterConstraintKinds; } private ImmutableArray> MakeTypeParameterConstraintTypes(BindingDiagnosticBag diagnostics) @@ -785,13 +785,12 @@ public override ImmutableArray TypeParameters { get { - if (_lazyTypeParameterInfo is null) + if (_typeParameterInfo.LazyTypeParameters.IsDefault) { var diagnostics = BindingDiagnosticBag.GetInstance(); - if (Interlocked.CompareExchange( - ref _lazyTypeParameterInfo, - TypeParameterInfo.Create(MakeTypeParameters(diagnostics)), - comparand: null) is null) + if (ImmutableInterlocked.InterlockedInitialize( + ref _typeParameterInfo.LazyTypeParameters, + MakeTypeParameters(diagnostics))) { AddDeclarationDiagnostics(diagnostics); } @@ -799,7 +798,7 @@ public override ImmutableArray TypeParameters diagnostics.Free(); } - return _lazyTypeParameterInfo.TypeParameters; + return _typeParameterInfo.LazyTypeParameters; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index a00c38d878231..c16bd29713ba3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -4,7 +4,6 @@ #nullable disable -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; @@ -97,7 +96,11 @@ private SourceOrdinaryMethodSymbol( public override ImmutableArray TypeParameters { - get { return _typeParameterInfo.TypeParameters; } + get + { + Debug.Assert(!_typeParameterInfo.LazyTypeParameters.IsDefault); + return _typeParameterInfo.LazyTypeParameters; + } } protected override (TypeWithAnnotations ReturnType, ImmutableArray Parameters, bool IsVararg, ImmutableArray DeclaredConstraintsForOverrideOrImplementation) MakeParametersAndBindReturnType(BindingDiagnosticBag diagnostics) From 3c7c4fa902a958c60f6dbfe7865e6ec5ffdc73d3 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 14:12:27 -0700 Subject: [PATCH 05/11] Move type --- .../Symbols/Source/SourceNamedTypeSymbol.cs | 40 -------------- .../Symbols/Source/TypeParameterInfo.cs | 55 +++++++++++++++++++ 2 files changed, 55 insertions(+), 40 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 42a096c93331c..5c468e6f148a8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -19,46 +19,6 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class TypeParameterInfo - { - public ImmutableArray LazyTypeParameters; - - /// - /// A collection of type parameter constraint types, populated when - /// constraint types for the first type parameter are requested. - /// - public ImmutableArray> LazyTypeParameterConstraintTypes; - - /// - /// A collection of type parameter constraint kinds, populated when - /// constraint kinds for the first type parameter are requested. - /// - public ImmutableArray LazyTypeParameterConstraintKinds; - - public static readonly TypeParameterInfo Empty = new TypeParameterInfo( - ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); - - public TypeParameterInfo() : this(default, default, default) - { - } - - private TypeParameterInfo( - ImmutableArray typeParameters, - ImmutableArray> typeParameterConstraintTypes, - ImmutableArray typeParameterConstraintKinds) - { - LazyTypeParameters = typeParameters; - LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; - LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; - } - - public static TypeParameterInfo Create(ImmutableArray typeParameters) - { - // If we have no type parameters (common case), we can just point at the singleton empty instance. - return typeParameters.IsEmpty ? Empty : new TypeParameterInfo(typeParameters, default, default); - } - } - // This is a type symbol associated with a type definition in source code. // That is, for a generic type C this is the instance type C. internal sealed partial class SourceNamedTypeSymbol : SourceMemberContainerTypeSymbol, IAttributeTargetSymbol diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs new file mode 100644 index 0000000000000..5f19a4b01f6a2 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + /// + /// Wrapper around type-parameter/constraints/constraint-kind info. We wrap this information (instead of inlining + /// directly within type/method symbols) as most types/methods are not generic. As such, all those non-generic + /// types can point at the singleton sentivel value, and avoid two pointers of overhead. + /// + internal sealed class TypeParameterInfo + { + public ImmutableArray LazyTypeParameters; + + /// + /// A collection of type parameter constraint types, populated when + /// constraint types for the first type parameter are requested. + /// + public ImmutableArray> LazyTypeParameterConstraintTypes; + + /// + /// A collection of type parameter constraint kinds, populated when + /// constraint kinds for the first type parameter are requested. + /// + public ImmutableArray LazyTypeParameterConstraintKinds; + + public static readonly TypeParameterInfo Empty = new TypeParameterInfo( + ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); + + public TypeParameterInfo() : this(default, default, default) + { + } + + private TypeParameterInfo( + ImmutableArray typeParameters, + ImmutableArray> typeParameterConstraintTypes, + ImmutableArray typeParameterConstraintKinds) + { + LazyTypeParameters = typeParameters; + LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; + LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; + } + + public static TypeParameterInfo Create(ImmutableArray typeParameters) + { + // If we have no type parameters (common case), we can just point at the singleton empty instance. + return typeParameters.IsEmpty ? Empty : new TypeParameterInfo(typeParameters, default, default); + } + } +} From 72929c5b0dedf20f2447f3dd141a0fbf2c6c8ba8 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Mon, 8 May 2023 14:14:36 -0700 Subject: [PATCH 06/11] Apply suggestions from code review --- .../CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 5c468e6f148a8..e3029c48fcb94 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -274,14 +274,12 @@ private ImmutableArray> GetTypeParameterCons GetTypeParameterConstraintKinds(); var diagnostics = BindingDiagnosticBag.GetInstance(); - if (ImmutableInterlocked.InterlockedInitialize( ref _typeParameterInfo.LazyTypeParameterConstraintTypes, MakeTypeParameterConstraintTypes(diagnostics))) { this.AddDeclarationDiagnostics(diagnostics); } - diagnostics.Free(); } From ae7ec307d8426ea709d7b188f6306fc0b5445854 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 17:50:44 -0700 Subject: [PATCH 07/11] speeling --- .../CSharp/Portable/Symbols/Source/TypeParameterInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs index 5f19a4b01f6a2..54ba24d9a6405 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// /// Wrapper around type-parameter/constraints/constraint-kind info. We wrap this information (instead of inlining /// directly within type/method symbols) as most types/methods are not generic. As such, all those non-generic - /// types can point at the singleton sentivel value, and avoid two pointers of overhead. + /// types can point at the singleton sentinel value, and avoid two pointers of overhead. /// internal sealed class TypeParameterInfo { From b99b69587fcd8c31bfe6dabdb7e74926243e3394 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 17:51:07 -0700 Subject: [PATCH 08/11] nrt --- .../CSharp/Portable/Symbols/Source/TypeParameterInfo.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs index 54ba24d9a6405..630de3430ab30 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CSharp.Symbols From e4e430c66e8e0d3cc843c22dfc7502aea78fc00c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 8 May 2023 17:54:20 -0700 Subject: [PATCH 09/11] Inline --- .../Source/SourceOrdinaryMethodSymbol.cs | 7 ++++++- .../Symbols/Source/TypeParameterInfo.cs | 18 ++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index c16bd29713ba3..54b7bd3bf6e73 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -79,7 +79,12 @@ private SourceOrdinaryMethodSymbol( { Debug.Assert(diagnostics.DiagnosticBag is object); - _typeParameterInfo = TypeParameterInfo.Create(MakeTypeParameters(syntax, diagnostics)); + // Compute the type parameters. If empty (the common case), directly point at the singleton to reduce the + // amount of pointers-to-arrays this type needs to store. + var typeParameters = MakeTypeParameters(syntax, diagnostics); + _typeParameterInfo = typeParameters.IsEmpty + ? TypeParameterInfo.Empty + : new TypeParameterInfo(typeParameters); _explicitInterfaceType = explicitInterfaceType; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs index 630de3430ab30..880f915e2c2a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs @@ -30,24 +30,14 @@ internal sealed class TypeParameterInfo public static readonly TypeParameterInfo Empty = new TypeParameterInfo( ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); - public TypeParameterInfo() : this(default, default, default) - { - } - - private TypeParameterInfo( - ImmutableArray typeParameters, - ImmutableArray> typeParameterConstraintTypes, - ImmutableArray typeParameterConstraintKinds) + public TypeParameterInfo( + ImmutableArray typeParameters = default, + ImmutableArray> typeParameterConstraintTypes = default, + ImmutableArray typeParameterConstraintKinds = default) { LazyTypeParameters = typeParameters; LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; } - - public static TypeParameterInfo Create(ImmutableArray typeParameters) - { - // If we have no type parameters (common case), we can just point at the singleton empty instance. - return typeParameters.IsEmpty ? Empty : new TypeParameterInfo(typeParameters, default, default); - } } } From d17689f52ff3ddfe56a549b86f6d4ff99b15e314 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 11 May 2023 08:21:15 -0700 Subject: [PATCH 10/11] Simplify --- .../Symbols/Source/SourceOrdinaryMethodSymbol.cs | 2 +- .../Portable/Symbols/Source/TypeParameterInfo.cs | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs index 54b7bd3bf6e73..b619030b5f6ec 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs @@ -84,7 +84,7 @@ private SourceOrdinaryMethodSymbol( var typeParameters = MakeTypeParameters(syntax, diagnostics); _typeParameterInfo = typeParameters.IsEmpty ? TypeParameterInfo.Empty - : new TypeParameterInfo(typeParameters); + : new TypeParameterInfo { LazyTypeParameters = typeParameters }; _explicitInterfaceType = explicitInterfaceType; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs index 880f915e2c2a4..7a91009a35962 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/TypeParameterInfo.cs @@ -27,17 +27,11 @@ internal sealed class TypeParameterInfo /// public ImmutableArray LazyTypeParameterConstraintKinds; - public static readonly TypeParameterInfo Empty = new TypeParameterInfo( - ImmutableArray.Empty, ImmutableArray>.Empty, ImmutableArray.Empty); - - public TypeParameterInfo( - ImmutableArray typeParameters = default, - ImmutableArray> typeParameterConstraintTypes = default, - ImmutableArray typeParameterConstraintKinds = default) + public static readonly TypeParameterInfo Empty = new TypeParameterInfo { - LazyTypeParameters = typeParameters; - LazyTypeParameterConstraintTypes = typeParameterConstraintTypes; - LazyTypeParameterConstraintKinds = typeParameterConstraintKinds; - } + LazyTypeParameters = ImmutableArray.Empty, + LazyTypeParameterConstraintTypes = ImmutableArray>.Empty, + LazyTypeParameterConstraintKinds = ImmutableArray.Empty, + }; } } From 7223446957e167af717d41018117bb8f423ac5a9 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Thu, 11 May 2023 08:24:03 -0700 Subject: [PATCH 11/11] Change to abstract override --- .../Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs index 58fe98c0a9c90..2eaef04464ab7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbolBase.cs @@ -166,6 +166,8 @@ private void CompleteAsyncMethodChecks(BindingDiagnosticBag diagnosticsOpt, Canc protected abstract void CompleteAsyncMethodChecksBetweenStartAndFinish(); + public abstract override ImmutableArray TypeParameters { get; } + public abstract override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)); public override string Name