Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of source generator #1804

Merged
merged 9 commits into from
Oct 9, 2024
1 change: 1 addition & 0 deletions nuget/Microsoft.Windows.CsWinRT.targets
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<CompilerVisibleProperty Include="CsWinRTCcwLookupTableGeneratorEnabled" />
<CompilerVisibleProperty Include="CsWinRTMergeReferencedActivationFactories" />
<CompilerVisibleProperty Include="CsWinRTAotWarningLevel" />
<CompilerVisibleProperty Include="CsWinRTEmbedded" />
</ItemGroup>

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Embedded.targets" Condition="'$(CsWinRTEmbedded)' == 'true'"/>
Expand Down
106 changes: 66 additions & 40 deletions src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,28 @@ public class WinRTAotSourceGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var properties = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) =>
(provider.IsCsWinRTAotOptimizerEnabled(), provider.IsCsWinRTComponent(), provider.IsCsWinRTCcwLookupTableGeneratorEnabled()));
var analyzerConfigProperties = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => (
provider.IsCsWinRTAotOptimizerEnabled(),
provider.IsCsWinRTComponent(),
provider.IsCsWinRTCcwLookupTableGeneratorEnabled(),
provider.IsCsWinRTAotOptimizerEnabledForBuiltInInterfaces(),
provider.IsCsWinRTEmbeddedSupport())
);

var properties = context.CompilationProvider.Combine(analyzerConfigProperties).
Select(static ((Compilation compilation, (bool isCsWinRTAotOptimizerEnabled, bool isCsWinRTComponent, bool, bool isCsWinRTAotOptimizerEnabledForBuiltInInterfaces, bool isCsWinRTEmbeddedSupport) properties) value, CancellationToken ct) =>
// Enable the optimizer if the optimizer property is set and we would have a WinRT.Runtime reference.
// There are a couple scenarios where we might not detect a WinRT.Runtime reference which we explicitly
// check for such as component support where the generator introduces the reference and embedded support.
// We will allow for an override for this by detecting whether CsWinRTAotWarningLevel is set to 2 which
// indicates the component cares about optimization for built-in interfaces.
(value.properties.isCsWinRTAotOptimizerEnabled &&
(value.properties.isCsWinRTComponent ||
value.properties.isCsWinRTAotOptimizerEnabledForBuiltInInterfaces ||
value.properties.isCsWinRTEmbeddedSupport ||
GeneratorHelper.HasWinRTRuntimeReference(value.compilation, ct)),
value.properties.isCsWinRTComponent,
value.properties.Item3));
Sergio0694 marked this conversation as resolved.
Show resolved Hide resolved

var assemblyName = context.CompilationProvider.Select(static (compilation, _) => GeneratorHelper.EscapeTypeNameForIdentifier(compilation.AssemblyName));

Expand All @@ -32,7 +52,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
static (n, _) => NeedVtableAttribute(n),
static (n, _) => n)
.Combine(typeMapper)
.Select((t, _) => GetVtableAttributeToAdd(t.Left, t.Right, false))
.Combine(properties)
.Select(static (((GeneratorSyntaxContext generatorSyntaxContext, TypeMapper typeMapper) left, (bool isCsWinRTAotOptimizerEnabled, bool, bool isCsWinRTCcwLookupTableGeneratorEnabled) properties) value, CancellationToken _) =>
value.properties.isCsWinRTAotOptimizerEnabled ?
GetVtableAttributeToAdd(value.left.generatorSyntaxContext, value.left.typeMapper, false, value.properties.isCsWinRTCcwLookupTableGeneratorEnabled) : default)
.Where(static vtableAttribute => vtableAttribute != default);

