Browse Source

Shared XAML setters cache (#14717)

pull/14782/head
Julien Lebosquain 3 years ago
committed by GitHub
parent
commit
434cbac055
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 80
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  2. 5
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  3. 15
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  4. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlOptionMarkupExtensionTransformer.cs
  5. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  6. 9
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs
  7. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs
  8. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  9. 9
      src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs
  10. 13
      src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs

80
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -18,6 +18,7 @@ using FieldAttributes = Mono.Cecil.FieldAttributes;
using MethodAttributes = Mono.Cecil.MethodAttributes;
using TypeAttributes = Mono.Cecil.TypeAttributes;
using XamlX.IL;
using XamlX.IL.Emitters;
namespace Avalonia.Build.Tasks
{
@ -126,7 +127,7 @@ namespace Avalonia.Build.Tasks
System.Threading.Thread.Sleep(100);
}
time.Stop();
time.Stop();
if (time.Elapsed >= timeout)
{
engine.LogMessage("Wating attach debugger timeout.", MessageImportance.Normal);
@ -137,7 +138,7 @@ namespace Avalonia.Build.Tasks
engine.LogMessage("Debugging cancelled.", MessageImportance.Normal);
}
}
// Some transformers might need to parse "avares://" Uri.
AssetLoader.RegisterResUriParsers();
@ -157,15 +158,21 @@ namespace Avalonia.Build.Tasks
asm.CustomAttributes.Add(new CustomAttribute(ctor) { ConstructorArguments = { arg1, arg2 } });
}
var clrPropertiesDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "XamlIlHelpers",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(clrPropertiesDef);
var indexerAccessorClosure = new TypeDefinition(CompiledAvaloniaXamlNamespace, "!IndexerAccessorFactoryClosure",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(indexerAccessorClosure);
var trampolineBuilder = new TypeDefinition(CompiledAvaloniaXamlNamespace, "XamlIlTrampolines",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(trampolineBuilder);
TypeDefinition AddClass(string name, TypeAttributes extraAttributes = 0)
{
var typeDef = new TypeDefinition(
CompiledAvaloniaXamlNamespace,
name,
TypeAttributes.Class | extraAttributes,
asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(typeDef);
return typeDef;
}
var clrPropertiesDef = AddClass("XamlIlHelpers");
var indexerAccessorClosure = AddClass("!IndexerAccessorFactoryClosure");
var trampolineBuilder = AddClass("XamlIlTrampolines");
var dynamicSettersBuilder = typeSystem.CreateTypeBuilder(AddClass("XamlDynamicSetters"));
var (xamlLanguage , emitConfig) = AvaloniaXamlIlLanguage.Configure(typeSystem);
var diagnostics = new List<XamlDiagnostic>();
@ -194,14 +201,17 @@ namespace Avalonia.Build.Tasks
diagnosticsHandler);
var contextDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "XamlIlContext",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(contextDef);
var contextDef = AddClass("XamlIlContext");
var contextClass = XamlILContextDefinition.GenerateContextClass(typeSystem.CreateTypeBuilder(contextDef), typeSystem,
xamlLanguage, emitConfig);
var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass) { EnableIlVerification = verifyIl, DefaultCompileBindings = defaultCompileBindings };
var compiler = new AvaloniaXamlIlCompiler(compilerConfig, emitConfig, contextClass)
{
EnableIlVerification = verifyIl,
DefaultCompileBindings = defaultCompileBindings,
DynamicSetterContainerProvider = new DefaultXamlDynamicSetterContainerProvider(dynamicSettersBuilder)
};
var editorBrowsableAttribute = typeSystem
.GetTypeReference(typeSystem.FindType("System.ComponentModel.EditorBrowsableAttribute"))
@ -215,10 +225,8 @@ namespace Avalonia.Build.Tasks
typeSystem.GetTypeReference(runtimeHelpers).Resolve().Methods
.First(x => x.Name == "CreateRootServiceProviderV3"));
var serviceProviderType = createRootServiceProviderMethod.ReturnType;
var loaderDispatcherDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "!XamlLoader",
TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
var loaderDispatcherDef = AddClass("!XamlLoader", TypeAttributes.Public);
loaderDispatcherDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
{
@ -257,7 +265,6 @@ namespace Avalonia.Build.Tasks
};
loaderDispatcherDef.Methods.Add(loaderDispatcherMethod);
loaderDispatcherDef.Methods.Add(loaderDispatcherMethodOld);
asm.MainModule.Types.Add(loaderDispatcherDef);
var stringEquals = asm.MainModule.ImportReference(asm.MainModule.TypeSystem.String.Resolve().Methods.First(
@ -270,17 +277,15 @@ namespace Avalonia.Build.Tasks
bool CompileGroup(IResourceGroup group)
{
var typeDef = new TypeDefinition(CompiledAvaloniaXamlNamespace, "!"+ group.Name,
TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
var typeDef = AddClass("!" + group.Name, TypeAttributes.Public);
var transformFailed = false;
typeDef.CustomAttributes.Add(new CustomAttribute(editorBrowsableCtor)
{
ConstructorArguments = {new CustomAttributeArgument(editorBrowsableCtor.Parameters[0].ParameterType, 1)}
});
asm.MainModule.Types.Add(typeDef);
var builder = typeSystem.CreateTypeBuilder(typeDef);
IReadOnlyCollection<XamlDocumentResource> parsedXamlDocuments = new List<XamlDocumentResource>();
foreach (var res in group.Resources.Where(CheckXamlName).OrderBy(x => x.FilePath.ToLowerInvariant()))
{
@ -325,7 +330,7 @@ namespace Avalonia.Build.Tasks
else
throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", classModifierDirective);
}
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
IXamlType classType = null;
@ -348,7 +353,7 @@ namespace Avalonia.Build.Tasks
"XAML file x:ClassModifier doesn't match the x:Class type modifiers.",
precompileDirective);
}
compiler.OverrideRootType(parsed,
new XamlAstClrTypeReference(classDirective, classType, false));
initialRoot.Children.Remove(classDirective);
@ -380,6 +385,7 @@ namespace Avalonia.Build.Tasks
classTypeDefinition == null && classModifierPublic.Value
? XamlVisibility.Public
: XamlVisibility.Private),
buildName == null ? null : builder,
buildName == null ?
null :
compiler.DefineBuildMethod(
@ -407,7 +413,7 @@ namespace Avalonia.Build.Tasks
transformFailed = true;
engine.LogError(AvaloniaXamlDiagnosticCodes.TransformError, "", e);
}
var hasAnyError = ReportDiagnostics(engine, diagnostics) || transformFailed;
if (hasAnyError)
{
@ -426,22 +432,20 @@ namespace Avalonia.Build.Tasks
var parsed = document.XamlDocument;
var classType = document.ClassType;
var populateBuilder = document.TypeBuilderProvider.TypeBuilder;
var populateBuilder = document.TypeBuilderProvider.PopulateDeclaringType;
try
{
var classTypeDefinition =
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve();
compiler.Compile(parsed,
compiler.Compile(parsed,
contextClass,
document.TypeBuilderProvider.PopulateMethod,
populateBuilder,
document.TypeBuilderProvider.BuildMethod,
builder,
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, XamlVisibility.Public),
(closureName, closureBaseType) =>
populateBuilder.DefineSubType(closureBaseType, closureName, XamlVisibility.Private),
(closureName, returnType, parameterTypes) =>
populateBuilder.DefineDelegateSubType(closureName, XamlVisibility.Private, returnType, parameterTypes),
res.Uri, res
);
@ -480,10 +484,10 @@ namespace Avalonia.Build.Tasks
MethodAttributes.Static | MethodAttributes.Private, asm.MainModule.TypeSystem.Void);
if (hasSystemProviderArg)
{
trampoline.Parameters.Add(new ParameterDefinition(serviceProviderType));
trampoline.Parameters.Add(new ParameterDefinition(serviceProviderType));
}
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
classTypeDefinition.Methods.Add(trampoline);
var regularStart = Instruction.Create(OpCodes.Nop);
@ -498,7 +502,7 @@ namespace Avalonia.Build.Tasks
trampoline.Body.Instructions.Add(regularStart);
trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_0 : OpCodes.Ldnull));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod));
trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0));
trampoline.Body.Instructions.Add(Instruction.Create(hasSystemProviderArg ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Call, compiledPopulateMethod));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
CopyDebugDocument(trampoline, compiledPopulateMethod);
@ -650,10 +654,10 @@ namespace Avalonia.Build.Tasks
dupe.Name += "_dup" + dupeCounter++;
}
}
return true;
}
if (avares.Resources.Count(CheckXamlName) != 0)
{
if (!CompileGroup(avares))
@ -698,7 +702,7 @@ namespace Avalonia.Build.Tasks
foreach (var ogType in compiledTypes)
{
var wrappedOgType = sourceTypeSystem.TargetAssembly.FindType(ogType.FullName);
var clrPropertiesDef = new TypeDefinition(ogType.Namespace, ogType.Name,
TypeAttributes.Class | TypeAttributes.Public, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(clrPropertiesDef);

5
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -242,7 +242,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
},
CodeMappings = AvaloniaXamlDiagnosticCodes.XamlXDiagnosticCodeToAvalonia
};
var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm,
_sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter,
new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
@ -292,6 +292,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
() => new XamlDocumentTypeBuilderProvider(
builder,
compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, XamlVisibility.Public),
document.RootInstance is null ? builder : null,
document.RootInstance is null ?
compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, XamlVisibility.Public) :
null)));
@ -305,7 +306,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
var createdTypes = parsedDocuments.Select(document =>
{
compiler.Compile(document.XamlDocument, document.TypeBuilderProvider, document.Uri, document.FileSource);
return _sreTypeSystem.GetType(document.TypeBuilderProvider.TypeBuilder.CreateType());
return _sreTypeSystem.GetType(document.TypeBuilderProvider.PopulateDeclaringType.CreateType());
}).ToArray();
clrPropertyBuilder.CreateTypeInfo();

