Browse Source

Merge branch 'master' into pr-template

pull/8712/head
Max Katz 4 years ago
committed by GitHub
parent
commit
a6f1b7c0da
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs
  2. 26
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  3. 152
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  4. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

50
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDeferredResourceTransformer.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using XamlX.Ast;
using XamlX.Emit;
@ -47,7 +48,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return !node.Type.GetClrType().IsValueType;
}
class AdderSetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
class AdderSetter : IXamlILOptimizedEmitablePropertySetter, IEquatable<AdderSetter>
{
private readonly IXamlMethod _getter;
private readonly IXamlMethod _adder;
@ -58,16 +59,22 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_adder = adder;
TargetType = getter.DeclaringType;
Parameters = adder.ParametersWithThis().Skip(1).ToList();
bool allowNull = Parameters.Last().AcceptsNull();
BinderParameters = new PropertySetterBinderParameters
{
AllowMultiple = true,
AllowXNull = allowNull,
AllowRuntimeNull = allowNull
};
}
public IXamlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters
{
AllowMultiple = true
};
public PropertySetterBinderParameters BinderParameters { get; }
public IReadOnlyList<IXamlType> Parameters { get; }
public void Emit(IXamlILEmitter emitter)
{
var locals = new Stack<XamlLocalsPool.PooledLocal>();
@ -80,11 +87,40 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
emitter.EmitCall(_getter);
while (locals.Count > 0)
while (locals.Count>0)
using (var loc = locals.Pop())
emitter.Ldloc(loc.Local);
emitter.EmitCall(_adder, true);
}
public void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
emitter.EmitCall(_getter);
for (var i = 0; i < arguments.Count; ++i)
context.Emit(arguments[i], emitter, Parameters[i]);
emitter.EmitCall(_adder, true);
}
public bool Equals(AdderSetter other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return _getter.Equals(other._getter) && _adder.Equals(other._adder);
}
public override bool Equals(object obj)
=> Equals(obj as AdderSetter);
public override int GetHashCode()
=> (_getter.GetHashCode() * 397) ^ _adder.GetHashCode();
}
}
}

26
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@ -75,17 +75,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
Getter = setterType.Methods.First(m => m.Name == "get_Value");
var method = setterType.Methods.First(m => m.Name == "set_Value");
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.IBinding));
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.UnsetValueType));
Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType));
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.IBinding, false));
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.UnsetValueType, false));
Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType, targetType.AcceptsNull()));
}
class XamlIlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
sealed class XamlIlDirectCallPropertySetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
{
private readonly IXamlMethod _method;
private readonly IXamlType _type;
public IXamlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
public PropertySetterBinderParameters BinderParameters { get; }
public IReadOnlyList<IXamlType> Parameters { get; }
public void Emit(IXamlILEmitter codegen)
{
@ -94,13 +94,27 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
codegen.EmitCall(_method, true);
}
public XamlIlDirectCallPropertySetter(IXamlMethod method, IXamlType type)
public XamlIlDirectCallPropertySetter(IXamlMethod method, IXamlType type, bool allowNull)
{
_method = method;
_type = type;
Parameters = new[] {type};
TargetType = method.ThisOrFirstParameter();
BinderParameters = new PropertySetterBinderParameters
{
AllowXNull = allowNull,
AllowRuntimeNull = allowNull
};
}
private bool Equals(XamlIlDirectCallPropertySetter other)
=> Equals(_method, other._method) && Equals(_type, other._type);
public override bool Equals(object obj)
=> Equals(obj as XamlIlDirectCallPropertySetter);
public override int GetHashCode()
=> (_method.GetHashCode() * 397) ^ _type.GetHashCode();
}
}
}

