Esempio n. 1
0
        internal static void EmitReadList(MuffinProtoBuf.Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, WireType packedWireType, bool castListForAdd)
        {
            using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int))))
            {
                Compiler.CodeLabel readPacked = packedWireType == WireType.None ? new Compiler.CodeLabel() : ctx.DefineLabel();
                if (packedWireType != WireType.None)
                {
                    ctx.LoadReaderWriter();
                    ctx.LoadValue(typeof(ProtoReader).GetProperty("WireType"));
                    ctx.LoadValue((int)WireType.String);
                    ctx.BranchIfEqual(readPacked, false);
                }
                ctx.LoadReaderWriter();
                ctx.LoadValue(typeof(ProtoReader).GetProperty("FieldNumber"));
                ctx.StoreValue(fieldNumber);

                Compiler.CodeLabel @continue = ctx.DefineLabel();
                ctx.MarkLabel(@continue);

                EmitReadAndAddItem(ctx, list, tail, add, castListForAdd);

                ctx.LoadReaderWriter();
                ctx.LoadValue(fieldNumber);
                ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("TryReadFieldHeader"));
                ctx.BranchIfTrue(@continue, false);

                if (packedWireType != WireType.None)
                {
                    Compiler.CodeLabel allDone = ctx.DefineLabel();
                    ctx.Branch(allDone, false);
                    ctx.MarkLabel(readPacked);

                    ctx.LoadReaderWriter();
                    ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem"));

                    Compiler.CodeLabel testForData = ctx.DefineLabel(), noMoreData = ctx.DefineLabel();
                    ctx.MarkLabel(testForData);
                    ctx.LoadValue((int)packedWireType);
                    ctx.LoadReaderWriter();
                    ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("HasSubValue"));
                    ctx.BranchIfFalse(noMoreData, false);

                    EmitReadAndAddItem(ctx, list, tail, add, castListForAdd);
                    ctx.Branch(testForData, false);

                    ctx.MarkLabel(noMoreData);
                    ctx.LoadReaderWriter();
                    ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem"));
                    ctx.MarkLabel(allDone);
                }
            }
        }
Esempio n. 2
0
        protected override void EmitWrite(MuffinProtoBuf.Compiler.CompilerContext ctx, MuffinProtoBuf.Compiler.Local valueFrom)
        {
            using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom))
            {
                MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(ctx.Model, out moveNext, out current);
                Helpers.DebugAssert(moveNext != null);
                Helpers.DebugAssert(current != null);
                Helpers.DebugAssert(getEnumerator != null);
                Type enumeratorType = getEnumerator.ReturnType;
                bool writePacked    = WritePacked;
                using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType))
                    using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)
                    {
                        if (writePacked)
                        {
                            ctx.LoadValue(fieldNumber);
                            ctx.LoadValue((int)WireType.String);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader"));

                            ctx.LoadValue(list);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem"));
                            ctx.StoreValue(token);

                            ctx.LoadValue(fieldNumber);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("SetPackedField"));
                        }

                        ctx.LoadAddress(list, ExpectedType);
                        ctx.EmitCall(getEnumerator);
                        ctx.StoreValue(iter);
                        using (ctx.Using(iter))
                        {
                            Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel();
                            ctx.Branch(next, false);

                            ctx.MarkLabel(body);

                            ctx.LoadAddress(iter, enumeratorType);
                            ctx.EmitCall(current);
                            Type itemType = Tail.ExpectedType;
                            if (itemType != ctx.MapType(typeof(object)) && current.ReturnType == ctx.MapType(typeof(object)))
                            {
                                ctx.CastFromObject(itemType);
                            }
                            Tail.EmitWrite(ctx, null);

                            ctx.MarkLabel(@next);
                            ctx.LoadAddress(iter, enumeratorType);
                            ctx.EmitCall(moveNext);
                            ctx.BranchIfTrue(body, false);
                        }

                        if (writePacked)
                        {
                            ctx.LoadValue(token);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem"));
                        }
                    }
            }
        }
Esempio n. 3
0
        protected override void EmitRead(MuffinProtoBuf.Compiler.CompilerContext ctx, MuffinProtoBuf.Compiler.Local valueFrom)
        {
            /* This looks more complex than it is. Look at the non-compiled Read to
             * see what it is trying to do, but note that it needs to cope with a
             * few more scenarios. Note that it picks the **most specific** Add,
             * unlike the runtime version that uses IList when possible. The core
             * is just a "do {list.Add(readValue())} while {thereIsMore}"
             *
             * The complexity is due to:
             *  - value types vs reference types (boxing etc)
             *  - initialization if we need to pass in a value to the tail
             *  - handling whether or not the tail *returns* the value vs updates the input
             */
            bool returnList = ReturnList;

            using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : new Compiler.Local(ctx, declaredType))
                using (Compiler.Local origlist = (returnList && AppendToCollection) ? new Compiler.Local(ctx, ExpectedType) : null)
                {
                    if (!AppendToCollection)
                    { // always new
                        ctx.LoadNullRef();
                        ctx.StoreValue(list);
                    }
                    else if (returnList)
                    { // need a copy
                        ctx.LoadValue(list);
                        ctx.StoreValue(origlist);
                    }
                    if (concreteType != null)
                    {
                        ctx.LoadValue(list);
                        Compiler.CodeLabel notNull = ctx.DefineLabel();
                        ctx.BranchIfTrue(notNull, true);
                        ctx.EmitCtor(concreteType);
                        ctx.StoreValue(list);
                        ctx.MarkLabel(notNull);
                    }

                    bool castListForAdd = !add.DeclaringType.IsAssignableFrom(declaredType);
                    EmitReadList(ctx, list, Tail, add, packedWireType, castListForAdd);

                    if (returnList)
                    {
                        if (AppendToCollection)
                        {
                            // remember ^^^^ we had a spare copy of the list on the stack; now we'll compare
                            ctx.LoadValue(origlist);
                            ctx.LoadValue(list); // [orig] [new-value]
                            Compiler.CodeLabel sameList = ctx.DefineLabel(), allDone = ctx.DefineLabel();
                            ctx.BranchIfEqual(sameList, true);
                            ctx.LoadValue(list);
                            ctx.Branch(allDone, true);
                            ctx.MarkLabel(sameList);
                            ctx.LoadNullRef();
                            ctx.MarkLabel(allDone);
                        }
                        else
                        {
                            ctx.LoadValue(list);
                        }
                    }
                }
        }