protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using Compiler.Local oldValue = ctx.GetLocalWithValue(ExpectedType, valueFrom); using Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken)); using Compiler.Local field = new Compiler.Local(ctx, typeof(int)); ctx.LoadState(); ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.StartSubItem), Type.EmptyTypes)); ctx.StoreValue(token); Compiler.CodeLabel next = ctx.DefineLabel(), processField = ctx.DefineLabel(), end = ctx.DefineLabel(); ctx.MarkLabel(next); ctx.EmitStateBasedRead(nameof(ProtoReader.State.ReadFieldHeader), typeof(int)); ctx.CopyValue(); ctx.StoreValue(field); ctx.LoadValue(Tag); // = 1 - process ctx.BranchIfEqual(processField, true); ctx.LoadValue(field); ctx.LoadValue(1); // < 1 - exit ctx.BranchIfLess(end, false); // default: skip ctx.LoadState(); ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.SkipField), Type.EmptyTypes)); ctx.Branch(next, true); // process ctx.MarkLabel(processField); if (Tail.RequiresOldValue) { if (ExpectedType.IsValueType) { ctx.LoadAddress(oldValue, ExpectedType); ctx.EmitCall(ExpectedType.GetMethod("GetValueOrDefault", Type.EmptyTypes)); } else { ctx.LoadValue(oldValue); } } Tail.EmitRead(ctx, null); // note we demanded always returns a value if (ExpectedType.IsValueType) { ctx.EmitCtor(ExpectedType, Tail.ExpectedType); // re-nullable<T> it } ctx.StoreValue(oldValue); ctx.Branch(next, false); // outro ctx.MarkLabel(end); ctx.LoadState(); ctx.LoadValue(token); ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.EndSubItem), new[] { typeof(SubItemToken) })); ctx.LoadValue(oldValue); // load the old value }
void IRuntimeProtoSerializerNode.EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity) { ctx.LoadState(); ctx.LoadNullRef(); // map ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.ReadString), BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(StringMap) }, null)); }
void IDirectWriteNode.EmitDirectWrite(int fieldNumber, WireType wireType, Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using var loc = ctx.GetLocalWithValue(typeof(int), valueFrom); ctx.LoadState(); ctx.LoadValue(fieldNumber); ctx.LoadValue(loc); ctx.EmitCall(typeof(ProtoWriter.State).GetMethod(nameof(ProtoWriter.State.WriteInt32Varint), BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int), typeof(int) }, null)); }
void IRuntimeProtoSerializerNode.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using var loc = ctx.GetLocalWithValue(typeof(string), valueFrom); ctx.LoadState(); ctx.LoadValue(loc); ctx.LoadNullRef(); // map ctx.EmitCall(typeof(ProtoWriter.State).GetMethod(nameof(ProtoWriter.State.WriteString), BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string), typeof(StringMap) }, null)); }
public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { // BclHelpers.WriteNetObject(ref state, value, options); using var loc = ctx.GetLocalWithValue(ExpectedType, valueFrom); ctx.LoadState(); ctx.LoadValue(loc); ctx.CastToObject(ExpectedType); ctx.LoadValue((int)options); ctx.EmitCall(typeof(BclHelpers).GetMethod(nameof(BclHelpers.WriteNetObject), new[] { Compiler.WriterUtil.ByRefStateType, typeof(object), typeof(BclHelpers.NetObjectOptions) })); }
void IRuntimeProtoSerializerNode.EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity) { using var tmp = overwriteList ? default : ctx.GetLocalWithValue(typeof(byte[]), entity); ctx.LoadState(); if (overwriteList) { ctx.LoadNullRef(); } else { ctx.LoadValue(tmp); } ctx.EmitCall(typeof(ProtoReader.State) .GetMethod(nameof(ProtoReader.State.AppendBytes), new[] { typeof(byte[]) })); }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { // BclHelpers.ReadNetObject(ref state, value, ExpectedType == typeof(object) ? null : ExpectedType, options); using var loc = ctx.GetLocalWithValue(ExpectedType, valueFrom); ctx.LoadState(); ctx.LoadValue(loc); if (ExpectedType == typeof(object)) { ctx.LoadNullRef(); } else { ctx.LoadValue(ExpectedType); } ctx.LoadValue((int)options); ctx.EmitCall(typeof(BclHelpers).GetMethod(nameof(BclHelpers.ReadNetObject), new[] { Compiler.CompilerContext.StateBasedReadMethods.ByRefStateType, typeof(object), typeof(Type), typeof(BclHelpers.NetObjectOptions) })); }
void IRuntimeProtoSerializerNode.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Type type = ExpectedType; using var loc = ctx.GetLocalWithValue(ExpectedType, valueFrom); ctx.LoadState(); ctx.LoadAddress(loc, type); if (type.IsValueType) { // note that for structs, we've already asserted that a custom ToString // exists; no need to handle the box/callvirt scenario // force it to a variable if needed, so we can take the address ctx.EmitCall(GetCustomToString(type)); } else { ctx.EmitCall(typeof(object).GetMethod(nameof(object.ToString))); } ctx.LoadNullRef(); // map ctx.EmitCall(typeof(ProtoWriter.State).GetMethod(nameof(ProtoWriter.State.WriteString), BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string), typeof(StringMap) }, null)); }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local incoming) { using Compiler.Local objValue = ctx.GetLocalWithValue(ExpectedType, incoming); Compiler.Local[] locals = new Compiler.Local[members.Length]; try { 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); if (members[i] is FieldInfo fieldInfo) { ctx.LoadValue(fieldInfo); } else if (members[i] is PropertyInfo propertyInfo) { ctx.LoadValue(propertyInfo); } ctx.StoreValue(locals[i]); } if (!ExpectedType.IsValueType) { ctx.MarkLabel(skipOld); } using (Compiler.Local fieldNumber = new Compiler.Local(ctx, 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]); IRuntimeProtoSerializerNode tail = tails[i]; Compiler.Local oldValIfNeeded = tail.RequiresOldValue ? locals[i] : null; ctx.ReadNullCheckedTail(locals[i].Type, tail, oldValIfNeeded); if (tail.ReturnsValue) { 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.LoadState(); ctx.EmitCall(typeof(ProtoReader.State).GetMethod(nameof(ProtoReader.State.SkipField), Type.EmptyTypes)); ctx.MarkLabel(@continue); ctx.EmitStateBasedRead(nameof(ProtoReader.State.ReadFieldHeader), typeof(int)); ctx.CopyValue(); ctx.StoreValue(fieldNumber); ctx.LoadValue(0); ctx.BranchIfGreater(processField, false); } for (int i = 0; i < locals.Length; i++) { ctx.LoadValue(locals[i]); } ctx.EmitCtor(ctor); ctx.StoreValue(objValue); } finally { for (int i = 0; i < locals.Length; i++) { if (locals[i] != null) { locals[i].Dispose(); // release for re-use } } } }