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); } } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this, _field.Name)) { using (Compiler.Local loc = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local newVal = new Compiler.Local(ctx, _field.FieldType)) { Compiler.Local valueForTail; if (Tail.RequiresOldValue) { ctx.LoadAddress(loc, ExpectedType); ctx.LoadValue(_field); if (!Tail.EmitReadReturnsValue) { ctx.StoreValue(newVal); valueForTail = newVal; } else { valueForTail = null; // on stack } } else { valueForTail = null; } Tail.EmitRead(ctx, valueForTail); if (Tail.EmitReadReturnsValue) { ctx.StoreValue(newVal); } ctx.LoadAddress(loc, ExpectedType); ctx.LoadValue(newVal); ctx.StoreValue(_field); if (EmitReadReturnsValue) { ctx.LoadValue(loc); } } } }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this)) { using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local converted = new Compiler.Local(ctx, _declaredType)) // declare/re-use local using (Compiler.Local reservedTrap = new Compiler.Local(ctx, typeof(int))) { var g = ctx.G; if (!ExpectedType.IsValueType) { g.Assign(reservedTrap, g.ReaderFunc.ReserveNoteObject_int()); } ctx.LoadValue(value); // load primary onto stack ctx.EmitCall(_toTail); // static convert op, primary-to-surrogate ctx.StoreValue(converted); // store into surrogate local _rootTail.EmitRead(ctx, _rootTail.RequiresOldValue ? converted : null); // downstream processing against surrogate local if (_rootTail.EmitReadReturnsValue) { ctx.StoreValue(converted); } ctx.LoadValue(converted); // load from surrogate local ctx.EmitCall(_fromTail); // static convert op, surrogate-to-primary ctx.StoreValue(value); // store back into primary if (!ExpectedType.IsValueType) { g.Reader.NoteReservedTrappedObject(reservedTrap, value); } if (EmitReadReturnsValue) { ctx.LoadValue(value); } } } }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this)) { var g = ctx.G; using (var value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) { _subTypeHelpers.EmitTryRead( g, value, _model[_typeKey], r => { using (ctx.StartDebugBlockAuto(this, "returnGen")) { if (r == null) { g.If(value.AsOperand == null); { g.ThrowProtoException(CantCreateInstanceMessage); } g.End(); g.Reader.NoteObject(value); } else { r.Serializer.EmitCreateInstance(ctx); ctx.StoreValue(value); } g.Reader.NoteLateReference(ctx.MapMetaKeyToCompiledKey(_baseTypeKey), value); } }); if (EmitReadReturnsValue) { ctx.LoadValue(value); } } } }
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); } } } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this, _property.Name)) { var g = ctx.G; bool canSet; SanityCheck(ctx.Model, _property, Tail, out canSet, ctx.NonPublic, ctx.AllowInternal(_property), true); using (Compiler.Local loc = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local oldVal = canSet ? new Compiler.Local(ctx, _property.PropertyType) : null) using (Compiler.Local newVal = new Compiler.Local(ctx, _property.PropertyType)) { Compiler.Local valueForTail = null; if (Tail.RequiresOldValue) { ctx.LoadAddress(loc, ExpectedType); ctx.LoadValue(_property); if (!oldVal.IsNullRef()) { if (Tail.RequiresOldValue) // we need it later { ctx.CopyValue(); } ctx.StoreValue(oldVal); } } if (Tail.RequiresOldValue) // !here! <-- we need value again { if (!Tail.EmitReadReturnsValue) { ctx.StoreValue(newVal); valueForTail = newVal; } // otherwise valueForTail = null (leave value on stack) } Tail.EmitRead(ctx, valueForTail); // otherwise newVal was passed to EmitRead so already has necessary data if (Tail.EmitReadReturnsValue) { ctx.StoreValue(newVal); } // check-condition: //(!Tail.RequiresOldValue // always set where can't check oldVal // // and if it's value type or nullable with changed null/not null or ref // || (Helpers.IsValueType(property.PropertyType) && oldVal != null && newVal != null) // || !ReferenceEquals(oldVal, newVal) // )) if (canSet) { bool check = Tail.RequiresOldValue; if (check) { var condition = !g.StaticFactory.InvokeReferenceEquals(oldVal, newVal); if (Helpers.IsValueType(_property.PropertyType)) { condition = (oldVal.AsOperand != null && newVal.AsOperand != null) || condition; } g.If(condition); } ctx.LoadAddress(loc, ExpectedType); ctx.LoadValue(newVal); if (_shadowSetter == null) { ctx.StoreValue(_property); } else { ctx.EmitCall(_shadowSetter); } if (check) { g.End(); } } if (EmitReadReturnsValue) { ctx.LoadValue(loc); } } } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (ctx.StartDebugBlockAuto(this)) { Type voidType = ctx.MapType(typeof(void)); using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom)) using (Compiler.Local builderInstance = new Compiler.Local(ctx, _builderFactory.ReturnType)) using (Compiler.Local trappedKey = new Compiler.Local(ctx, typeof(int))) { ctx.G.Assign(trappedKey, ctx.G.ReaderFunc.ReserveNoteObject_int()); ctx.EmitCall(_builderFactory); ctx.StoreValue(builderInstance); if (AppendToCollection) { Compiler.CodeLabel done = ctx.DefineLabel(); if (!ExpectedType.IsValueType) { ctx.LoadValue(value); ctx.BranchIfFalse(done, false); // old value null; nothing to add } PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false) ?? Helpers.GetProperty(ExpectedType, "Count", false); #if !NO_GENERICS if (prop == null) { prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false); } #endif ctx.LoadAddress(value, value.Type); ctx.EmitCall(Helpers.GetGetMethod(prop, false, false)); ctx.BranchIfFalse(done, false); // old list is empty; nothing to add if (_addRange != null) { ctx.LoadValue(builderInstance); ctx.LoadValue(value); 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(value, 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(builderInstance, builderInstance.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); } ListHelpers.EmitRead( ctx.G, null, null, o => { using (ctx.StartDebugBlockAuto(this, "add")) { ctx.LoadAddress(builderInstance, builderInstance.Type); ctx.LoadValue(o); ctx.EmitCall(_add); if (_add.ReturnType != null && _add.ReturnType != voidType) { ctx.DiscardValue(); } } }); ctx.LoadAddress(builderInstance, builderInstance.Type); ctx.EmitCall(_finish); if (ExpectedType != _finish.ReturnType) { ctx.Cast(ExpectedType); } ctx.StoreValue(value); ctx.G.Reader.NoteReservedTrappedObject(trappedKey, value); if (EmitReadReturnsValue) { ctx.LoadValue(value); } } } }
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(); } } } }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local incoming) { using (ctx.StartDebugBlockAuto(this)) { var g = ctx.G; using (Compiler.Local objValue = ctx.GetLocalWithValueForEmitRead(this, incoming)) using (Compiler.Local reservedTrap = new Local(ctx, ctx.MapType(typeof(int)))) using (Compiler.Local token = new Local(ctx, ctx.MapType(typeof(SubItemToken)))) using (Compiler.Local refLocalToNoteObject = new Local(ctx, ctx.MapType(typeof(object)))) { ctx.EmitCallReserveNoteObject(); ctx.StoreValue(reservedTrap); Compiler.Local[] locals = new Compiler.Local[_members.Length]; try { g.Assign(token, g.ReaderFunc.StartSubItem()); for (int i = 0; i < locals.Length; i++) { Type type = GetMemberType(i); bool store = true; locals[i] = new Compiler.Local(ctx, type); if (!ExpectedType.IsValueType) { // value-types always read the old value if (type.IsValueType) { switch (Helpers.GetTypeCode(type)) { case ProtoTypeCode.Boolean: case ProtoTypeCode.Byte: case ProtoTypeCode.Int16: case ProtoTypeCode.Int32: case ProtoTypeCode.SByte: case ProtoTypeCode.UInt16: case ProtoTypeCode.UInt32: ctx.LoadValue(0); break; case ProtoTypeCode.Int64: case ProtoTypeCode.UInt64: ctx.LoadValue(0L); break; case ProtoTypeCode.Single: ctx.LoadValue(0.0F); break; case ProtoTypeCode.Double: ctx.LoadValue(0.0D); break; case ProtoTypeCode.Decimal: ctx.LoadValue(0M); break; case ProtoTypeCode.Guid: ctx.LoadValue(Guid.Empty); break; default: ctx.LoadAddress(locals[i], type); ctx.EmitCtor(type); store = false; break; } } else { ctx.LoadNullRef(); } if (store) { ctx.StoreValue(locals[i]); } } } Compiler.CodeLabel skipOld = ExpectedType.IsValueType ? new Compiler.CodeLabel() : ctx.DefineLabel(); if (!ExpectedType.IsValueType) { ctx.LoadAddress(objValue, ExpectedType); ctx.BranchIfFalse(skipOld, false); } for (int i = 0; i < _members.Length; i++) { ctx.LoadAddress(objValue, 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.StoreValue(locals[i]); } if (!ExpectedType.IsValueType) { ctx.MarkLabel(skipOld); } using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) { Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(), notRecognised = ctx.DefineLabel(); ctx.Branch(@continue, false); Compiler.CodeLabel[] handlers = new Compiler.CodeLabel[_members.Length]; for (int i = 0; i < _members.Length; i++) { handlers[i] = ctx.DefineLabel(); } ctx.MarkLabel(processField); ctx.LoadValue(fieldNumber); ctx.LoadValue(1); ctx.Subtract(); // jump-table is zero-based ctx.Switch(handlers); // and the default: ctx.Branch(notRecognised, false); for (int i = 0; i < handlers.Length; i++) { ctx.MarkLabel(handlers[i]); IProtoSerializer tail = _tails[i]; Compiler.Local oldValIfNeeded = tail.RequiresOldValue ? locals[i] : null; ctx.ReadNullCheckedTail(locals[i].Type, tail, oldValIfNeeded); if (tail.EmitReadReturnsValue) { if (locals[i].Type.IsValueType) { ctx.StoreValue(locals[i]); } else { Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel(); ctx.CopyValue(); ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign" ctx.DiscardValue(); ctx.Branch(allDone, true); ctx.MarkLabel(hasValue); ctx.StoreValue(locals[i]); ctx.MarkLabel(allDone); } } ctx.Branch(@continue, false); } ctx.MarkLabel(notRecognised); ctx.LoadReaderWriter(); 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); } g.Reader.EndSubItem(token); for (int i = 0; i < locals.Length; i++) { ctx.LoadValue(locals[i]); } ctx.EmitCtor(_ctor); ctx.StoreValue(objValue); ctx.LoadValue(objValue); ctx.CastToObject(ctx.MapType(_ctor.DeclaringType)); ctx.StoreValue(refLocalToNoteObject); ctx.LoadValue(reservedTrap); ctx.LoadAddress(refLocalToNoteObject, refLocalToNoteObject.Type); ctx.EmitCallNoteReservedTrappedObject(); if (EmitReadReturnsValue) { ctx.LoadValue(objValue); } } finally { for (int i = 0; i < locals.Length; i++) { if (!locals[i].IsNullRef()) { locals[i].Dispose(); // release for re-use } } } } } }
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); } } } }