Skip to content

Commit

Permalink
Shared XAML setters cache
Browse files Browse the repository at this point in the history
  • Loading branch information
MrJul committed Feb 23, 2024
1 parent e35e949 commit e786d3d
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 61 deletions.
80 changes: 42 additions & 38 deletions src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using MethodAttributes = Mono.Cecil.MethodAttributes;
using TypeAttributes = Mono.Cecil.TypeAttributes;
using XamlX.IL;
using XamlX.IL.Emitters;

namespace Avalonia.Build.Tasks
{
Expand Down Expand Up @@ -126,7 +127,7 @@ internal static CompileResult Compile(IBuildEngine engine,
System.Threading.Thread.Sleep(100);
}

time.Stop();
time.Stop();
if (time.Elapsed >= timeout)
{
engine.LogMessage("Wating attach debugger timeout.", MessageImportance.Normal);
Expand All @@ -137,7 +138,7 @@ internal static CompileResult Compile(IBuildEngine engine,
engine.LogMessage("Debugging cancelled.", MessageImportance.Normal);
}
}

// Some transformers might need to parse "avares://" Uri.
AssetLoader.RegisterResUriParsers();

Expand All @@ -157,15 +158,21 @@ internal static CompileResult Compile(IBuildEngine engine,
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>();
Expand Down Expand Up @@ -194,14 +201,17 @@ internal static CompileResult Compile(IBuildEngine engine,
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"))
Expand All @@ -215,10 +225,8 @@ internal static CompileResult Compile(IBuildEngine engine,
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)
{
Expand Down Expand Up @@ -257,7 +265,6 @@ internal static CompileResult Compile(IBuildEngine engine,
};
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(
Expand All @@ -270,17 +277,15 @@ internal static CompileResult Compile(IBuildEngine engine,

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()))
{
Expand Down Expand Up @@ -325,7 +330,7 @@ bool CompileGroup(IResourceGroup group)
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;
Expand All @@ -348,7 +353,7 @@ bool CompileGroup(IResourceGroup group)
"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);
Expand Down Expand Up @@ -380,6 +385,7 @@ bool CompileGroup(IResourceGroup group)
classTypeDefinition == null && classModifierPublic.Value
? XamlVisibility.Public
: XamlVisibility.Private),
buildName == null ? null : builder,
buildName == null ?
null :
compiler.DefineBuildMethod(
Expand Down Expand Up @@ -407,7 +413,7 @@ bool CompileGroup(IResourceGroup group)
transformFailed = true;
engine.LogError(AvaloniaXamlDiagnosticCodes.TransformError, "", e);
}

var hasAnyError = ReportDiagnostics(engine, diagnostics) || transformFailed;
if (hasAnyError)
{
Expand All @@ -426,22 +432,20 @@ bool CompileGroup(IResourceGroup group)

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
);

Expand Down Expand Up @@ -480,10 +484,10 @@ MethodDefinition CreateTrampolineMethod(bool hasSystemProviderArg)
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);
Expand All @@ -498,7 +502,7 @@ MethodDefinition CreateTrampolineMethod(bool hasSystemProviderArg)
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);
Expand Down Expand Up @@ -650,10 +654,10 @@ MethodDefinition CreateTrampolineMethod(bool hasSystemProviderArg)
dupe.Name += "_dup" + dupeCounter++;
}
}

return true;
}

if (avares.Resources.Count(CheckXamlName) != 0)
{
if (!CompileGroup(avares))
Expand Down Expand Up @@ -698,7 +702,7 @@ static bool ReportDiagnostics(IBuildEngine engine, IReadOnlyCollection<XamlDiagn
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static IReadOnlyList<object> LoadGroupSreCore(IReadOnlyCollection<RuntimeXamlLoa
},
CodeMappings = AvaloniaXamlDiagnosticCodes.XamlXDiagnosticCodeToAvalonia
};

var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm,
_sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter,
new XamlIlClrPropertyInfoEmitter(_sreTypeSystem.CreateTypeBuilder(clrPropertyBuilder)),
Expand Down Expand Up @@ -279,6 +279,7 @@ static IReadOnlyList<object> LoadGroupSreCore(IReadOnlyCollection<RuntimeXamlLoa
() => 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)));
Expand All @@ -292,7 +293,7 @@ document.RootInstance is null ?
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,17 @@ public XamlDocument Parse(string xaml, IXamlType overrideRootType)

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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ public OptionsMarkupExtensionMethod(

public string Name => "ProvideValue";
public bool IsPublic => true;
public bool IsPrivate => false;
public bool IsStatic => false;
public IXamlType ReturnType => ExtensionNodeContainer.GetReturnType();
public IReadOnlyList<IXamlType> Parameters { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ public GetterMethod(AvaloniaAttachedInstanceProperty parent)
}
public AvaloniaAttachedInstanceProperty Parent { get; }
public bool IsPublic => true;
public bool IsPrivate => false;
public bool IsStatic => true;
public string Name { get; protected set; }
public IXamlType DeclaringType { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Reflection.Emit;
using Avalonia.Markup.Parsers;
Expand All @@ -12,7 +11,6 @@
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;
Expand Down Expand Up @@ -667,7 +665,11 @@ public void Emit(XamlIlEmitContext context, IXamlILEmitter codeGen)
{
// 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
Expand Down
9 changes: 2 additions & 7 deletions src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -23,7 +21,7 @@ public static MiniCompiler CreateDefault(RoslynTypeSystem typeSystem, params str
mappings.XmlnsAttributes.Add(typeSystem.GetType(additionalType));

var diagnosticsHandler = new XamlDiagnosticsHandler();

var configuration = new TransformerConfiguration(
typeSystem,
typeSystem.Assemblies.First(),
Expand All @@ -45,10 +43,7 @@ private MiniCompiler(TransformerConfiguration configuration)

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) =>
Expand Down
Loading

0 comments on commit e786d3d

Please sign in to comment.