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 EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (Compiler.Local oldList = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : null)
            using(Compiler.Local builder = new Compiler.Local(ctx, builderFactory.ReturnType))
            {
                ctx.EmitCall(builderFactory);
                ctx.StoreValue(builder);

                if(AppendToCollection)
                {
                    Compiler.CodeLabel done = ctx.DefineLabel();
                    if(!ExpectedType.IsValueType)
                    {
                        ctx.LoadValue(oldList);
                        ctx.BranchIfFalse(done, false); // old value null; nothing to add
                    }
                    PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false);
                    if(prop == null) prop = Helpers.GetProperty(ExpectedType, "Count", false);
#if !NO_GENERICS
                    if (prop == null) prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false);
#endif
                    ctx.LoadAddress(oldList, oldList.Type);
                    ctx.EmitCall(Helpers.GetGetMethod(prop, false, false));
                    ctx.BranchIfFalse(done, false); // old list is empty; nothing to add

                    Type voidType = ctx.MapType(typeof(void));
                    if(addRange != null)
                    {
                        ctx.LoadValue(builder);
                        ctx.LoadValue(oldList);
                        ctx.EmitCall(addRange);
                        if (addRange.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue();
                    }
                    else
                    {
                        // loop and call Add repeatedly
                        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;
                        using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType))
                        {
                            ctx.LoadAddress(oldList, 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(builder, builder.Type);
                                ctx.LoadAddress(iter, enumeratorType);                                
                                ctx.EmitCall(current);
                                ctx.EmitCall(add);
                                if (add.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue();

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


                    ctx.MarkLabel(done);
                }

                EmitReadList(ctx, builder, Tail, add, packedWireType, false);

                ctx.LoadAddress(builder, builder.Type);
                ctx.EmitCall(finish);
                if(ExpectedType != finish.ReturnType)
                {
                    ctx.Cast(ExpectedType);
                }
            }
        }
예제 #3
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
        }
예제 #4
0
        private void WriteFieldHandler(
            Compiler.CompilerContext ctx, Type expected, Compiler.Local loc,
            Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer)
        {
            ctx.MarkLabel(handler);
            if (serializer.ExpectedType == forType) {
                EmitCreateIfNull(ctx, expected, loc);
                serializer.EmitRead(ctx, loc);
            }
            else {
                ctx.LoadValue(loc);
                ctx.Cast(serializer.ExpectedType);
                serializer.EmitRead(ctx, null);
            }

            if (serializer.ReturnsValue)
            {   // update the variable
                ctx.StoreValue(loc);
            }
            ctx.Branch(@continue, false); // "continue"
        }
예제 #5
0
        private void EmitCreateIfNull(Compiler.CompilerContext ctx, Type type, Compiler.Local storage)
        {
            Helpers.DebugAssert(storage != null);
            if (!type.IsValueType)
            {
                Compiler.CodeLabel afterNullCheck = ctx.DefineLabel();
                ctx.LoadValue(storage);
                ctx.BranchIfTrue(afterNullCheck, true);

                // different ways of creating a new instance
                bool callNoteObject = true;
                if (!useConstructor)
                {   // DataContractSerializer style
                    ctx.LoadValue(constructType);
                    ctx.EmitCall(typeof(BclHelpers).GetMethod("GetUninitializedObject"));
                    ctx.Cast(forType);
                }
                else if (constructType.IsClass && hasConstructor)
                {   // XmlSerializer style
                    ctx.EmitCtor(constructType);
                }
                else
                {
                    ctx.LoadValue(type);
                    ctx.EmitCall(typeof(TypeModel).GetMethod("ThrowCannotCreateInstance",
                        BindingFlags.Static | BindingFlags.Public));
                    ctx.LoadNullRef();
                    callNoteObject = false;
                }
                if (callNoteObject)
                {
                // track root object creation
                ctx.CopyValue();
                ctx.LoadReaderWriter();
                ctx.EmitCall(typeof(ProtoReader).GetMethod("NoteObject",
                        BindingFlags.Static | BindingFlags.Public));
                }
                if (baseCtorCallbacks != null) {
                    for (int i = 0; i < baseCtorCallbacks.Length; i++) {
                        EmitInvokeCallback(ctx, baseCtorCallbacks[i]);
                    }
                }
                if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize);
                ctx.StoreValue(storage);
                ctx.MarkLabel(afterNullCheck);
            }
        }
        private void EmitCreateIfNull(Compiler.CompilerContext ctx, Type type, Compiler.Local storage)
        {
            Helpers.DebugAssert(storage != null);
            if (!type.IsValueType)
            {
                Compiler.CodeLabel afterNullCheck = ctx.DefineLabel();
                ctx.LoadValue(storage);
                ctx.BranchIfTrue(afterNullCheck, true);

                // different ways of creating a new instance
                if (!useConstructor)
                {   // DataContractSerializer style
                    ctx.LoadValue(forType);
                    ctx.EmitCall(typeof(BclHelpers).GetMethod("GetUninitializedObject"));
                    ctx.Cast(forType);
                } else if (type.IsClass && !type.IsAbstract && (
                    (type.GetConstructor(
                    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
                    null, Helpers.EmptyTypes, null)) != null))
                {   // XmlSerializer style
                    ctx.EmitCtor(type);
                }
                else
                {
                    ctx.LoadValue(type);
                    ctx.EmitCall(typeof(TypeModel).GetMethod("ThrowCannotCreateInstance",
                        BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
                    ctx.LoadNullRef();
                }
                if (baseCtorCallbacks != null) {
                    for (int i = 0; i < baseCtorCallbacks.Length; i++) {
                        EmitInvokeCallback(ctx, baseCtorCallbacks[i]);
                    }
                }
                if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize);
                ctx.StoreValue(storage);
                ctx.MarkLabel(afterNullCheck);
            }
        }