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 } } } } } }