var vtableAttributesToAdd = vtablesToAddFromClassTypes.Select(static (vtable, _) => vtable.Item1);
Expand All @@ -46,37 +69,37 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
static (n, _) => IsComponentType(n),
static (n, _) => n)
.Combine(typeMapper)
.Select((t, _) => GetVtableAttributeToAdd(t.Left, t.Right, true))
.Where(static vtableAttribute => vtableAttribute != default).Collect()
.Combine(properties)
// Get component types if only authoring scenario
.SelectMany(static ((ImmutableArray<(VtableAttribute vtableAttribute, EquatableArray<VtableAttribute> adapterTypes)> classTypes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
value.properties.isCsWinRTComponent ? value.classTypes : ImmutableArray<(VtableAttribute, EquatableArray<VtableAttribute>)>.Empty);
// Get component types if only authoring scenario and if aot optimizer enabled.
.Select(static (((GeneratorSyntaxContext generatorSyntaxContext, TypeMapper typeMapper) left, (bool isCsWinRTAotOptimizerEnabled, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
value.properties.isCsWinRTAotOptimizerEnabled && value.properties.isCsWinRTComponent ?
GetVtableAttributeToAdd(value.left.generatorSyntaxContext, value.left.typeMapper, true, true) : default)
.Where(static vtableAttribute => vtableAttribute != default);

var instantiatedTypesToAddOnLookupTable = context.SyntaxProvider.CreateSyntaxProvider(
static (n, _) => NeedVtableOnLookupTable(n),
static (n, _) => n)
.Combine(typeMapper)
.Select((t, _) => GetVtableAttributesToAddOnLookupTable(t.Left, t.Right))
.Combine(properties)
// Get component types if only authoring scenario
.Select(static (((EquatableArray<VtableAttribute> lookupTable, EquatableArray<VtableAttribute> componentLookupTable) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
value.properties.isCsWinRTComponent ? value.vtableAttributes.componentLookupTable : value.vtableAttributes.lookupTable)
.Select(static (((GeneratorSyntaxContext generatorSyntaxContext, TypeMapper typeMapper) left, (bool isCsWinRTAotOptimizerEnabled, bool isCsWinRTComponent, bool isCsWinRTCcwLookupTableGeneratorEnabled) properties) value,
CancellationToken _) =>
value.properties.isCsWinRTAotOptimizerEnabled && value.properties.isCsWinRTCcwLookupTableGeneratorEnabled ?
GetVtableAttributesToAddOnLookupTable(value.left.generatorSyntaxContext, value.left.typeMapper, value.properties.isCsWinRTComponent) :
(EquatableArray<VtableAttribute>)ImmutableArray<VtableAttribute>.Empty)
.SelectMany(static (vtable, _) => vtable)
.Where(static vtableAttribute => vtableAttribute != null);

var instantiatedTaskAdapters = context.SyntaxProvider.CreateSyntaxProvider(
static (n, _) => IsAsyncOperationMethodCall(n),
static (n, _) => n)
.Combine(typeMapper)
.Select((data, ct) => GetVtableAttributesForTaskAdapters(data.Left, data.Right))
.Where(static vtableAttribute => vtableAttribute != default)
.Combine(properties)
// Get component types if only authoring scenario
.Select(static (((VtableAttribute vtableAttribute, VtableAttribute componentVtableAttribute) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
value.properties.isCsWinRTComponent ? value.vtableAttributes.componentVtableAttribute : value.vtableAttributes.vtableAttribute)
.Where(static vtableAttribute => vtableAttribute != default)
.Collect();
.Select(static (((GeneratorSyntaxContext generatorSyntaxContext, TypeMapper typeMapper) left, (bool isCsWinRTAotOptimizerEnabled, bool isCsWinRTComponent, bool isCsWinRTCcwLookupTableGeneratorEnabled) properties) value,
CancellationToken _) =>
value.properties.isCsWinRTAotOptimizerEnabled && value.properties.isCsWinRTCcwLookupTableGeneratorEnabled ?
GetVtableAttributesForTaskAdapters(value.left.generatorSyntaxContext, value.left.typeMapper, value.properties.isCsWinRTComponent) : default)
.Where(static vtableAttribute => vtableAttribute != default)
.Collect();

// Merge both adapter types list and instantiated types list
var vtablesToAddOnLookupTable =
Expand Down Expand Up @@ -109,7 +132,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
var bindableCustomPropertyAttributes = context.SyntaxProvider.CreateSyntaxProvider(
static (n, _) => NeedCustomPropertyImplementation(n),
static (n, _) => n)
.Select((data, _) => GetBindableCustomProperties(data))
.Combine(properties)
.Select(static ((GeneratorSyntaxContext generatorSyntaxContext, (bool isCsWinRTAotOptimizerEnabled, bool, bool) properties) value, CancellationToken _) =>
value.properties.isCsWinRTAotOptimizerEnabled ? GetBindableCustomProperties(value.generatorSyntaxContext) : default)
.Where(static bindableCustomProperties => bindableCustomProperties != default)
.Collect()
.Combine(properties);
Expand Down Expand Up @@ -147,7 +172,8 @@ private static bool NeedCustomPropertyImplementation(SyntaxNode node)
private static (VtableAttribute, EquatableArray<VtableAttribute>) GetVtableAttributeToAdd(
GeneratorSyntaxContext context,
TypeMapper typeMapper,
bool checkForComponentTypes)
bool checkForComponentTypes,
bool isCsWinRTCcwLookupTableGeneratorEnabled)
{
var isWinRTTypeFunc = checkForComponentTypes ?
GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation) :
Expand All @@ -159,7 +185,10 @@ private static (VtableAttribute, EquatableArray<VtableAttribute>) GetVtableAttri
HashSet<VtableAttribute> vtableAttributesForLookupTable = [];
// Add any adapter types which may be needed if certain functions
// from some known interfaces are called.
AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, isWinRTTypeFunc, typeMapper, vtableAttributesForLookupTable);
if (isCsWinRTCcwLookupTableGeneratorEnabled)
{
AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, isWinRTTypeFunc, typeMapper, vtableAttributesForLookupTable);
}
return (vtableAttribute, vtableAttributesForLookupTable.ToImmutableArray());
}

Expand Down Expand Up @@ -204,7 +233,7 @@ static bool IsAsyncOperationMethodCall(SyntaxNode node)
// We do this both assuming this is not an authoring component and is an authoring
// component as we don't know that at this stage and the results can vary based on that.
// We will choose the right one later when we can combine with properties.
private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context, TypeMapper typeMapper)
private static VtableAttribute GetVtableAttributesForTaskAdapters(GeneratorSyntaxContext context, TypeMapper typeMapper, bool isCsWinRTComponent)
{
// Generic instantiation of task adapters make of use of unsafe.
// This will be caught by GetVtableAttributeToAdd, but catching it early here too.
Expand All @@ -222,8 +251,12 @@ private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdap
if (adpaterType is not null)
{
var constructedAdapterType = adpaterType.Construct([.. symbol.TypeArguments]);
return (GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTType, typeMapper, context.SemanticModel.Compilation, false),
GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation), typeMapper, context.SemanticModel.Compilation, false));
return GetVtableAttributeToAdd(
constructedAdapterType,
!isCsWinRTComponent ? GeneratorHelper.IsWinRTType : GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation),
typeMapper,
context.SemanticModel.Compilation,
false);
}
}
}
Expand Down Expand Up @@ -1030,23 +1063,16 @@ node is PropertyDeclarationSyntax ||
node is ReturnStatementSyntax;
}

