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