bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read)
        {
            System.Reflection.Emit.MethodBuilder method = ctx.GetDedicatedMethod(key, read);
            if (method == null) return false;
            using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, typeof(SubItemToken)))
            {
                Type rwType = read ? typeof(ProtoReader) : typeof(ProtoWriter);
                ctx.LoadValue(valueFrom);
                if (!read) // write requires the object for StartSubItem; read doesn't
                {
                    if (type.IsValueType) { ctx.LoadNullRef(); }
                    else { ctx.CopyValue(); }
                }
                ctx.LoadReaderWriter();
                ctx.EmitCall(rwType.GetMethod("StartSubItem"));
                ctx.StoreValue(token);

                // note: value already on the stack
                ctx.LoadReaderWriter();                
                ctx.EmitCall(method);
                // handle inheritance (we will be calling the *base* version of things,
                // but we expect Read to return the "type" type)
                if (read && type != method.ReturnType) ctx.Cast(this.type);
                ctx.LoadValue(token);
                
                ctx.LoadReaderWriter();
                ctx.EmitCall(rwType.GetMethod("EndSubItem"));
            }            
            return true;
        }
        protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
        {
            // int i and T[] arr
            using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom))
            using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, typeof(int)))
            {
                if (packedFieldNumber > 0)
                {
                    Compiler.CodeLabel allDone = ctx.DefineLabel();
                    ctx.LoadLength(arr, false);
                    ctx.BranchIfFalse(allDone, false);

                    ctx.LoadValue(packedFieldNumber);
                    ctx.LoadValue((int)WireType.String);
                    ctx.LoadReaderWriter();
                    ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteFieldHeader"));

                    ctx.LoadValue(arr);
                    ctx.LoadReaderWriter();
                    ctx.EmitCall(typeof(ProtoWriter).GetMethod("StartSubItem"));
                    using (Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken))) { 
                        ctx.StoreValue(token);

                        ctx.LoadValue(packedFieldNumber);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(typeof(ProtoWriter).GetMethod("SetPackedField"));

                        EmitWriteArrayLoop(ctx, i, arr);

                        ctx.LoadValue(token);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(typeof(ProtoWriter).GetMethod("EndSubItem"));
                    }
                    ctx.MarkLabel(allDone);
                }
                else
                {
                    EmitWriteArrayLoop(ctx, i, arr);    
                }
            }
        }
Пример #3
0
        protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
        {
            // int i and T[] arr
            using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom))
            using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))))
            {
                bool writePacked = (options & OPTIONS_WritePacked) != 0;
                using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)
                {
                    Type mappedWriter = ctx.MapType(typeof (ProtoWriter));
                    if (writePacked)
                    {
                        ctx.LoadValue(fieldNumber);
                        ctx.LoadValue((int)WireType.String);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader"));

                        ctx.LoadValue(arr);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(mappedWriter.GetMethod("StartSubItem"));
                        ctx.StoreValue(token);

                        ctx.LoadValue(fieldNumber);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(mappedWriter.GetMethod("SetPackedField"));
                    }
                    EmitWriteArrayLoop(ctx, i, arr);

                    if (writePacked)
                    {
                        ctx.LoadValue(token);
                        ctx.LoadReaderWriter();
                        ctx.EmitCall(mappedWriter.GetMethod("EndSubItem"));
                    }
                }
            }
        }
        protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
        {
            Type listType;
#if NO_GENERICS
            listType = typeof(BasicList);
#else
            listType = typeof(System.Collections.Generic.List<>).MakeGenericType(itemType);
#endif
            using (Compiler.Local oldArr = ctx.GetLocalWithValue(ExpectedType, valueFrom))
            using (Compiler.Local newArr = new Compiler.Local(ctx, ExpectedType))
            using (Compiler.Local list = new Compiler.Local(ctx, listType))
            {
                ctx.EmitCtor(listType);
                ctx.StoreValue(list);
                ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType);

                // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList
                using(Compiler.Local oldLen = new ProtoBuf.Compiler.Local(ctx, typeof(int))) {
                    ctx.LoadLength(oldArr, true);
                    ctx.CopyValue();
                    ctx.StoreValue(oldLen);
                    ctx.LoadAddress(list, listType);
                    ctx.LoadValue(listType.GetProperty("Count"));
                    ctx.Add();
                    ctx.CreateArray(itemType, null); // length is on the stack
                    ctx.StoreValue(newArr);

                    ctx.LoadValue(oldLen);
                    Compiler.CodeLabel nothingToCopy = ctx.DefineLabel();
                    ctx.BranchIfFalse(nothingToCopy, true);
                    ctx.LoadValue(oldArr);
                    ctx.LoadValue(newArr);
                    ctx.LoadValue(oldLen);
                    Type[] argTypes = new Type[] {typeof(Array), typeof(int)};
                    ctx.EmitCall(ExpectedType.GetMethod("CopyTo",argTypes));
                    ctx.MarkLabel(nothingToCopy);

                    ctx.LoadValue(list);
                    ctx.LoadValue(newArr);
                    ctx.LoadValue(oldLen);
                    argTypes[0] = ExpectedType; // // prefer: CopyTo(T[], int)
                    MethodInfo copyTo = listType.GetMethod("CopyTo", argTypes);
                    if (copyTo == null)
                    { // fallback: CopyTo(Array, int)
                        argTypes[1] = typeof(Array);
                        copyTo = listType.GetMethod("CopyTo", argTypes);
                    }
                    ctx.EmitCall(copyTo);
                }
                ctx.LoadValue(newArr);
            }


        }
