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)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var next = codeGen.DefineLabel(); var scopeField = context.RuntimeContext.ContextType.Fields.First(f => f.Name == AvaloniaXamlIlLanguage.ContextNameScopeFieldName); using (var local = codeGen.LocalsPool.GetLocal(_types.StyledElement)) { codeGen .Isinst(_types.StyledElement) .Dup() .Stloc(local.Local) .Brfalse(next) .Ldloc(local.Local) .Ldloc(context.ContextLocal) .Ldfld(scopeField) .EmitCall(_types.NameScopeSetNameScope, true) .MarkLabel(next) .Ldloc(context.ContextLocal) .Ldfld(scopeField) .EmitCall(_types.INameScopeComplete, true); } return(XamlIlNodeEmitResult.Void(1)); }
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(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(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 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(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, 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, IXamlIlEmitter codeGen) { if (!(node is XamlIlManipulationGroupNode group)) { return(null); } if (group.Children.Count == 0) { codeGen.Emit(OpCodes.Pop); } else { for (var c = 0; c < group.Children.Count; c++) { if (c != group.Children.Count - 1) { codeGen.Emit(OpCodes.Dup); } context.Emit(group.Children[c], codeGen, null); } } return(XamlIlNodeEmitResult.Void(1)); }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) { context.Emit(Value, codeGen, Value.Type.GetClrType()); context.Emit(Manipulation, codeGen, null); return(XamlIlNodeEmitResult.Void(0)); }
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 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 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)); }