152
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@ -206,38 +206,64 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field));
}
abstract class AvaloniaPropertyCustomSetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter>
abstract class AvaloniaPropertyCustomSetter : IXamlILOptimizedEmitablePropertySetter, IEquatable<AvaloniaPropertyCustomSetter>
{
protected AvaloniaXamlIlWellKnownTypes Types;
protected IXamlField AvaloniaProperty;
protected readonly AvaloniaXamlIlWellKnownTypes Types;
protected readonly IXamlField AvaloniaProperty;
public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types,
protected AvaloniaPropertyCustomSetter(
AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType,
IXamlField avaloniaProperty)
IXamlField avaloniaProperty,
bool allowNull)
{
Types = types;
AvaloniaProperty = avaloniaProperty;
TargetType = declaringType;
BinderParameters = new PropertySetterBinderParameters
{
AllowXNull = allowNull,
AllowRuntimeNull = allowNull
};
}
public IXamlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters
{
AllowXNull = false
};
public PropertySetterBinderParameters BinderParameters { get; }
public IReadOnlyList<IXamlType> Parameters { get; set; }
public abstract void Emit(IXamlILEmitter codegen);
public abstract void Emit(IXamlILEmitter emitter);
public abstract void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments);
public bool Equals(AvaloniaPropertyCustomSetter other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return GetType() == other.GetType() && AvaloniaProperty.Equals(other.AvaloniaProperty);
}
public override bool Equals(object obj)
=> Equals(obj as AvaloniaPropertyCustomSetter);
public override int GetHashCode()
=> AvaloniaProperty.GetHashCode();
}
class BindingSetter : AvaloniaPropertyCustomSetter
{
public BindingSetter(AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType,
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false)
{
Parameters = new[] {types.IBinding};
Parameters = new[] { types.IBinding };
}
public override void Emit(IXamlILEmitter emitter)
@ -246,10 +272,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
emitter
.Stloc(bloc.Local)
.Ldsfld(AvaloniaProperty)
.Ldloc(bloc.Local)
// TODO: provide anchor?
.Ldnull();
emitter.EmitCall(Types.AvaloniaObjectBindMethod, true);
.Ldloc(bloc.Local);
EmitAnchorAndBind(emitter);
}
public override void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
emitter.Ldsfld(AvaloniaProperty);
context.Emit(arguments[0], emitter, Parameters[0]);
EmitAnchorAndBind(emitter);
}
private void EmitAnchorAndBind(IXamlILEmitter emitter)
{
emitter
.Ldnull() // TODO: provide anchor?
.EmitCall(Types.AvaloniaObjectBindMethod, true);
}
}
@ -257,7 +298,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
public BindingWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types,
IXamlType declaringType,
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false)
{
Parameters = new[] { types.BindingPriority, types.IBinding };
}
@ -265,15 +306,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
public override void Emit(IXamlILEmitter emitter)
{
using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding))
using (var priorityLocal = emitter.LocalsPool.GetLocal(Types.Int))
emitter
.Stloc(bloc.Local)
.Stloc(priorityLocal.Local)
.Pop() // ignore priority
.Ldsfld(AvaloniaProperty)
.Ldloc(bloc.Local)
// TODO: provide anchor?
.Ldnull();
emitter.EmitCall(Types.AvaloniaObjectBindMethod, true);
.Ldloc(bloc.Local);
EmitAnchorAndBind(emitter);
}
public override void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
emitter.Ldsfld(AvaloniaProperty);
context.Emit(arguments[1], emitter, Parameters[1]);
EmitAnchorAndBind(emitter);
}
private void EmitAnchorAndBind(IXamlILEmitter emitter)
{
emitter
.Ldnull() // TODO: provide anchor?
.EmitCall(Types.AvaloniaObjectBindMethod, true);
}
}
@ -281,7 +336,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
public SetValueWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty,
IXamlType propertyType)
: base(types, declaringType, avaloniaProperty)
: base(types, declaringType, avaloniaProperty, propertyType.AcceptsNull())
{
Parameters = new[] { types.BindingPriority, propertyType };
}
@ -295,9 +350,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
- value
*/
var method = Types.AvaloniaObjectSetStyledPropertyValue
.MakeGenericMethod(new[] { Parameters[1] });
using (var valueLocal = emitter.LocalsPool.GetLocal(Parameters[1]))
using (var priorityLocal = emitter.LocalsPool.GetLocal(Types.Int))
emitter
@ -305,25 +357,57 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
.Stloc(priorityLocal.Local)
.Ldsfld(AvaloniaProperty)
.Ldloc(valueLocal.Local)
.Ldloc(priorityLocal.Local)
.EmitCall(method, true);
.Ldloc(priorityLocal.Local);
EmitSetStyledPropertyValue(emitter);
}
public override void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
emitter.Ldsfld(AvaloniaProperty);
context.Emit(arguments[1], emitter, Parameters[1]);
context.Emit(arguments[0], emitter, Parameters[0]);
EmitSetStyledPropertyValue(emitter);
}
private void EmitSetStyledPropertyValue(IXamlILEmitter emitter)
{
var method = Types.AvaloniaObjectSetStyledPropertyValue.MakeGenericMethod(new[] { Parameters[1] });
emitter.EmitCall(method, true);
}
}
class UnsetValueSetter : AvaloniaPropertyCustomSetter
{
public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty)
: base(types, declaringType, avaloniaProperty)
: base(types, declaringType, avaloniaProperty, false)
{
Parameters = new[] {types.UnsetValueType};
Parameters = new[] { types.UnsetValueType };
}
public override void Emit(IXamlILEmitter codegen)
{
codegen.Pop();
EmitSetValue(codegen);
}
public override void EmitWithArguments(
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context,
IXamlILEmitter emitter,
IReadOnlyList<IXamlAstValueNode> arguments)
{
EmitSetValue(emitter);
}
private void EmitSetValue(IXamlILEmitter emitter)
{
// Ignore the instance and load one from the static field to avoid extra local variable
var unsetValue = Types.AvaloniaProperty.Fields.First(f => f.Name == "UnsetValue");
codegen
// Ignore the instance and load one from the static field to avoid extra local variable
.Pop()
emitter
.Ldsfld(AvaloniaProperty)
.Ldsfld(unsetValue)
.Ldc_I4(0)

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

@ -1 +1 @@
Subproject commit a4e6be2d1407abec4f35fcb208848830ce513ead
Subproject commit c1c0594ec2c35b08988183b1a5b3e34dfa19179d
Loading…
Cancel
Save