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));
            }
Пример #2
0
        public void Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen, bool swallowResult)
        {
            int firstCast = -1;

            for (var c = ParametersWithThis.Count - 1; c >= 0; c--)
            {
                if (!_method.ParametersWithThis[c].Equals(ParametersWithThis[c]))
                {
                    firstCast = c;
                }
            }

            if (firstCast != -1)
            {
                var locals = new Stack <XamlIlEmitContext.PooledLocal>();
                for (var c = ParametersWithThis.Count - 1; c >= firstCast; c--)
                {
                    codeGen.Castclass(ParametersWithThis[c]);
                    if (c > firstCast)
                    {
                        var l = context.GetLocal(ParametersWithThis[c]);
                        codeGen.Stloc(l.Local);
                        locals.Push(l);
                    }
                }

                while (locals.Count != 0)
                {
                    using (var l = locals.Pop())
                        codeGen.Ldloc(l.Local);
                }
            }

            _method.Emit(context, codeGen, swallowResult);
        }
        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));
        }
Пример #4
0
        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();
        }
Пример #5
0
        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));
        }
Пример #6
0
 public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what,
                                IXamlIlType to, Func <bool, IXamlIlEmitter> ld)
 {
     if (what.Equals(to))
     {
         ld(false);
     }
     else if (what == XamlIlPseudoType.Null)
     {
         if (to.IsValueType)
         {
             if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true)
             {
                 using (var loc = context.GetLocal(to))
                     ld(false)
                     .Pop()
                     .Ldloca(loc.Local)
                     .Emit(OpCodes.Initobj, to)
                     .Ldloc(loc.Local);
             }
             else
             {
                 throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node);
             }
         }
         else
         {
             ld(false);
         }
     }
     else if (what.IsValueType && to.IsValueType)
     {
         if (to.IsNullableOf(what))
         {
             ld(false).Emit(OpCodes.Newobj,
                            to.Constructors.First(c =>
                                                  c.Parameters.Count == 1 && c.Parameters[0].Equals(what)));
         }
         else if (what.IsNullableOf(what))
         {
             ld(true)
             .EmitCall(what.FindMethod(m => m.Name == "get_Value"));
         }
         else
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
     }
     else if (!to.IsValueType && what.IsValueType)
     {
         if (!to.IsAssignableFrom(what))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
         ld(false).Box(what);
     }
     else if (to.IsValueType && !what.IsValueType)
     {
         if (!(what.Namespace == "System" && what.Name == "Object"))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
         ld(false).Unbox_Any(to);
     }
     else
     {
         if (to.IsAssignableFrom(what))
         {
             // Downcast, always safe
             ld(false);
         }
         else if (what.IsInterface || what.IsAssignableFrom(to))
         {
             // Upcast or cast from interface, might throw InvalidCastException
             ld(false).Emit(OpCodes.Castclass, to);
         }
         else
         {
             // Types are completely unrelated, e. g. string to List<int> conversion attempt
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
     }
 }
Пример #7
0
        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));
        }
Пример #8
0
        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));
        }