public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { // Discard the stack value we are "supposed" to manipulate codeGen.Pop(); context.Emit(Imperative, codeGen, null); return(XamlIlNodeEmitResult.Void(1)); }
protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (_selectors.Count == 0) { throw new XamlIlLoadException("Invalid selector count", this); } if (_selectors.Count == 1) { _selectors[0].Emit(context, codeGen); return; } var listType = context.Configuration.TypeSystem.FindType("System.Collections.Generic.List`1") .MakeGenericType(base.Type.GetClrType()); var add = listType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, Type.GetClrType()); codeGen .Newobj(listType.FindConstructor()); foreach (var s in _selectors) { codeGen.Dup(); context.Emit(s, codeGen, Type.GetClrType()); codeGen.EmitCall(add, true); } EmitCall(context, codeGen, m => m.Name == "Or" && m.Parameters.Count == 1 && m.Parameters[0].Name.StartsWith("IReadOnlyList")); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlInstanceMethodCallBaseNode mc)) { return(null); } for (var c = 0; c < mc.Arguments.Count; c++) { context.Emit(mc.Arguments[c], codeGen, mc.Method.Parameters[c]); } codeGen.Generator.Emit(mc.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, mc.Method); var isVoid = mc.Method.ReturnType.Equals(context.Configuration.WellKnownTypes.Void); if (mc is XamlIlInstanceNoReturnMethodCallNode && !isVoid) { codeGen.Generator.Emit(OpCodes.Pop); } if (mc is XamlIlStaticReturnMethodCallNode && isVoid) { throw new XamlIlLoadException( $"XamlIlStaticReturnMethodCallNode expects a value while {mc.Method.Name} returns void", node); } return(isVoid ? XamlIlNodeEmitResult.Void : XamlIlNodeEmitResult.Type(mc.Method.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlAstNewClrObjectNode n)) { return(null); } var type = n.Type.GetClrType(); var argTypes = n.Arguments.Select(a => a.Type.GetClrType()).ToList(); var ctor = type.FindConstructor(argTypes); if (ctor == null) { throw new XamlIlLoadException( $"Unable to find public constructor for type {type.GetFqn()}({string.Join(", ", argTypes.Select(at => at.GetFqn()))})", n); } for (var c = 0; c < n.Arguments.Count; c++) { var ctorArg = n.Arguments[c]; context.Emit(ctorArg, codeGen, ctor.Parameters[c]); } var gen = codeGen.Generator .Emit(OpCodes.Newobj, ctor); return(XamlIlNodeEmitResult.Type(type)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlValueWithManipulationNode vwm)) { return(null); } var created = context.Emit(vwm.Value, codeGen, vwm.Type.GetClrType()); if (vwm.Manipulation != null && !(vwm.Manipulation is XamlIlManipulationGroupNode grp && grp.Children.Count == 0)) { codeGen.Emit(OpCodes.Dup); context.Emit(vwm.Manipulation, codeGen, null); } return(XamlIlNodeEmitResult.Type(0, created.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlAstNewClrObjectNode n)) { return(null); } var type = n.Type.GetClrType(); var ctor = n.Constructor ?? type.FindConstructor(); if (ctor == null) { throw new XamlIlLoadException("Unable to find default constructor and no non-default one is specified", n); } for (var c = 0; c < n.Arguments.Count; c++) { context.Emit(n.Arguments[c], codeGen, ctor.Parameters[c]); } var gen = codeGen .Emit(OpCodes.Newobj, ctor); return(XamlIlNodeEmitResult.Type(0, type)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions"); var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope"); var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register"); using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType)) { var exit = codeGen.DefineLabel(); codeGen // var target = {pop} .Stloc(targetLoc.Local) // var scope = target.FindNameScope() .Ldloc(targetLoc.Local) .Castclass(findNameScope.Parameters[0]) .EmitCall(findNameScope) .Stloc(nameScopeLoc.Local) // if({scope} != null) goto call; .Ldloc(nameScopeLoc.Local) .Brfalse(exit) .Ldloc(nameScopeLoc.Local); context.Emit(Value, codeGen, Value.Type.GetClrType()); codeGen .Ldloc(targetLoc.Local) .EmitCall(registerMethod) .MarkLabel(exit); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var rv = context.Emit(Value, codeGen, Local.Type); codeGen.Emit(OpCodes.Dup); context.StLocal(Local, codeGen); return(XamlIlNodeEmitResult.Type(0, rv.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlObjectInitializationNode init)) { return(null); } var supportInitType = context.Configuration.TypeMappings.SupportInitialize; var supportsInitialize = supportInitType != null && context.Configuration.TypeMappings.SupportInitialize .IsAssignableFrom(init.Type); if (supportsInitialize) { codeGen // We need a copy for/EndInit .Emit(OpCodes.Dup); if (!init.SkipBeginInit) { codeGen .Emit(OpCodes.Dup) .EmitCall(supportInitType.FindMethod(m => m.Name == "BeginInit")); } } var addToParentStack = context.RuntimeContext.ParentListField != null && !init.Type.IsValueType && context.GetOrCreateItem <XamlIlNeedsParentStackCache>().NeedsParentStack(node); if (addToParentStack) { using (var local = context.GetLocal(init.Type)) codeGen .Stloc(local.Local) .Ldloc(context.ContextLocal) .Ldloc(local.Local) .EmitCall(context.RuntimeContext.PushParentMethod) .Ldloc(local.Local); } context.Emit(init.Manipulation, codeGen, null); if (addToParentStack) { codeGen .Ldloc(context.ContextLocal) .EmitCall(context.RuntimeContext.PopParentMethod, true); } if (supportsInitialize) { codeGen .EmitCall(supportInitType.FindMethod(m => m.Name == "EndInit")); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { context.Emit(Value, codeGen, Method.DeclaringType); codeGen .Ldftn(Method) .Newobj(DelegateType.Constructors.FirstOrDefault(ct => ct.Parameters.Count == 2 && ct.Parameters[0].Equals(context.Configuration.WellKnownTypes.Object))); return(XamlIlNodeEmitResult.Type(0, DelegateType)); }
public virtual XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (Previous != null) { context.Emit(Previous, codeGen, Type.GetClrType()); } DoEmit(context, codeGen); return(XamlIlNodeEmitResult.Type(0, Type.GetClrType())); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlPropertyAssignmentNode an)) return null; var callOp = an.Property.Setter.IsStatic ? OpCodes.Call : OpCodes.Callvirt; context.Emit(an.Value, codeGen, an.Property.Setter.Parameters.Last()); codeGen.Emit(callOp, an.Property.Setter); return XamlIlNodeEmitResult.Void(1); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter ilgen) { if (!(node is XamlIlMarkupExtensionNode me)) { return(null); } XamlIlNeedsParentStackCache.Verify(context, node); var prop = context.ParentNodes().OfType <XamlIlPropertyAssignmentNode>().FirstOrDefault(); var needProvideValueTarget = me.ProvideValue.Parameters.Count != 0 && context.RuntimeContext.PropertyTargetObject != null && prop != null; void EmitPropertyDescriptor() { if (context.Configuration.TypeMappings.ProvideValueTargetPropertyEmitter ?.Invoke(context, ilgen, prop.Property) == true) { return; } ilgen.Ldstr(prop.Property.Name); } context.Emit(me.Value, ilgen, me.Value.Type.GetClrType()); if (me.ProvideValue.Parameters.Count > 0) { ilgen .Emit(OpCodes.Ldloc, context.ContextLocal); } if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal); EmitPropertyDescriptor(); ilgen .Stfld(context.RuntimeContext.PropertyTargetProperty); } ilgen.EmitCall(me.ProvideValue); if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal) .Ldnull() .Stfld(context.RuntimeContext.PropertyTargetProperty); } return(XamlIlNodeEmitResult.Type(0, me.ProvideValue.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlPropertyValueManipulationNode pvm)) { return(null); } codeGen.EmitCall(pvm.Property.Getter); context.Emit(pvm.Manipulation, codeGen, null); return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlPropertyValueManipulationNode pvm)) { return(null); } codeGen.Generator.Emit(pvm.Property.Getter.IsStatic ? OpCodes.Call : OpCodes.Callvirt, pvm.Property.Getter); context.Emit(pvm.Manipulation, codeGen, null); return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object); var t = Type.GetClrType(); if (t.IsValueType) { codeGen.Unbox_Any(t); } else { codeGen.Castclass(t); } return(XamlIlNodeEmitResult.Type(0, t)); }
protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property)) { throw new XamlIlLoadException( $"{Property.Name} of {(Property.Setter ?? Property.Getter).DeclaringType.GetFqn()} doesn't seem to be an AvaloniaProperty", this); } context.Emit(Value, codeGen, context.Configuration.WellKnownTypes.Object); EmitCall(context, codeGen, m => m.Name == "PropertyEquals" && m.Parameters.Count == 3 && m.Parameters[1].FullName == "Avalonia.AvaloniaProperty" && m.Parameters[2].Equals(context.Configuration.WellKnownTypes.Object)); }
void CompileBuilder(XamlIlEmitContext context) { var il = context.Emitter; // Initialize the context il .Ldarg_0(); context.RuntimeContext.Factory(il); il.Stloc(context.ContextLocal); // It might be better to save this in a closure if (context.Configuration.TypeMappings.RootObjectProvider != null) { // Attempt to get the root object from parent service provider var noRoot = il.DefineLabel(); using (var loc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) il // if(arg == null) goto noRoot; .Ldarg_0() .Brfalse(noRoot) // var loc = arg.GetService(typeof(IRootObjectProvider)) .Ldarg_0() .Ldtype(context.Configuration.TypeMappings.RootObjectProvider) .EmitCall(context.Configuration.TypeMappings.ServiceProvider .FindMethod(m => m.Name == "GetService")) .Stloc(loc.Local) // if(loc == null) goto noRoot; .Ldloc(loc.Local) .Brfalse(noRoot) // loc = ((IRootObjectProvider)loc).RootObject .Ldloc(loc.Local) .Castclass(context.Configuration.TypeMappings.RootObjectProvider) .EmitCall(context.Configuration.TypeMappings.RootObjectProvider .FindMethod(m => m.Name == "get_RootObject")) .Stloc(loc.Local) // contextLocal.RootObject = loc; .Ldloc(context.ContextLocal) .Ldloc(loc.Local) .Castclass(context.RuntimeContext.ContextType.GenericArguments[0]) .Stfld(context.RuntimeContext.RootObjectField) .MarkLabel(noRoot); } context.Emit(Value, context.Emitter, context.Configuration.WellKnownTypes.Object); il.Ret(); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var res = context.Emit(Value, codeGen, Value.Type.GetClrType()); var supportInitType = context.Configuration.TypeMappings.SupportInitialize; var supportsInitialize = supportInitType != null && context.Configuration.TypeMappings.SupportInitialize .IsAssignableFrom(Value.Type.GetClrType()); if (supportsInitialize) { codeGen .Dup() .EmitCall(supportInitType.FindMethod(m => m.Name == "BeginInit")); } return(res); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var scopeField = context.RuntimeContext.ContextType.Fields.First(f => f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName); using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) { codeGen // var target = {pop} .Stloc(targetLoc.Local) // _context.NameScope.Register(Name, target) .Ldloc(context.ContextLocal) .Ldfld(scopeField); context.Emit(Name, codeGen, Name.Type.GetClrType()); codeGen .Ldloc(targetLoc.Local) .EmitCall(_types.INameScopeRegister, true); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlManipulationGroupNode group)) { return(null); } if (group.Children.Count == 0) { codeGen.Generator.Emit(OpCodes.Pop); } else { for (var c = 0; c < group.Children.Count; c++) { if (c != group.Children.Count - 1) { codeGen.Generator.Emit(OpCodes.Dup); } context.Emit(group.Children[c], codeGen, null); } } return(XamlIlNodeEmitResult.Void); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlMethodCallBaseNode mc)) { return(null); } bool thisArgFromArgs = node is XamlIlStaticOrTargetedReturnMethodCallNode; bool expectsVoid = node is XamlIlNoReturnMethodCallNode; for (var c = 0; c < mc.Arguments.Count; c++) { var off = thisArgFromArgs ? 0 : 1; var expectedType = mc.Method.ParametersWithThis[c + off]; context.Emit(mc.Arguments[c], codeGen, expectedType); } mc.Method.Emit(context, codeGen, expectsVoid); var isVoid = mc.Method.ReturnType.Equals(context.Configuration.WellKnownTypes.Void); if (!expectsVoid && isVoid) { throw new XamlIlLoadException( $"XamlIlStaticReturnMethodCallNode expects a value while {mc.Method.Name} returns void", node); } var consumed = thisArgFromArgs ? 0 : 1; return(isVoid || expectsVoid ? XamlIlNodeEmitResult.Void(consumed) : XamlIlNodeEmitResult.Type(consumed, mc.Method.ReturnType)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen) { if (!(node is XamlIlMarkupExtensionNode me)) { return(null); } var ptype = me.Manipulation?.Parameters[0] ?? me.Property.PropertyType; var rtype = me.ProvideValue.ReturnType; context.Emit(me.Value, codeGen, me.Value.Type.GetClrType()); if (me.ProvideValue.Parameters.Count != 0) { //TODO: IProvideValueTarget codeGen.Generator .Emit(OpCodes.Ldloc, context.ContextLocal); } var resultLocal = codeGen.Generator.DefineLocal(rtype); codeGen.Generator .Emit(OpCodes.Call, me.ProvideValue) .Emit(OpCodes.Stloc, resultLocal); IXamlIlEmitter CallSetter() { if (me.Manipulation != null) { // {target}.{Property}.{Method)(res) var res = codeGen.Generator.DefineLocal(ptype); if (me.Property != null) { codeGen.Generator .Emit(OpCodes.Stloc, res) .EmitCall(me.Property.Getter) .Emit(OpCodes.Ldloc, res); } codeGen.Generator .EmitCall(me.Manipulation, true); return(codeGen.Generator); } return(codeGen.Generator.EmitCall(me.Property.Setter)); } // Now we have the value returned by markup extension in resultLocal //Simplest case: exact type match if (ptype.Equals(rtype)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal); CallSetter(); return(XamlIlNodeEmitResult.Void); } var exit = codeGen.Generator.DefineLabel(); if (ptype.IsValueType && rtype.IsValueType) { // If both are value types, try convert non-nullable to nullable if (ptype.IsNullableOf(rtype)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Newobj, ptype.Constructors.First(c => c.Parameters.Count == 1 && c.Parameters[0].Equals(rtype))); CallSetter(); return(XamlIlNodeEmitResult.Void); } } else if (rtype.IsValueType && !ptype.IsValueType) { // If target is object, simply box if (ptype.Equals(context.Configuration.WellKnownTypes.Object)) { codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Box, rtype); CallSetter(); return(XamlIlNodeEmitResult.Void); } } else if (ptype.IsValueType) { // Cast attempt only makes sense if it's an object if (rtype.Equals(context.Configuration.WellKnownTypes.Object)) { var notMatchedType = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Isinst, ptype) .Emit(OpCodes.Brfalse, notMatchedType) .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Unbox_Any, ptype); CallSetter() .Emit(OpCodes.Br, exit) .MarkLabel(notMatchedType); } } else { // if(res==null) target.Property = null; var notNull = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Brtrue, notNull) .Emit(OpCodes.Ldloc, resultLocal); CallSetter() .Emit(OpCodes.Br, exit) .MarkLabel(notNull); // if (res is T matched) target.Property = matched; var nonMatchedType = codeGen.Generator.DefineLabel(); codeGen.Generator .Emit(OpCodes.Ldloc, resultLocal) .Emit(OpCodes.Isinst, ptype) .Emit(OpCodes.Dup) .Emit(OpCodes.Brfalse, nonMatchedType); CallSetter(); codeGen.Generator.Emit(OpCodes.Br, exit) .MarkLabel(nonMatchedType) .Emit(OpCodes.Pop); } // Cast attempts have failed, call external method codeGen.Generator .Emit(OpCodes.Ldstr, me.Property?.Name) .Emit(OpCodes.Ldloc, context.ContextLocal) .Emit(OpCodes.Ldloc, resultLocal); if (rtype.IsValueType) { codeGen.Generator.Emit(OpCodes.Box, rtype); } codeGen.Generator .Emit(OpCodes.Call, context.Configuration.TypeMappings.ApplyNonMatchingMarkupExtension) .Emit(OpCodes.Br, exit); codeGen.Generator.MarkLabel(exit); return(XamlIlNodeEmitResult.Void); }
protected override void DoEmit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { context.Emit(Argument, codeGen, Type.GetClrType()); EmitCall(context, codeGen, m => m.Name == "Not" && m.Parameters.Count == 2 && m.Parameters[1].Equals(Type.GetClrType())); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlObjectInitializationNode init)) { return(null); } var supportInitType = context.Configuration.TypeMappings.SupportInitialize; var supportsInitialize = supportInitType != null && context.Configuration.TypeMappings.SupportInitialize .IsAssignableFrom(init.Type); if (supportsInitialize) { codeGen // We need a copy for/EndInit .Emit(OpCodes.Dup); if (!init.SkipBeginInit) { codeGen .Emit(OpCodes.Dup) .EmitCall(supportInitType.FindMethod(m => m.Name == "BeginInit")); } } IXamlIlType objectListType = null; var addToParentStack = context.RuntimeContext.ParentListField != null && !init.Type.IsValueType && context.GetOrCreateItem <XamlIlNeedsParentStackCache>().NeedsParentStack(node); if (addToParentStack) { objectListType = context.Configuration.TypeSystem.GetType("System.Collections.Generic.List`1") .MakeGenericType(new[] { context.Configuration.WellKnownTypes.Object }); using (var local = context.GetLocal(init.Type)) codeGen .Stloc(local.Local) .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .Ldloc(local.Local) .EmitCall(objectListType.FindMethod("Add", context.Configuration.WellKnownTypes.Void, false, context.Configuration.WellKnownTypes.Object)) .Ldloc(local.Local); } context.Emit(init.Manipulation, codeGen, null); if (addToParentStack) { codeGen .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .Ldloc(context.ContextLocal).Ldfld(context.RuntimeContext.ParentListField) .EmitCall(objectListType.FindMethod(m => m.Name == "get_Count")) .Ldc_I4(1).Emit(OpCodes.Sub) .EmitCall(objectListType.FindMethod(m => m.Name == "RemoveAt")); } if (supportsInitialize) { codeGen .EmitCall(supportInitType.FindMethod(m => m.Name == "EndInit")); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlPropertyAssignmentNode an)) { return(null); } var setters = ValidateAndGetSetters(an); for (var c = 0; c < an.Values.Count - 1; c++) { context.Emit(an.Values[c], codeGen, an.Values[c].Type.GetClrType()); } var value = an.Values.Last(); var isValueType = value.Type.GetClrType().IsValueType; // If there is only one available setter or if value is a value type, always use the first one if (setters.Count == 1 || isValueType) { var setter = an.PossibleSetters.First(); context.Emit(value, codeGen, setter.Parameters.Last()); setter.Emit(codeGen); } else { var checkedTypes = new List <IXamlIlType>(); IXamlIlLabel exit = codeGen.DefineLabel(); IXamlIlLabel next = null; var hadJumps = false; context.Emit(value, codeGen, value.Type.GetClrType()); foreach (var setter in setters) { var type = setter.Parameters.Last(); // We have already checked this type or its base type if (checkedTypes.Any(ch => ch.IsAssignableFrom(type))) { continue; } if (next != null) { codeGen.MarkLabel(next); next = null; } IXamlIlLabel Next() => next ?? (next = codeGen.DefineLabel()); var checkNext = false; if (setter.BinderParameters.AllowRuntimeNull) { checkedTypes.Add(type); } else { // Check for null; Also don't add this type to the list of checked ones because of the null check codeGen .Dup() .Brfalse(Next()); checkNext = true; } // Only do dynamic checks if we know that type is not assignable by downcast if (!type.IsAssignableFrom(value.Type.GetClrType())) { codeGen .Dup() .Isinst(type) .Brfalse(Next()); checkNext = true; } if (checkNext) { hadJumps = true; } TypeSystemHelpers.EmitConvert(context, codeGen, value, value.Type.GetClrType(), type); setter.Emit(codeGen); if (hadJumps) { codeGen.Br(exit); } if (!checkNext) { break; } } if (next != null) { codeGen.MarkLabel(next); if (setters.Any(x => !x.BinderParameters.AllowRuntimeNull)) { next = codeGen.DefineLabel(); codeGen .Dup() .Brtrue(next) .Newobj(context.Configuration.TypeSystem.GetType("System.NullReferenceException") .FindConstructor()) .Throw(); codeGen.MarkLabel(next); } codeGen .Newobj(context.Configuration.TypeSystem.GetType("System.InvalidCastException") .FindConstructor()) .Throw(); } codeGen.MarkLabel(exit); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlEmitter codeGen) { if (!(node is XamlIlMarkupExtensionNode me)) { return(null); } XamlIlNeedsParentStackCache.Verify(context, node); var ilgen = codeGen; var so = context.Configuration.WellKnownTypes.Object; var ptype = me.Manipulation?.ParametersWithThis[1] ?? me.Property.PropertyType; var rtype = me.ProvideValue?.ReturnType ?? me.Value.Type.GetClrType(); var needProvideValueTarget = me.ProvideValue != null && me.ProvideValue.Parameters.Count != 0 && context.RuntimeContext.PropertyTargetObject != null && me.Property != null; void EmitPropertyDescriptor() { if (me.Property == null) { ilgen.Ldnull(); } else if (context.Configuration.TypeMappings.ProvideValueTargetPropertyEmitter ?.Invoke(context, codeGen, me.Property) == true) { return; } else if (me.Property is XamlIlAstAttachedProperty) { ilgen.Ldtoken(me.Property.Getter ?? me.Property.Setter) .Emit(OpCodes.Box, context.Configuration.TypeSystem.GetType("System.RuntimeMethodHandle")); } else { ilgen.Ldstr(me.Property?.Name); } } using (var resultLocalContainer = context.GetLocal(rtype)) { var resultLocal = resultLocalContainer.Local; using (var targetObjectLocal = needProvideValueTarget ? context.GetLocal(so) : null) { if (needProvideValueTarget) { ilgen .Dup().Stloc(targetObjectLocal.Local); } context.Emit(me.Value, codeGen, me.Value.Type.GetClrType()); if (me.ProvideValue?.Parameters.Count > 0) { ilgen .Emit(OpCodes.Ldloc, context.ContextLocal); } if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal) .Ldloc(targetObjectLocal.Local) .Stfld(context.RuntimeContext.PropertyTargetObject) .Ldloc(context.ContextLocal); EmitPropertyDescriptor(); ilgen .Stfld(context.RuntimeContext.PropertyTargetProperty); } if (me.ProvideValue != null) { ilgen .Emit(OpCodes.Call, me.ProvideValue); } ilgen .Emit(OpCodes.Stloc, resultLocal); if (needProvideValueTarget) { ilgen .Ldloc(context.ContextLocal) .Ldnull() .Stfld(context.RuntimeContext.PropertyTargetObject) .Ldloc(context.ContextLocal) .Ldnull() .Stfld(context.RuntimeContext.PropertyTargetProperty); } } // At this point we have the target object at the top of the stack and markup extension result in resultLocal var exit = ilgen.DefineLabel(); // This is needed for custom conversions of Binding to object var customTypes = context.Configuration.TypeMappings.MarkupExtensionCustomResultTypes; // This is needed for properties that accept Binding if ( me.Property != null && context.Configuration.TypeMappings.ShouldIgnoreMarkupExtensionCustomResultForProperty != null) { customTypes = customTypes.Where(ct => !context.Configuration.TypeMappings .ShouldIgnoreMarkupExtensionCustomResultForProperty(me.Property, ct)) .ToList(); } if (customTypes.Any() && !rtype.IsValueType) { void EmitCustomActionCall() { EmitPropertyDescriptor(); codeGen .Emit(OpCodes.Ldloc, context.ContextLocal) .Emit(OpCodes.Ldloc, resultLocal); if (rtype.IsValueType) { codeGen.Emit(OpCodes.Box, rtype); } codeGen .Emit(OpCodes.Call, context.Configuration.TypeMappings.MarkupExtensionCustomResultHandler) .Emit(OpCodes.Br, exit); } // Skip conversion attempts and call custom conversion directly if (customTypes.Any(ct => ct.IsAssignableFrom(rtype))) { EmitCustomActionCall(); ilgen.MarkLabel(exit); return(XamlIlNodeEmitResult.Void(1)); } var callCustomLabel = ilgen.DefineLabel(); var afterCustomLabel = ilgen.DefineLabel(); foreach (var ct in customTypes) { codeGen .Ldloc(resultLocal) .Isinst(ct) .Brtrue(callCustomLabel); } ilgen .Br(afterCustomLabel) .MarkLabel(callCustomLabel); EmitCustomActionCall(); ilgen.MarkLabel(afterCustomLabel); } TypeSystemHelpers.EmitConvert(context, node, rtype, ptype, lda => ilgen.Emit(lda ? OpCodes.Ldloca : OpCodes.Ldloc, resultLocal)); // Call some method either on the target or on target's property if (me.Manipulation != null) { // {target}.{Property}.{Method)(res) if (me.Property != null) { using (var res = context.GetLocal(ptype)) ilgen .Emit(OpCodes.Stloc, res.Local) .EmitCall(me.Property.Getter) .Emit(OpCodes.Ldloc, res.Local); } me.Manipulation.Emit(context, ilgen, true); } // Call property setter on the target else { ilgen.EmitCall(me.Property.Setter); } ilgen.MarkLabel(exit); } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { XamlIlNeedsParentStackCache.Verify(context, this); return(context.Emit(Value, codeGen, Value.Type.GetClrType())); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { context.Emit(Value, codeGen, Value.Type.GetClrType()); context.Emit(Manipulation, codeGen, null); return(XamlIlNodeEmitResult.Void(0)); }