| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
- using XamlX.Ast;
- using XamlX.Transform;
- using XamlX.TypeSystem;
- using XamlX.IL;
- using XamlX.Emit;
- namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
- {
- class XamlIlClrPropertyInfoEmitter
- {
- private readonly IXamlTypeBuilder<IXamlILEmitter> _builder;
- private Dictionary<string, List<(IXamlProperty prop, IXamlMethod get)>> _fields
- = new Dictionary<string, List<(IXamlProperty prop, IXamlMethod get)>>();
-
- public XamlIlClrPropertyInfoEmitter(IXamlTypeBuilder<IXamlILEmitter> builder)
- {
- _builder = builder;
- }
- static string GetKey(IXamlProperty property, string indexerArgumentsKey)
- {
- var baseKey = property.Getter.DeclaringType.GetFullName() + "." + property.Name;
- if (indexerArgumentsKey is null)
- {
- return baseKey;
- }
- return baseKey + $"[{indexerArgumentsKey}]";
- }
- public IXamlType Emit(XamlEmitContext<IXamlILEmitter, XamlILNodeEmitResult> context, IXamlILEmitter codeGen, IXamlProperty property, IEnumerable<IXamlAstValueNode> indexerArguments = null, string indexerArgumentsKey = null)
- {
- indexerArguments = indexerArguments ?? Enumerable.Empty<IXamlAstValueNode>();
- var types = context.GetAvaloniaTypes();
- IXamlMethod Get()
- {
- var key = GetKey(property, indexerArgumentsKey);
- if (!_fields.TryGetValue(key, out var lst))
- _fields[key] = lst = new List<(IXamlProperty prop, IXamlMethod get)>();
- foreach (var cached in lst)
- {
- if (
- ((cached.prop.Getter == null && property.Getter == null) ||
- cached.prop.Getter?.Equals(property.Getter) == true) &&
- ((cached.prop.Setter == null && property.Setter == null) ||
- cached.prop.Setter?.Equals(property.Setter) == true)
- )
- return cached.get;
- }
- var name = lst.Count == 0 ? key : key + "_" + Guid.NewGuid().ToString("N");
-
- var field = _builder.DefineField(types.IPropertyInfo, name + "!Field", false, true);
- void Load(IXamlMethod m, IXamlILEmitter cg)
- {
- cg
- .Ldarg_0();
- if (m.DeclaringType.IsValueType)
- cg.Unbox(m.DeclaringType);
- else
- cg.Castclass(m.DeclaringType);
- foreach (var indexerArg in indexerArguments)
- {
- context.Emit(indexerArg, cg, indexerArg.Type.GetClrType());
- }
- }
- var getter = property.Getter == null ?
- null :
- _builder.DefineMethod(types.XamlIlTypes.Object,
- new[] {types.XamlIlTypes.Object}, name + "!Getter", false, true, false);
- if (getter != null)
- {
- Load(property.Getter, getter.Generator);
-
- getter.Generator.EmitCall(property.Getter);
- if (property.Getter.ReturnType.IsValueType)
- getter.Generator.Box(property.Getter.ReturnType);
- getter.Generator.Ret();
- }
- var setter = property.Setter == null ?
- null :
- _builder.DefineMethod(types.XamlIlTypes.Void,
- new[] {types.XamlIlTypes.Object, types.XamlIlTypes.Object},
- name + "!Setter", false, true, false);
- if (setter != null)
- {
- Load(property.Setter, setter.Generator);
-
- setter.Generator.Ldarg(1);
- if (property.Setter.Parameters[0].IsValueType)
- setter.Generator.Unbox_Any(property.Setter.Parameters[0]);
- else
- setter.Generator.Castclass(property.Setter.Parameters[0]);
- setter.Generator
- .EmitCall(property.Setter, true)
- .Ret();
- }
- var get = _builder.DefineMethod(types.IPropertyInfo, Array.Empty<IXamlType>(),
- name + "!Property", true, true, false);
- var ctor = types.ClrPropertyInfo.Constructors.First(c =>
- c.Parameters.Count == 4 && c.IsStatic == false);
-
- var cacheMiss = get.Generator.DefineLabel();
- get.Generator
- .Ldsfld(field)
- .Brfalse(cacheMiss)
- .Ldsfld(field)
- .Ret()
- .MarkLabel(cacheMiss)
- .Ldstr(property.Name);
- void EmitFunc(IXamlILEmitter emitter, IXamlMethod method, IXamlType del)
- {
- if (method == null)
- emitter.Ldnull();
- else
- {
- emitter
- .Ldnull()
- .Ldftn(method)
- .Newobj(del.Constructors.First(c =>
- c.Parameters.Count == 2 &&
- c.Parameters[0].Equals(context.Configuration.WellKnownTypes.Object)));
- }
- }
- EmitFunc(get.Generator, getter, ctor.Parameters[1]);
- EmitFunc(get.Generator, setter, ctor.Parameters[2]);
- get.Generator
- .Ldtype(property.PropertyType)
- .Newobj(ctor)
- .Stsfld(field)
- .Ldsfld(field)
- .Ret();
- lst.Add((property, get));
- return get;
- }
- codeGen.EmitCall(Get());
- return types.IPropertyInfo;
- }
- }
- }
|