Skip to content

Commit 46137bd

Browse files
authored
Improve type caching in the XAML compiler (#21408)
* Update XamlX * XAML compiler: cache AvaloniaXamlIlWellKnownTypes per compilation * XAML compiler: use more well known types * XAML compiler: replace IXamlType.FullName usages
1 parent a678adf commit 46137bd

22 files changed

Lines changed: 213 additions & 208 deletions

src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ bool CompileGroup(IResourceGroup group)
458458
.Methods.First(m => m.Name == document.TypeBuilderProvider.PopulateMethod.Name);
459459

460460
var designLoaderFieldType = typeSystem
461-
.GetType("System.Action`1")
462-
.MakeGenericType(typeSystem.GetType("System.Object"));
461+
.WellKnownTypes.GetActionOfT(1)
462+
.MakeGenericType(typeSystem.WellKnownTypes.Object);
463463

464464
var designLoaderFieldTypeReference = (GenericInstanceType)typeSystem.GetTypeReference(designLoaderFieldType);
465465
designLoaderFieldTypeReference.GenericArguments[0] =

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompilerConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
12
using XamlX.Transform;
23
using XamlX.TypeSystem;
34

@@ -28,6 +29,7 @@ public AvaloniaXamlIlCompilerConfiguration(
2829
AddExtra(ClrPropertyEmitter);
2930
AddExtra(AccessorFactoryEmitter);
3031
AddExtra(TrampolineBuilder);
32+
AddExtra(new AvaloniaXamlIlWellKnownTypes(TypeSystem));
3133
}
3234
}
3335
}

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,16 @@ public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings<IXaml
7070
};
7171
rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv);
7272

73+
var nameScopeType = typeSystem.GetType("Avalonia.Controls.INameScope");
74+
var eagerParentStackProviderInterfaceType = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlEagerParentStackProvider");
75+
7376
var emit = new XamlLanguageEmitMappings<IXamlILEmitter, XamlILNodeEmitResult>
7477
{
7578
ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.EmitProvideValueTarget,
7679
ContextTypeBuilderCallback = definition =>
7780
{
78-
EmitNameScopeField(rv, typeSystem, definition);
79-
EmitEagerParentStackProvider(rv, typeSystem, definition, runtimeHelpers);
81+
EmitNameScopeField(rv, typeSystem, definition, nameScopeType);
82+
EmitEagerParentStackProvider(rv, typeSystem, definition, runtimeHelpers, eagerParentStackProviderInterfaceType);
8083
}
8184
};
8285
return (rv, emit);
@@ -88,17 +91,17 @@ public static (XamlLanguageTypeMappings language, XamlLanguageEmitMappings<IXaml
8891
private static void EmitNameScopeField(
8992
XamlLanguageTypeMappings mappings,
9093
IXamlTypeSystem typeSystem,
91-
IXamlILContextDefinition<IXamlILEmitter> definition)
94+
IXamlILContextDefinition<IXamlILEmitter> definition,
95+
IXamlType nameScopeType)
9296
{
93-
var nameScopeType = typeSystem.GetType("Avalonia.Controls.INameScope");
9497
var field = definition.TypeBuilder.DefineField(nameScopeType,
9598
ContextNameScopeFieldName, XamlVisibility.Public, false);
9699
definition.ConstructorBuilder.Generator
97100
.Ldarg_0()
98101
.Ldarg(1)
99102
.Ldtype(nameScopeType)
100103
.EmitCall(mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature("GetService",
101-
typeSystem.GetType("System.Object"), typeSystem.GetType("System.Type"))))
104+
typeSystem.WellKnownTypes.Object, typeSystem.WellKnownTypes.Type)))
102105
.Stfld(field);
103106
}
104107

@@ -107,10 +110,9 @@ private static void EmitEagerParentStackProvider(
107110
XamlLanguageTypeMappings mappings,
108111
IXamlTypeSystem typeSystem,
109112
IXamlILContextDefinition<IXamlILEmitter> definition,
110-
IXamlType runtimeHelpers)
113+
IXamlType runtimeHelpers,
114+
IXamlType interfaceType)
111115
{
112-
var interfaceType = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlEagerParentStackProvider");
113-
114116
definition.TypeBuilder.AddInterfaceImplementation(interfaceType);
115117

116118
// IReadOnlyList<object> DirectParentsStack => (IReadOnlyList<object>)ParentsStack;
@@ -122,8 +124,8 @@ private static void EmitEagerParentStackProvider(
122124

123125
var serviceProviderGetServiceMethod = mappings.ServiceProvider.GetMethod(new FindMethodMethodSignature(
124126
"GetService",
125-
typeSystem.GetType("System.Object"),
126-
typeSystem.GetType("System.Type")));
127+
typeSystem.WellKnownTypes.Object,
128+
typeSystem.WellKnownTypes.Type));
127129