Пример #5
0
        protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
        {
            Type listType;

#if NO_GENERICS
            listType = typeof(BasicList);
#else
            listType = ctx.MapType(typeof(System.Collections.Generic.List <>)).MakeGenericType(itemType);
#endif
            Type expected = ExpectedType;
            using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null)
                using (Compiler.Local newArr = new Compiler.Local(ctx, expected))
                    using (Compiler.Local list = new Compiler.Local(ctx, listType))
                    {
                        ctx.EmitCtor(listType);
                        ctx.StoreValue(list);
                        ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false);

                        // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList
                        using (Compiler.Local oldLen = AppendToCollection ? new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) {
                            Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) };

                            if (AppendToCollection)
                            {
                                ctx.LoadLength(oldArr, true);
                                ctx.CopyValue();
                                ctx.StoreValue(oldLen);

                                ctx.LoadAddress(list, listType);
                                ctx.LoadValue(listType.GetProperty("Count"));
                                ctx.Add();
                                ctx.CreateArray(itemType, null); // length is on the stack
                                ctx.StoreValue(newArr);

                                ctx.LoadValue(oldLen);
                                Compiler.CodeLabel nothingToCopy = ctx.DefineLabel();
                                ctx.BranchIfFalse(nothingToCopy, true);
                                ctx.LoadValue(oldArr);
                                ctx.LoadValue(newArr);
                                ctx.LoadValue(0); // index in target

                                ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args));
                                ctx.MarkLabel(nothingToCopy);

                                ctx.LoadValue(list);
                                ctx.LoadValue(newArr);
                                ctx.LoadValue(oldLen);
                            }
                            else
                            {
                                ctx.LoadAddress(list, listType);
                                ctx.LoadValue(listType.GetProperty("Count"));
                                ctx.CreateArray(itemType, null);
                                ctx.StoreValue(newArr);

                                ctx.LoadAddress(list, listType);
                                ctx.LoadValue(newArr);
                                ctx.LoadValue(0);
                            }

                            copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int)
                            MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
                            if (copyTo == null)
                            { // fallback: CopyTo(Array, int)
                                copyToArrayInt32Args[1] = ctx.MapType(typeof(Array));
                                copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
                            }
                            ctx.EmitCall(copyTo);
                        }
                        ctx.LoadValue(newArr);
                    }
        }
Пример #6
0
        protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.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;
            bool castListForAdd = !add.DeclaringType.IsAssignableFrom(declaredType);

            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);
                    }

                    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);
                        }
                    }
                }
        }
Пример #7
0
        protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.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, ExpectedType);
                        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, enumeratorType);
                            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, enumeratorType);
                            ctx.BranchIfTrue(body, false);
                        }

                        if (writePacked)
                        {
                            ctx.LoadValue(token);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem"));
                        }
                    }
            }
        }
Пример #8
0
        bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read)
        {
#if SILVERLIGHT
            return false;
#else
            MethodBuilder method = ctx.GetDedicatedMethod(key, read);
            if (method == null) return false;

            using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))))
            {
                Type rwType = ctx.MapType(read ? typeof(ProtoReader) : typeof(ProtoWriter));
                ctx.LoadValue(valueFrom);
                if (!read) // write requires the object for StartSubItem; read doesn't
                {  // (if recursion-check is disabled [subtypes] then null is fine too)
                    if (type.IsValueType || !recursionCheck) { ctx.LoadNullRef(); }
                    else { ctx.CopyValue(); }
                }
                ctx.LoadReaderWriter();
                ctx.EmitCall(rwType.GetMethod("StartSubItem"));
                ctx.StoreValue(token);

                // note: value already on the stack
                ctx.LoadReaderWriter();                
                ctx.EmitCall(method);
                // handle inheritance (we will be calling the *base* version of things,
                // but we expect Read to return the "type" type)
                if (read && type != method.ReturnType) ctx.Cast(this.type);
                ctx.LoadValue(token);
                
                ctx.LoadReaderWriter();
                ctx.EmitCall(rwType.GetMethod("EndSubItem"));
            }            
            return true;
