Beispiel #1
0
        public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var g = ctx.G;

                g.Writer.ExpectRoot();
                if (_protoCompatibility)
                {
                    _serializer.EmitWrite(ctx, valueFrom);
                    return;
                }

                using (var rootToken = ctx.Local(typeof(SubItemToken)))
                    using (var typeKey = ctx.Local(typeof(int)))
                        using (var obj = ctx.Local(typeof(object)))
                            using (var refKey = ctx.Local(typeof(int)))
                            {
                                g.Assign(rootToken, g.WriterFunc.StartSubItem(null, false));
                                g.Writer.WriteFieldHeaderBegin(CurrentFormatVersion);
                                _serializer.EmitWrite(ctx, valueFrom);
                                g.While(g.StaticFactory.Invoke(typeof(ProtoWriter), nameof(ProtoWriter.TryGetNextLateReference), typeKey, obj, refKey, g.ArgReaderWriter()));
                                {
                                    g.Writer.WriteFieldHeaderBegin(refKey.AsOperand + 1);
                                    g.Writer.WriteRecursionSafeObject(obj, typeKey);
                                }
                                g.End();
                                g.Writer.EndSubItem(rootToken);
                            }
            }
        }
        public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var g = ctx.G;
                using (Compiler.Local value = ctx.GetLocalWithValue(_ctor.DeclaringType, valueFrom))
                    using (Compiler.Local token = ctx.Local(typeof(SubItemToken)))
                    {
                        g.Assign(token, g.WriterFunc.StartSubItem(value, _prefixLength));
                        for (int i = 0; i < _tails.Length; i++)
                        {
                            Type type = GetMemberType(i);
                            ctx.LoadAddress(value, ExpectedType);
                            switch (_members[i].Member.MemberType)
                            {
                            case MemberTypes.Field:
                                ctx.LoadValue((FieldInfo)_members[i].Member);
                                break;

                            case MemberTypes.Property:
                                ctx.LoadValue((PropertyInfo)_members[i].Member);
                                break;
                            }
                            ctx.LoadValue(i + 1);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod(nameof(ProtoWriter.WriteFieldHeaderBegin)));
                            ctx.WriteNullCheckedTail(type, _tails[i], null, true);
                        }
                        g.Writer.EndSubItem(token);
                    }
            }
        }
Beispiel #3
0
        private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var  g = ctx.G;
                Type nullableUnderlying = Helpers.GetNullableUnderlyingType(ExpectedType);

                if (nullableUnderlying != null)
                {
                    using (var loc = ctx.Local(ExpectedType))
                    {
                        // we another for null check
                        ctx.G.Assign(loc, g.GetStackValueOperand(ExpectedType));
                        g.If(loc.AsOperand.Property("HasValue"));

                        // unwrap value
                        g.LeaveNextReturnOnStack();
                        g.Eval(loc.AsOperand.Property("Value"));
                    }
                }

                EmitBranchIfDefaultValue_Switch(ctx, label);

                if (nullableUnderlying != null)
                {
                    g.End();
                }
            }
        }
        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var g = ctx.G;
                using (var value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) // overwriteList ? null : value
                    using (var result = ctx.Local(ExpectedType))
                    {
                        g.Assign(result, g.ReaderFunc.AppendBytes(value));
                        if (!value.IsNullRef())
                        {
                            g.If(value.AsOperand == null);
                        }
                        {
                            //if (overwriteList || value == null)
                            g.Reader.NoteObject(result);
                        }
                        if (!value.IsNullRef())
                        {
                            g.End();
                        }

                        ctx.LoadValue(result);
                    }
            }
        }
Beispiel #5
0
        public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var g = ctx.G;

                g.Reader.ExpectRoot();
                if (_protoCompatibility)
                {
                    _serializer.EmitRead(ctx, _serializer.RequiresOldValue ? valueFrom : null);
                    return;
                }

                using (var rootToken = ctx.Local(typeof(SubItemToken)))
                    using (var typeKey = ctx.Local(typeof(int)))
                        using (var obj = ctx.Local(typeof(object)))
                            using (var formatVersion = ctx.Local(typeof(int)))
                                using (var expectedRefKey = ctx.Local(typeof(int)))
                                    using (var actualRefKey = ctx.Local(typeof(int)))
                                        using (var value = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                                        {
                                            g.Assign(rootToken, g.ReaderFunc.StartSubItem());
                                            g.Assign(formatVersion, g.ReaderFunc.ReadFieldHeader_int());
                                            g.If(formatVersion.AsOperand != CurrentFormatVersion);
                                            {
                                                g.ThrowProtoException("Wrong format version, required " + CurrentFormatVersion + " but actual " + formatVersion.AsOperand);
                                            }
                                            g.End();
                                            _serializer.EmitRead(ctx, _serializer.RequiresOldValue ? value : null);
                                            if (_serializer.EmitReadReturnsValue)
                                            {
                                                g.Assign(value, g.GetStackValueOperand(ExpectedType));
                                            }

                                            g.While(g.StaticFactory.Invoke(typeof(ProtoReader), nameof(ProtoReader.TryGetNextLateReference), typeKey, obj, expectedRefKey, g.ArgReaderWriter()));
                                            {
                                                g.DoWhile();
                                                {
                                                    g.Assign(actualRefKey, g.ReaderFunc.ReadFieldHeader_int() - 1);
                                                    g.If(actualRefKey.AsOperand != expectedRefKey.AsOperand);
                                                    {
                                                        g.If(actualRefKey.AsOperand <= -1);
                                                        {
                                                            g.ThrowProtoException("Expected field for late reference");
                                                        }
                                                        g.End();
                                                        g.If(actualRefKey.AsOperand > expectedRefKey.AsOperand);
                                                        {
                                                            g.ThrowProtoException("Mismatched order of late reference objects");
                                                        }
                                                        g.End();
                                                        g.Reader.SkipField();
                                                    }
                                                    g.End();
                                                }
                                                g.EndDoWhile(actualRefKey.AsOperand < expectedRefKey.AsOperand);
                                                g.If(!g.StaticFactory.InvokeReferenceEquals(g.ReaderFunc.ReadObject(obj, typeKey), obj));
                                                {
                                                    g.ThrowProtoException("Late reference changed during deserializing");
                                                }
                                                g.End();
                                            }
                                            g.End();
                                            g.Reader.EndSubItem(rootToken);

                                            if (EmitReadReturnsValue)
                                            {
                                                ctx.LoadValue(value);
                                            }
                                        }
            }
        }
