Skip to content

Commit 7602014

Browse files
authored
Fix marshaling in AOT source generator (#1628)
* Fix bool marshaling and array marshaling * Fix lookup table generation to properly handle authoring scenarios * Improve comment
1 parent 6257088 commit 7602014

File tree

4 files changed

+130
-63
lines changed

4 files changed

+130
-63
lines changed

src/Authoring/WinRT.SourceGenerator/AotOptimizer.cs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
2424

2525
var vtablesToAddFromClassTypes = context.SyntaxProvider.CreateSyntaxProvider(
2626
static (n, _) => NeedVtableAttribute(n),
27-
static (n, _) => GetVtableAttributeToAdd(n)
27+
static (n, _) => GetVtableAttributeToAdd(n, false)
2828
).Where(static vtableAttribute => vtableAttribute != default);
2929

3030
var vtableAttributesToAdd = vtablesToAddFromClassTypes.Select(static (vtable, _) => vtable.Item1);
@@ -36,7 +36,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
3636
// that will already be generated by the component generator.
3737
var vtablesFromComponentTypes = context.SyntaxProvider.CreateSyntaxProvider(
3838
static (n, _) => IsComponentType(n),
39-
static (n, _) => GetVtableAttributeToAdd(n)
39+
static (n, _) => GetVtableAttributeToAdd(n, true)
4040
).Where(static vtableAttribute => vtableAttribute != default).Collect().Combine(properties).
4141
// Get component types if only authoring scenario
4242
SelectMany(static ((ImmutableArray<(VtableAttribute vtableAttribute, EquatableArray<VtableAttribute> adapterTypes)> classTypes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
@@ -45,7 +45,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
4545
var instantiatedTypesToAddOnLookupTable = context.SyntaxProvider.CreateSyntaxProvider(
4646
static (n, _) => NeedVtableOnLookupTable(n),
4747
static (n, _) => GetVtableAttributesToAddOnLookupTable(n)
48-
).SelectMany(static (vtable, _) => vtable).
48+
).Combine(properties)
49+
// Get component types if only authoring scenario
50+
.Select(static (((EquatableArray<VtableAttribute> lookupTable, EquatableArray<VtableAttribute> componentLookupTable) vtableAttributes, (bool, bool isCsWinRTComponent, bool) properties) value, CancellationToken _) =>
51+
value.properties.isCsWinRTComponent ? value.vtableAttributes.componentLookupTable : value.vtableAttributes.lookupTable)
52+
.SelectMany(static (vtable, _) => vtable).
4953
Where(static vtableAttribute => vtableAttribute != null);
5054

5155
var instantiatedTaskAdapters = context.SyntaxProvider.CreateSyntaxProvider(
@@ -108,16 +112,19 @@ private static bool IsComponentType(SyntaxNode node)
108112
!GeneratorHelper.IsWinRTType(declaration); // Making sure it isn't an RCW we are projecting.
109113
}
110114

111-
private static (VtableAttribute, EquatableArray<VtableAttribute>) GetVtableAttributeToAdd(GeneratorSyntaxContext context)
115+
private static (VtableAttribute, EquatableArray<VtableAttribute>) GetVtableAttributeToAdd(GeneratorSyntaxContext context, bool checkForComponentTypes)
112116
{
117+
var isWinRTTypeFunc = checkForComponentTypes ?
118+
GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation) :
119+
GeneratorHelper.IsWinRTType;
113120
var symbol = context.SemanticModel.GetDeclaredSymbol(context.Node as ClassDeclarationSyntax);
114-
var vtableAttribute = GetVtableAttributeToAdd(symbol, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false);
121+
var vtableAttribute = GetVtableAttributeToAdd(symbol, isWinRTTypeFunc, context.SemanticModel.Compilation, false);
115122
if (vtableAttribute != default)
116123
{
117124
HashSet<VtableAttribute> vtableAttributesForLookupTable = [];
118125
// Add any adapter types which may be needed if certain functions
119126
// from some known interfaces are called.
120-
AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, GeneratorHelper.IsWinRTType, vtableAttributesForLookupTable);
127+
AddVtableAdapterTypeForKnownInterface(symbol, context.SemanticModel.Compilation, isWinRTTypeFunc, vtableAttributesForLookupTable);
121128
return (vtableAttribute, vtableAttributesForLookupTable.ToImmutableArray());
122129
}
123130

@@ -194,19 +201,13 @@ private static (VtableAttribute, VtableAttribute) GetVtableAttributesForTaskAdap
194201
{
195202
var constructedAdapterType = adpaterType.Construct([.. symbol.TypeArguments]);
196203
return (GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false),
197-
GetVtableAttributeToAdd(constructedAdapterType, IsWinRTTypeWithPotentialAuthoringComponentTypes, context.SemanticModel.Compilation, false));
204+
GetVtableAttributeToAdd(constructedAdapterType, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation), context.SemanticModel.Compilation, false));
198205
}
199206
}
200207
}
201208
}
202209

