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

Share similar XAML dynamic setters #14717

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -242,7 +242,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 @@ -292,6 +292,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 @@ -305,7 +306,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 @@ -187,14 +187,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,8 @@ public OptionsMarkupExtensionMethod(

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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ public GetterMethod(AvaloniaAttachedInstanceProperty parent)
}
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; }
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
Loading