Beispiel #6
0
        protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                using (Compiler.Local oldValue = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                {
                    Compiler.Local tempLocal = null;
                    Compiler.Local valueForTail;
                    Debug.Assert(Tail.RequiresOldValue || Tail.EmitReadReturnsValue);
                    if (Tail.RequiresOldValue)
                    {
                        if (_expectedType.IsValueType)
                        {
                            tempLocal = ctx.Local(Tail.ExpectedType);
                            ctx.LoadAddress(oldValue, _expectedType);
                            ctx.EmitCall(_expectedType.GetMethod("GetValueOrDefault", Helpers.EmptyTypes));
                            ctx.StoreValue(tempLocal);
                            valueForTail = tempLocal;
                        }
                        else
                        {
                            valueForTail = oldValue;
                        }
                    }
                    else
                    {
                        valueForTail = null;
                    }

                    // valueForTail contains:
                    // null: when not required old value
                    // oldValue local: when reference type
                    // tempLocal: when nullable value type

                    Tail.EmitRead(ctx, valueForTail);

                    if (_expectedType.IsValueType)
                    {
                        if (!Tail.EmitReadReturnsValue)
                        {
                            ctx.LoadValue(tempLocal);
                        }
                        // note we demanded always returns a value
                        ctx.EmitCtor(_expectedType, Tail.ExpectedType); // re-nullable<T> it
                    }

                    if (Tail.EmitReadReturnsValue || _expectedType.IsValueType)
                    {
                        ctx.StoreValue(oldValue);
                    }

                    if (EmitReadReturnsValue)
                    {
                        ctx.LoadValue(oldValue);
                    }

                    if (!tempLocal.IsNullRef())
                    {
                        tempLocal.Dispose();
                    }
                }
            }
        }
        void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var g = ctx.G;
                Helpers.DebugAssert(!valueFrom.IsNullRef());

                using (Compiler.Local loc = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                    using (Compiler.Local token = ctx.Local(typeof(SubItemToken)))
                        using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int))))
                        {
                            g.Assign(token, g.ReaderFunc.StartSubItem());
                            // pre-callbacks
                            if (HasCallbacks(TypeModel.CallbackType.BeforeDeserialize))
                            {
                                if (ExpectedType.IsValueType)
                                {
                                    EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize);
                                }
                                else
                                { // could be null
                                    Compiler.CodeLabel callbacksDone = ctx.DefineLabel();
                                    ctx.LoadValue(loc);
                                    ctx.BranchIfFalse(callbacksDone, false);
                                    EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize);
                                    ctx.MarkLabel(callbacksDone);
                                }
                            }

                            Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel();
                            ctx.Branch(@continue, false);

                            ctx.MarkLabel(processField);
                            foreach (BasicList.Group group in BasicList.GetContiguousGroups(_fieldNumbers, _serializers))
                            {
                                Compiler.CodeLabel tryNextField = ctx.DefineLabel();
                                int groupItemCount = group.Items.Count;
                                if (groupItemCount == 1)
                                {
                                    // discreet group; use an equality test
                                    ctx.LoadValue(fieldNumber);
                                    ctx.LoadValue(group.First);
                                    Compiler.CodeLabel processThisField = ctx.DefineLabel();
                                    ctx.BranchIfEqual(processThisField, true);
                                    ctx.Branch(tryNextField, false);
                                    WriteFieldHandler(ctx, loc, processThisField, @continue, (IProtoSerializer)group.Items[0]);
                                }
                                else
                                { // implement as a jump-table-based switch
                                    ctx.LoadValue(fieldNumber);
                                    ctx.LoadValue(group.First);
                                    ctx.Subtract(); // jump-tables are zero-based
                                    Compiler.CodeLabel[] jmp = new Compiler.CodeLabel[groupItemCount];
                                    for (int i = 0; i < groupItemCount; i++)
                                    {
                                        jmp[i] = ctx.DefineLabel();
                                    }
                                    ctx.Switch(jmp);
                                    // write the default...
                                    ctx.Branch(tryNextField, false);
                                    for (int i = 0; i < groupItemCount; i++)
                                    {
                                        WriteFieldHandler(ctx, loc, jmp[i], @continue, (IProtoSerializer)group.Items[i]);
                                    }
                                }
                                ctx.MarkLabel(tryNextField);
                            }

                            EmitCreateIfNull(ctx, loc);
                            ctx.LoadReaderWriter();
                            if (_isExtensible)
                            {
                                ctx.LoadValue(loc);
                                ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("AppendExtensionData"));
                            }
                            else
                            {
                                ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField"));
                            }

                            ctx.MarkLabel(@continue);
                            ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int)));
                            ctx.CopyValue();
                            ctx.StoreValue(fieldNumber);
                            ctx.LoadValue(0);
                            ctx.BranchIfGreater(processField, false);

                            EmitCreateIfNull(ctx, loc);
                            // post-callbacks
                            EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterDeserialize);

                            g.Reader.EndSubItem(token);

                            if (EmitReadReturnsValue)
                            {
                                ctx.LoadValue(loc);
                            }
                        }
            }
        }
        } = false;                                         // updates field directly

        void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
        {
            using (ctx.StartDebugBlockAuto(this))
            {
                var  g        = ctx.G;
                Type expected = ExpectedType;
                using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom))
                    using (Compiler.Local token = ctx.Local(typeof(SubItemToken)))
                    {
                        g.Assign(token, g.WriterFunc.StartSubItem(loc, _prefixLength));
                        // pre-callbacks
                        EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeSerialize);

                        Compiler.CodeLabel startFields = ctx.DefineLabel();
                        // inheritance
                        if (CanHaveInheritance)
                        {
                            for (int i = 0; i < _serializers.Length; i++)
                            {
                                IProtoSerializer ser     = _serializers[i];
                                Type             serType = ser.ExpectedType;
                                if (serType != ExpectedType)
                                {
                                    Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel();
                                    ctx.LoadValue(loc);
                                    ctx.TryCast(serType);
                                    ctx.CopyValue();
                                    ctx.BranchIfTrue(ifMatch, true);
                                    ctx.DiscardValue();
                                    ctx.Branch(nextTest, true);
                                    ctx.MarkLabel(ifMatch);
                                    ctx.G.Writer.WriteFieldHeaderBegin(_fieldNumbers[i]);
                                    ser.EmitWrite(ctx, null);
                                    ctx.Branch(startFields, false);
                                    ctx.MarkLabel(nextTest);
                                }
                            }


                            if (_constructType != null && _constructType != ExpectedType)
                            {
                                using (Compiler.Local actualType = new Compiler.Local(ctx, ctx.MapType(typeof(System.Type))))
                                {
                                    // would have jumped to "fields" if an expected sub-type, so two options:
                                    // a: *exactly* that type, b: an *unexpected* type
                                    ctx.LoadValue(loc);
                                    ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
                                    ctx.CopyValue();
                                    ctx.StoreValue(actualType);
                                    ctx.LoadValue(ExpectedType);
                                    ctx.BranchIfEqual(startFields, true);

                                    ctx.LoadValue(actualType);
                                    ctx.LoadValue(_constructType);
                                    ctx.BranchIfEqual(startFields, true);
                                }
                            }
                            else
                            {
                                // would have jumped to "fields" if an expected sub-type, so two options:
                                // a: *exactly* that type, b: an *unexpected* type
                                ctx.LoadValue(loc);
                                ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
                                ctx.LoadValue(ExpectedType);
                                ctx.BranchIfEqual(startFields, true);
                            }
                            // unexpected, then... note that this *might* be a proxy, which
                            // is handled by ThrowUnexpectedSubtype
                            ctx.LoadValue(ExpectedType);
                            ctx.LoadValue(loc);
                            ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType"));
                            ctx.EmitCall(
                                ctx.MapType(typeof(TypeModel)).GetMethod(
                                    "ThrowUnexpectedSubtype",
                                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static));
                        }
                        // fields

                        ctx.MarkLabel(startFields);
                        for (int i = 0; i < _serializers.Length; i++)
                        {
                            IProtoSerializer ser = _serializers[i];
                            if (ser.ExpectedType == ExpectedType)
                            {
                                ctx.G.Writer.WriteFieldHeaderBegin(_fieldNumbers[i]);
                                ser.EmitWrite(ctx, loc);
                            }
                        }

                        // extension data
                        if (_isExtensible)
                        {
                            ctx.LoadValue(loc);
                            ctx.LoadReaderWriter();
                            ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("AppendExtensionData"));
                        }
                        // post-callbacks
                        EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterSerialize);
                        g.Writer.EndSubItem(token);
                    }
            }
        }