203210
return default;
204-
205-
bool IsWinRTTypeWithPotentialAuthoringComponentTypes(ISymbol type)
206-
{
207-
var winrtTypeAttribute = context.SemanticModel.Compilation.GetTypeByMetadataName("WinRT.WindowsRuntimeTypeAttribute");
208-
return GeneratorHelper.IsWinRTType(type, winrtTypeAttribute, true, context.SemanticModel.Compilation.Assembly);
209-
}
210211
}
211212

212213
private static string ToFullyQualifiedString(ISymbol symbol)
@@ -836,7 +837,18 @@ node is VariableDeclarationSyntax ||
836837
node is ReturnStatementSyntax;
837838
}
838839

839-
private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupTable(GeneratorSyntaxContext context)
840+
private static (EquatableArray<VtableAttribute>, EquatableArray<VtableAttribute>) GetVtableAttributesToAddOnLookupTable(GeneratorSyntaxContext context)
841+
{
842+
// Get the lookup table as if we are running in an authoring component scenario and as if we are not
843+
// and then use the properties later on when we have access to it to check if we are to choose the right one.
844+
// Otherwise we will end up generating lookup tables which don't have vtable entries for authoring types.
845+
return (GetVtableAttributesToAddOnLookupTable(context, GeneratorHelper.IsWinRTType),
846+
GetVtableAttributesToAddOnLookupTable(context, GeneratorHelper.IsWinRTTypeWithPotentialAuthoringComponentTypesFunc(context.SemanticModel.Compilation)));
847+
}
848+
849+
private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupTable(
850+
GeneratorSyntaxContext context,
851+
Func<ISymbol, bool> isWinRTType)
840852
{
841853
HashSet<ITypeSymbol> visitedTypes = new(SymbolEqualityComparer.Default);
842854
HashSet<VtableAttribute> vtableAttributes = new();
@@ -850,7 +862,7 @@ private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupT
850862
// and end up calling a projection function (i.e. ones generated by XAML compiler)
851863
// In theory, another library can also be called which can call a projected function
852864
// but not handling those scenarios for now.
853-
(GeneratorHelper.IsWinRTType(methodSymbol.ContainingSymbol) ||
865+
(isWinRTType(methodSymbol.ContainingSymbol) ||
854866
SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly)))
855867
{
856868
// Get the concrete types directly from the argument rather than
@@ -879,13 +891,13 @@ private static EquatableArray<VtableAttribute> GetVtableAttributesToAddOnLookupT
879891
{
880892
var leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol;
881893
if (leftSymbol is IPropertySymbol propertySymbol &&
882-
(GeneratorHelper.IsWinRTType(propertySymbol.ContainingSymbol) ||
894+
(isWinRTType(propertySymbol.ContainingSymbol) ||
883895
SymbolEqualityComparer.Default.Equals(propertySymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly)))
884896
{
885897
AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), propertySymbol.Type);
886898
}
887899
else if (leftSymbol is IFieldSymbol fieldSymbol &&
888-
(GeneratorHelper.IsWinRTType(fieldSymbol.ContainingSymbol) ||
900+
(isWinRTType(fieldSymbol.ContainingSymbol) ||
889901
SymbolEqualityComparer.Default.Equals(fieldSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly)))
890902
{
891903
AddVtableAttributesForType(context.SemanticModel.GetTypeInfo(assignment.Right), fieldSymbol.Type);
@@ -953,14 +965,14 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType
953965
}
954966
visitedTypes.Add(arrayType);
955967

956-
var vtableAtribute = GetVtableAttributeToAdd(arrayType, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false);
968+
var vtableAtribute = GetVtableAttributeToAdd(arrayType, isWinRTType, context.SemanticModel.Compilation, false);
957969
if (vtableAtribute != default)
958970
{
959971
vtableAttributes.Add(vtableAtribute);
960972
}
961973

962974
// Also add the enumerator type to the lookup table as the native caller can call it.
963-
AddEnumeratorAdapterForType(arrayType.ElementType, context.SemanticModel.Compilation, GeneratorHelper.IsWinRTType, vtableAttributes);
975+
AddEnumeratorAdapterForType(arrayType.ElementType, context.SemanticModel.Compilation, isWinRTType, vtableAttributes);
964976
}
965977
}
966978
else if (instantiatedType.Type is not null || instantiatedType.ConvertedType is not null)
@@ -982,11 +994,11 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType
982994
// information is available.
983995
if (instantiatedTypeSymbol.TypeKind == TypeKind.Delegate &&
984996
instantiatedTypeSymbol.MetadataName.Contains("`") &&
985-
GeneratorHelper.IsWinRTType(instantiatedTypeSymbol) &&
997+
isWinRTType(instantiatedTypeSymbol) &&
986998
convertedToTypeSymbol.SpecialType == SpecialType.System_Object)
987999
{
9881000
var argumentClassNamedTypeSymbol = instantiatedTypeSymbol as INamedTypeSymbol;
989-
vtableAttributes.Add(GetVtableAttributeToAdd(instantiatedTypeSymbol, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false));
1001+
vtableAttributes.Add(GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, context.SemanticModel.Compilation, false));
9901002
}
9911003