15
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -187,14 +187,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource)
{
var tb = typeBuilderProvider.TypeBuilder;
Compile(document, _contextType, typeBuilderProvider.PopulateMethod, typeBuilderProvider.BuildMethod,
Compile(
document,
_contextType,
typeBuilderProvider.PopulateMethod,
typeBuilderProvider.PopulateDeclaringType,
typeBuilderProvider.BuildMethod,
typeBuilderProvider.BuildDeclaringType,
_configuration.TypeMappings.XmlNamespaceInfoProvider == null ?
null :
tb.DefineSubType(_configuration.WellKnownTypes.Object,
"__AvaloniaXamlIlNsInfo", XamlVisibility.Private), (name, bt) => tb.DefineSubType(bt, name, XamlVisibility.Private),
(s, returnType, parameters) => tb.DefineDelegateSubType(s, XamlVisibility.Private, returnType, parameters), baseUri,
typeBuilderProvider.PopulateDeclaringType.DefineSubType(_configuration.WellKnownTypes.Object, "__AvaloniaXamlIlNsInfo", XamlVisibility.Private),
baseUri,
fileSource);
}

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

@ -330,6 +330,8 @@ internal class AvaloniaXamlIlOptionMarkupExtensionTransformer : IXamlAstTransfor
public string Name => "ProvideValue";
public bool IsPublic => true;
public bool IsPrivate => false;
public bool IsFamily => false;
public bool IsStatic => false;
public IXamlType ReturnType => ExtensionNodeContainer.GetReturnType();
public IReadOnlyList<IXamlType> Parameters { get; }

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs

@ -163,6 +163,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
public AvaloniaAttachedInstanceProperty Parent { get; }
public bool IsPublic => true;
public bool IsPrivate => false;
public bool IsFamily => false;
public bool IsStatic => true;
public string Name { get; protected set; }
public IXamlType DeclaringType { get; }

9
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs

@ -8,16 +8,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions;
internal sealed class XamlDocumentTypeBuilderProvider
{
public XamlDocumentTypeBuilderProvider(
IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
IXamlTypeBuilder<IXamlILEmitter> populateDeclaringType,
IXamlMethodBuilder<IXamlILEmitter> populateMethod,
IXamlTypeBuilder<IXamlILEmitter>? buildDeclaringType,
IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
{
TypeBuilder = typeBuilder;
PopulateDeclaringType = populateDeclaringType;
PopulateMethod = populateMethod;
BuildDeclaringType = buildDeclaringType;
BuildMethod = buildMethod;
}
public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
public IXamlTypeBuilder<IXamlILEmitter> PopulateDeclaringType { get; }
public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
public IXamlTypeBuilder<IXamlILEmitter>? BuildDeclaringType { get; }
public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }
}

8
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlBindingPathHelper.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Reflection.Emit;
using Avalonia.Markup.Parsers;
@ -12,7 +11,6 @@ using XamlX.TypeSystem;
using XamlX;
using XamlX.Emit;
using XamlX.IL;
using Avalonia.Utilities;
using XamlIlEmitContext = XamlX.Emit.XamlEmitContextWithLocals<XamlX.IL.IXamlILEmitter, XamlX.IL.XamlILNodeEmitResult>;
using System.Xml.Linq;
@ -667,7 +665,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
// In this case, we need to emit our own delegate type.
string delegateTypeName = context.Configuration.IdentifierGenerator.GenerateIdentifierPart();
specificDelegateType = newDelegateTypeBuilder = context.DefineDelegateSubType(delegateTypeName, Method.ReturnType, Method.Parameters);
specificDelegateType = newDelegateTypeBuilder = context.DeclaringType.DefineDelegateSubType(
delegateTypeName,
XamlVisibility.Private,
Method.ReturnType,
Method.Parameters);
}
codeGen

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit 320e57fa1c95d10de33d9a96a323d1bc27563fa1
Subproject commit b357355b9df3e781cf194f2f2ce21669d798bb14