128130
var asEagerParentStackProviderMethod = runtimeHelpers.GetMethod(new FindMethodMethodSignature(
129131
"AsEagerParentStackProvider",
@@ -184,12 +186,11 @@ void AddType(IXamlType type, IXamlType conv)
184186
AddType(typeSystem.GetType("Avalonia.Media.IImage"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
185187
AddType(typeSystem.GetType("Avalonia.Media.Imaging.Bitmap"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
186188
AddType(typeSystem.GetType("Avalonia.Media.IImageBrushSource"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.BitmapTypeConverter"));
187-
var ilist = typeSystem.GetType("System.Collections.Generic.IList`1");
188-
AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")),
189+
AddType(typeSystem.WellKnownTypes.IListOfT.MakeGenericType(typeSystem.GetType("Avalonia.Point")),
189190
typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter"));
190191
AddType(typeSystem.GetType("Avalonia.Controls.WindowIcon"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.IconTypeConverter"));
191192
AddType(typeSystem.GetType("System.Globalization.CultureInfo"), typeSystem.GetType( "System.ComponentModel.CultureInfoConverter"));
192-
AddType(typeSystem.GetType("System.Uri"), typeSystem.GetType( "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter"));
193+
AddType(typeSystem.WellKnownTypes.Uri, typeSystem.GetType( "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter"));
193194
AddType(typeSystem.GetType("System.TimeSpan"), typeSystem.GetType( "Avalonia.Markup.Xaml.Converters.TimeSpanTypeConverter"));
194195
AddType(typeSystem.GetType("Avalonia.Media.FontFamily"), typeSystem.GetType("Avalonia.Markup.Xaml.Converters.FontFamilyTypeConverter"));
195196
_avaloniaList = typeSystem.GetType("Avalonia.Collections.AvaloniaList`1");
@@ -270,7 +271,7 @@ public static bool CustomValueConverter(
270271
return true;
271272
}
272273

273-
if (type.FullName == "Avalonia.AvaloniaProperty")
274+
if (type.Is("Avalonia", "AvaloniaProperty"))
274275
{
275276
var attrType = context.GetAvaloniaTypes().InheritDataTypeFromAttribute;
276277
var scopeKind = customAttributes?

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ bool ReturnOnParseError(string title, out IXamlAstValueNode? result)
3939
return false;
4040
}
4141

42-
if (type.FullName == "System.TimeSpan")
42+
if (type.Is("System", "TimeSpan"))
4343
{
4444
var tsText = text.Trim();
4545

@@ -348,7 +348,7 @@ bool ReturnOnParseError(string title, out IXamlAstValueNode? result)
348348
}
349349

350350
// Keep it in the end, so more specific parsers can be applied.
351-
var elementType = GetElementType(type, context.Configuration.WellKnownTypes);
351+
var elementType = GetElementType(type);
352352
if (elementType is not null)
353353
{
354354
string[] items;
@@ -445,15 +445,16 @@ bool ReturnOnParseError(string title, out IXamlAstValueNode? result)
445445
return false;
446446
}
447447

448-
private static IXamlType? GetElementType(IXamlType type, XamlTypeWellKnownTypes types)
448+
private static IXamlType? GetElementType(IXamlType type)
449449
{
450450
if (type.IsArray)
451451
{
452452
return type.ArrayElementType;
453453
}
454454

455-
return type.GetAllInterfaces().FirstOrDefault(i =>
456-
i.FullName.StartsWith(types.IEnumerableT.FullName))?
455+
return type.GetAllInterfaces().FirstOrDefault(static i =>
456+
i.Name.StartsWith("IEnumerable`1", StringComparison.Ordinal) &&
457+
i.Namespace == "System.Collections.Generic")?
457458
.GenericArguments[0];
458459
}
459460
}

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode nod
1616
if (node is XamlPropertyAssignmentNode pa)
1717
{
1818
if (pa.Property.Name == "Name"
19-
&& pa.Property.DeclaringType.Interfaces.Any(t => t.FullName == "Avalonia.INamed"))
19+
&& pa.Property.DeclaringType.Interfaces.Any(t => t.Is("Avalonia", "INamed")))
2020
{
2121
if (context.ParentNodes().FirstOrDefault() is XamlManipulationGroupNode mg
2222
&& mg.Children.OfType<AvaloniaNameScopeRegistrationXamlIlNode>().Any())

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode nod
3030
startType = extension.Type.GetClrType();
3131

3232
//let's try to infer StaticResource type from parent resources in xaml
33-
if (extension.Value.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension" &&
33+
if (extension.Value.Type.GetClrType().Is("Avalonia.Markup.Xaml.MarkupExtensions", "StaticResourceExtension") &&
3434
extension.Value is XamlAstConstructableObjectNode cn &&
3535
cn.Arguments.Count == 1 && cn.Arguments[0] is XamlAstTextNode keyNode)
3636
{
@@ -56,7 +56,7 @@ IEnumerable<XamlPropertyAssignmentNode> getResourceValues(IXamlAstNode node)
5656
{
5757
if (propertyNode.Values.Count == 1 &&
5858
propertyNode.Values[0] is XamlAstConstructableObjectNode obj &&
59-
obj.Type.GetClrType().FullName == "Avalonia.Controls.ResourceDictionary")
59+
obj.Type.GetClrType().Is("Avalonia.Controls", "ResourceDictionary"))
6060
{
6161
foreach (var r in obj.Children.SelectMany(c => getResourceValues(c)))
6262
{

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode nod
163163
{
164164
foreach (var i in GetAllInterfacesIncludingSelf(itemsCollectionType))
165165
{
166-
if (i.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.IEnumerableT) == true)
166+
if (i.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.IEnumerableOfT) == true)
167167
{
168168
return new AvaloniaXamlIlDataContextTypeMetadataNode(on, i.GenericArguments[0]);
169169
}

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ bool AddBranchNode(
136136
try
137137
{
138138
var targetType = method.Parameters.Last();
139-
if (targetType.FullName == "System.Type")
139+
if (targetType.Is("System", "Type"))
140140
{
141141
if (option is IXamlType typeOption)
142142
{

src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlQueryTransformer.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public virtual XamlILNodeEmitResult Emit(XamlEmitContext<IXamlILEmitter, XamlILN
138138
[UnconditionalSuppressMessage("Trimming", "IL2122", Justification = TrimmingMessages.TypesInCoreOrAvaloniaAssembly)]
139139
protected void EmitCall(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, Func<IXamlMethod, bool> method)
140140
{
141-
var queries = context.Configuration.TypeSystem.GetType("Avalonia.Styling.StyleQueries");
141+
var queries = context.GetAvaloniaTypes().StyleQueries;
142142
var found = queries.FindMethod(m => m.IsStatic && m.Parameters.Count > 0 && method(m));
143143
if(found == null)
144144
throw new XamlTypeSystemException(
@@ -174,7 +174,7 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
174174
var name = Concrete ? "OfType" : "Is";
175175
codeGen.Ldtype(TargetType);
176176
EmitCall(context, codeGen,
177-
m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].FullName == "System.Type");
177+
m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].Equals(context.Configuration.WellKnownTypes.Type));
178178
}
179179
}
180180

@@ -201,7 +201,7 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
201201
codeGen.Ldstr(String);
202202
var name = _type.ToString();
203203
EmitCall(context, codeGen,
204-
m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].FullName == "System.String");
204+
m => m.Name == name && m.Parameters.Count == 2 && m.Parameters[1].Equals(context.Configuration.WellKnownTypes.String));
205205
}
206206
}
207207

@@ -320,11 +320,10 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
320320
return;
321321
}
322322

323-
if (context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1") is not { } type)
324-
return;
325323

326-
IXamlType listType = type.MakeGenericType(base.Type.GetClrType());
327-
var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType());
324+
var typeArgument = Type.GetClrType();
325+
var listType = context.Configuration.WellKnownTypes.ListOfT.MakeGenericType(typeArgument);
326+
var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, typeArgument);
328327
if (add == null)
329328
return;
330329

@@ -338,7 +337,7 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
338337
foreach (var s in _queries)
339338
{
340339
codeGen.Dup();
341-
context.Emit(s, codeGen, Type.GetClrType());
340+
context.Emit(s, codeGen, typeArgument);
342341
codeGen.EmitCall(add, true);
343342
}
344343

@@ -399,11 +398,9 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
399398
return;
400399
}
401400

402-
if (context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1") is not { } type)
403-
return;
404-
405-
IXamlType listType = type.MakeGenericType(base.Type.GetClrType());
406-
var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType());
401+
var typeArgument = Type.GetClrType();
402+
var listType = context.Configuration.WellKnownTypes.ListOfT.MakeGenericType(typeArgument);
403+
var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, typeArgument);
407404
if (add == null)
408405
return;
409406

@@ -417,7 +414,7 @@ protected override void DoEmit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitRes
417414
foreach (var s in _queries)
418415
{
419416
codeGen.Dup();
420-
context.Emit(s, codeGen, Type.GetClrType());
417+
context.Emit(s, codeGen, typeArgument);
421418
codeGen.EmitCall(add, true);
422419
}
423420

0 commit comments

Comments
 (0)