9921004
// This handles the case where the source generator wasn't able to run
@@ -998,21 +1010,21 @@ void AddVtableAttributesForType(Microsoft.CodeAnalysis.TypeInfo instantiatedType
9981010
// library which happened to not run the AOT optimizer. So as a best effort,
9991011
// we handle it here.
10001012
if (instantiatedTypeSymbol.TypeKind == TypeKind.Class &&
1001-
(instantiatedTypeSymbol.MetadataName.Contains("`") || !GeneratorHelper.IsWinRTType(instantiatedTypeSymbol)) &&
1013+
(instantiatedTypeSymbol.MetadataName.Contains("`") || !isWinRTType(instantiatedTypeSymbol)) &&
10021014
!GeneratorHelper.HasWinRTExposedTypeAttribute(instantiatedTypeSymbol) &&
10031015
// If the type is defined in the same assembly as what the source generator is running on,
10041016
// we let the WinRTExposedType attribute generator handle it.
10051017
!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol.ContainingAssembly, context.SemanticModel.Compilation.Assembly) &&
10061018
// Make sure the type we are passing is being boxed or cast to another interface.
10071019
!SymbolEqualityComparer.Default.Equals(instantiatedTypeSymbol, convertedToTypeSymbol))
10081020
{
1009-
var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, GeneratorHelper.IsWinRTType, context.SemanticModel.Compilation, false);
1021+
var vtableAtribute = GetVtableAttributeToAdd(instantiatedTypeSymbol, isWinRTType, context.SemanticModel.Compilation, false);
10101022
if (vtableAtribute != default)
10111023
{
10121024
vtableAttributes.Add(vtableAtribute);
10131025
}
10141026

1015-
AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, GeneratorHelper.IsWinRTType, vtableAttributes);
1027+
AddVtableAdapterTypeForKnownInterface(instantiatedTypeSymbol, context.SemanticModel.Compilation, isWinRTType, vtableAttributes);
10161028
}
10171029
}
10181030
}

0 commit comments

Comments
 (0)