Skip to content

Commit

Permalink
Reduce allocations in TypeSymbolExtensions.IsAtLeastAsVisibleAs (#75401)
Browse files Browse the repository at this point in the history
* Reduce allocations in TypeSymbolExtensions.IsAtLeastAsVisibleAs

This method showed up in multiple profiles as about 0.6% of allocations in the Roslyn CA process in the csharp editing speedometer test.

This simply avoids those allocations by switching to a static lambda using the arg data to pass in a pooled object. Note that the arg passed into VisitType needed to be a class to allow the ref parameter to change it's value.
  • Loading branch information
ToddGrun authored Oct 8, 2024
1 parent 1b735c7 commit fccf517
Showing 1 changed file with 29 additions and 5 deletions.
34 changes: 29 additions & 5 deletions src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal static partial class TypeSymbolExtensions
{
private sealed class VisitTypeData
{
public Symbol? Symbol;
public CompoundUseSiteInfo<AssemblySymbol> UseSiteInfo;
}

private static readonly ObjectPool<VisitTypeData> s_visitTypeDataPool
= new ObjectPool<VisitTypeData>(() => new VisitTypeData(), size: 4);

public static bool ImplementsInterface(this TypeSymbol subType, TypeSymbol superInterface, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
foreach (NamedTypeSymbol @interface in subType.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteInfo))
Expand Down Expand Up @@ -663,11 +672,26 @@ public static SpecialType GetSpecialTypeSafe(this TypeSymbol? type)

public static bool IsAtLeastAsVisibleAs(this TypeSymbol type, Symbol sym, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
CompoundUseSiteInfo<AssemblySymbol> localUseSiteInfo = useSiteInfo;
var result = type.VisitType((type1, symbol, unused) => IsTypeLessVisibleThan(type1, symbol, ref localUseSiteInfo), sym,
canDigThroughNullable: true); // System.Nullable is public
useSiteInfo = localUseSiteInfo;
return result is null;
var visitTypeData = s_visitTypeDataPool.Allocate();

try
{
visitTypeData.UseSiteInfo = useSiteInfo;
visitTypeData.Symbol = sym;

var result = type.VisitType(static (type1, arg, unused) => IsTypeLessVisibleThan(type1, arg.Symbol!, ref arg.UseSiteInfo),
arg: visitTypeData,
canDigThroughNullable: true); // System.Nullable is public

useSiteInfo = visitTypeData.UseSiteInfo;
return result is null;
}
finally
{
visitTypeData.UseSiteInfo = default;
visitTypeData.Symbol = null;
s_visitTypeDataPool.Free(visitTypeData);
}
}

private static bool IsTypeLessVisibleThan(TypeSymbol type, Symbol sym, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
Expand Down

0 comments on commit fccf517

Please sign in to comment.