9
src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using XamlX;
using XamlX.Compiler;
using XamlX.Emit;
using XamlX.Transform;
@ -23,7 +21,7 @@ internal sealed class MiniCompiler : XamlCompiler<object, IXamlEmitResult>
mappings.XmlnsAttributes.Add(typeSystem.GetType(additionalType));
var diagnosticsHandler = new XamlDiagnosticsHandler();
var configuration = new TransformerConfiguration(
typeSystem,
typeSystem.Assemblies.First(),
@ -45,10 +43,7 @@ internal sealed class MiniCompiler : XamlCompiler<object, IXamlEmitResult>
protected override XamlEmitContext<object, IXamlEmitResult> InitCodeGen(
IFileSource file,
Func<string, IXamlType,
IXamlTypeBuilder<object>> createSubType,
Func<string, IXamlType, IEnumerable<IXamlType>,
IXamlTypeBuilder<object>> createDelegateType,
IXamlTypeBuilder<object> declaringType,
object codeGen,
XamlRuntimeContext<object, IXamlEmitResult> context,
bool needContextLocal) =>

13
src/tools/Avalonia.Generators/Compiler/RoslynTypeSystem.cs

@ -128,6 +128,13 @@ internal class RoslynType : IXamlType
public IXamlAssembly Assembly => _assembly;
public bool IsPublic => _symbol.DeclaredAccessibility == Accessibility.Public;
public bool IsNestedPrivate => _symbol.DeclaredAccessibility == Accessibility.Private;
public IXamlType DeclaringType =>
_symbol.ContainingType is { } containingType ? new RoslynType(containingType, _assembly) : null;
public IReadOnlyList<IXamlProperty> Properties =>
_symbol.GetMembers()
.Where(member => member.Kind == SymbolKind.Property)
@ -259,7 +266,11 @@ internal class RoslynMethod : IXamlMethod
public string Name => _symbol.Name;
public bool IsPublic => true;
public bool IsPublic => _symbol.DeclaredAccessibility == Accessibility.Public;
public bool IsPrivate => _symbol.DeclaredAccessibility == Accessibility.Private;
public bool IsFamily => _symbol.DeclaredAccessibility == Accessibility.Protected;
public bool IsStatic => false;

Loading…
Cancel
Save