#endif
        }
Пример #9
0
        private bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read)
        {
            MethodBuilder method = ctx.GetDedicatedMethod(key, read);

            if (method == null)
            {
                return(false);
            }

            using (Compiler.Local val = ctx.GetLocalWithValue(type, valueFrom))
                using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, typeof(SubItemToken)))
                {
                    Type rwType = read ? typeof(ProtoReader) : typeof(ProtoWriter);

                    if (read)
                    {
                        ctx.LoadReader(true);
                    }
                    else
                    {
                        // write requires the object for StartSubItem; read doesn't
                        // (if recursion-check is disabled [subtypes] then null is fine too)
                        if (Helpers.IsValueType(type) || !recursionCheck)
                        {
                            ctx.LoadNullRef();
                        }
                        else
                        {
                            ctx.LoadValue(val);
                        }
                        ctx.LoadWriter(true);
                    }
                    ctx.EmitCall(Helpers.GetStaticMethod(rwType, "StartSubItem",
                                                         read ? ProtoReader.State.ReaderStateTypeArray : new Type[] { typeof(object), rwType, ProtoWriter.ByRefStateType }));
                    ctx.StoreValue(token);

                    if (read)
                    {
                        ctx.LoadReader(true);
                        ctx.LoadValue(val);
                    }
                    else
                    {
                        ctx.LoadWriter(true);
                        ctx.LoadValue(val);
                    }
                    ctx.EmitCall(method);
                    // handle inheritance (we will be calling the *base* version of things,
                    // but we expect Read to return the "type" type)
                    if (read && type != method.ReturnType)
                    {
                        ctx.Cast(type);
                    }
                    ctx.LoadValue(token);
                    if (read)
                    {
                        ctx.LoadReader(true);
                        ctx.EmitCall(Helpers.GetStaticMethod(rwType, "EndSubItem",
                                                             new Type[] { typeof(SubItemToken), rwType, ProtoReader.State.ByRefStateType }));
                    }
                    else
                    {
                        ctx.LoadWriter(true);
                        ctx.EmitCall(ProtoWriter.GetStaticMethod("EndSubItem"));
                    }
                }
            return(true);
        }
Пример #10
0
        bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read)

        {
#if SILVERLIGHT
            return(false);
#else
            MethodBuilder method = ctx.GetDedicatedMethod(key, read);

            if (method == null)
            {
                return(false);
            }



            using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))))

            {
                Type rwType = ctx.MapType(read ? typeof(ProtoReader) : typeof(ProtoWriter));

                ctx.LoadValue(valueFrom);

                if (!read) // write requires the object for StartSubItem; read doesn't

                {          // (if recursion-check is disabled [subtypes] then null is fine too)
                    if (type.IsValueType || !recursionCheck)
                    {
                        ctx.LoadNullRef();
                    }

                    else
                    {
                        ctx.CopyValue();
                    }
                }

                ctx.LoadReaderWriter();

                ctx.EmitCall(rwType.GetMethod("StartSubItem"));

                ctx.StoreValue(token);



                // note: value already on the stack

                ctx.LoadReaderWriter();

                ctx.EmitCall(method);

                // handle inheritance (we will be calling the *base* version of things,

                // but we expect Read to return the "type" type)

                if (read && type != method.ReturnType)
                {
                    ctx.Cast(this.type);
                }

                ctx.LoadValue(token);



                ctx.LoadReaderWriter();

                ctx.EmitCall(rwType.GetMethod("EndSubItem"));
            }

            return(true);
#endif
        }
Пример #11
0
        protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)

        {
            // int i and T[] arr

            using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom))

                using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))))

                {
                    bool writePacked = (options & OPTIONS_WritePacked) != 0;

                    using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)

                    {
                        Type mappedWriter = ctx.MapType(typeof(ProtoWriter));

                        if (writePacked)

                        {
                            ctx.LoadValue(fieldNumber);

                            ctx.LoadValue((int)WireType.String);

                            ctx.LoadReaderWriter();

                            ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader"));



                            ctx.LoadValue(arr);

                            ctx.LoadReaderWriter();

                            ctx.EmitCall(mappedWriter.GetMethod("StartSubItem"));

                            ctx.StoreValue(token);



                            ctx.LoadValue(fieldNumber);

                            ctx.LoadReaderWriter();

                            ctx.EmitCall(mappedWriter.GetMethod("SetPackedField"));
                        }

                        EmitWriteArrayLoop(ctx, i, arr);



                        if (writePacked)

                        {
                            ctx.LoadValue(token);

                            ctx.LoadReaderWriter();

                            ctx.EmitCall(mappedWriter.GetMethod("EndSubItem"));
                        }
                    }
                }
        }