private static (EquatableArray<VtableAttribute>, EquatableArray<VtableAttribute>) GetVtableAttributesToAddOnLookupTable(
private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupTable(
GeneratorSyntaxContext context,
TypeMapper typeMapper)
TypeMapper typeMapper,
bool isCsWinRTComponent)
{
// Get the lookup table as if we are running in an authoring component scenario and as if we are not
// and then use the properties later on when we have access to it to check if we are to choose the right one.
// Otherwise we will end up generating lookup tables which don't have vtable entries for authoring types.
return (GetVtableAttributesToAddOnLookupTable(
context,
typeMapper,
GeneratorHelper.IsWinRTType,
GeneratorHelper.IsWinRTClass(context.SemanticModel.Compilation)),
GetVtableAttributesToAddOnLookupTable(
context,
typeMapper,
GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation),
GeneratorHelper.IsWinRTClass(context.SemanticModel.Compilation)));
return GetVtableAttributesToAddOnLookupTable(
context,
typeMapper,
!isCsWinRTComponent ? GeneratorHelper.IsWinRTType : GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation),
GeneratorHelper.IsWinRTClass(context.SemanticModel.Compilation));
}

private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupTable(
Expand Down
22 changes: 22 additions & 0 deletions src/Authoring/WinRT.SourceGenerator/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
manodasanW marked this conversation as resolved.
Show resolved Hide resolved
manodasanW marked this conversation as resolved.
Show resolved Hide resolved

namespace Generator
{
Expand Down Expand Up @@ -103,6 +104,16 @@ public static bool IsCsWinRTComponent(this AnalyzerConfigOptionsProvider provide
return false;
}

public static bool IsCsWinRTEmbeddedSupport(this AnalyzerConfigOptionsProvider provider)
{
if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTEmbedded", out var isCsWinRTEmbeddedStr))
{
return bool.TryParse(isCsWinRTEmbeddedStr, out var isCsWinRTEmbedded) && isCsWinRTEmbedded;
}

return false;
}

public static bool IsCsWinRTAotOptimizerEnabled(this AnalyzerConfigOptionsProvider provider)
{
if (provider.GlobalOptions.TryGetValue("build_property.CsWinRTAotOptimizerEnabled", out var isCsWinRTAotOptimizerEnabledStr))
Expand Down Expand Up @@ -174,6 +185,11 @@ public static int GetCsWinRTAotWarningLevel(this AnalyzerConfigOptionsProvider p
return 0;
}

public static bool IsCsWinRTAotOptimizerEnabledForBuiltInInterfaces(this AnalyzerConfigOptionsProvider provider)
{
return GetCsWinRTAotWarningLevel(provider) == 2;
}

public static bool ShouldGenerateWinMDOnly(this GeneratorExecutionContext context)
{
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTGenerateWinMDOnly", out var CsWinRTGenerateWinMDOnlyStr))
Expand Down Expand Up @@ -1122,5 +1138,11 @@ public static string GetTaskAdapterIfAsyncMethod(IMethodSymbol symbol)

return null;
}

public static bool HasWinRTRuntimeReference(Compilation compilation, CancellationToken ct)
{
return compilation.GetUsedAssemblyReferences(ct).Any(reference =>
string.Equals(compilation.GetAssemblyOrModuleSymbol(reference)?.Name, "WinRT.Runtime", StringComparison.OrdinalIgnoreCase));
}
}
}
3 changes: 2 additions & 1 deletion src/Authoring/WinRT.SourceGenerator/WinRTAotCodeFixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public override void Initialize(AnalysisContext context)
var typeMapper = new TypeMapper(context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTUseWindowsUIXamlProjections());
var csWinRTAotWarningLevel = context.Options.AnalyzerConfigOptionsProvider.GetCsWinRTAotWarningLevel();
var allowUnsafe = GeneratorHelper.AllowUnsafe(context.Compilation);
var isCsWinRTCcwLookupTableGeneratorEnabled = context.Options.AnalyzerConfigOptionsProvider.IsCsWinRTCcwLookupTableGeneratorEnabled();

context.RegisterSymbolAction(context =>
{
Expand Down Expand Up @@ -127,7 +128,7 @@ public override void Initialize(AnalysisContext context)
}
}, SymbolKind.NamedType);

if (!allowUnsafe)
if (!allowUnsafe && isCsWinRTCcwLookupTableGeneratorEnabled)
{
context.RegisterSyntaxNodeAction(context =>
{
Expand Down
Loading