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, ctx.MapType(typeof(SubItemToken)))) using (Compiler.Local field = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) { ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem")); ctx.StoreValue(token); Compiler.CodeLabel next = ctx.DefineLabel(), processField = ctx.DefineLabel(), end = ctx.DefineLabel(); ctx.MarkLabel(next); ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(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.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); ctx.Branch(next, true); // process ctx.MarkLabel(processField); if (Tail.RequiresOldValue) { if (Helpers.IsValueType(expectedType)) { ctx.LoadAddress(oldValue, expectedType); ctx.EmitCall(expectedType.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); } else { ctx.LoadValue(oldValue); } } Tail.EmitRead(ctx, null); // note we demanded always returns a value if (Helpers.IsValueType(expectedType)) { ctx.EmitCtor(expectedType, Tail.ExpectedType); // re-nullable<T> it } ctx.StoreValue(oldValue); ctx.Branch(next, false); // outro ctx.MarkLabel(end); ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem")); ctx.LoadValue(oldValue); // load the old value } }
public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadValue(valueFrom); ctx.CastToObject(type); ctx.LoadReaderWriter(); ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); if (type == ctx.MapType(typeof(object))) ctx.LoadNullRef(); else ctx.LoadValue(type); ctx.LoadValue((int)options); ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("ReadNetObject")); ctx.CastFromObject(type); }
public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadValue(valueFrom); ctx.CastToObject(type); ctx.LoadReaderWriter(); ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); ctx.LoadValue((int)options); ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("WriteNetObject")); }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Tail.EmitRead(ctx, valueFrom); ctx.CopyValue(); Compiler.CodeLabel @nonEmpty = ctx.DefineLabel(), @end = ctx.DefineLabel(); ctx.LoadValue(typeof(string).GetProperty("Length")); ctx.BranchIfTrue(@nonEmpty, true); ctx.DiscardValue(); ctx.LoadNullRef(); ctx.Branch(@end, true); ctx.MarkLabel(@nonEmpty); ctx.EmitCtor(expectedType, ctx.MapType(typeof(string))); ctx.MarkLabel(@end); }
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 (!Helpers.IsValueType(ExpectedType)) { // value-types always read the old value if (Helpers.IsValueType(type)) { 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 = Helpers.IsValueType(ExpectedType) ? new Compiler.CodeLabel() : ctx.DefineLabel(); if (!Helpers.IsValueType(ExpectedType)) { 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) { ctx.LoadValue((FieldInfo)members[i]); } else if (members[i] is PropertyInfo) { ctx.LoadValue((PropertyInfo)members[i]); } ctx.StoreValue(locals[i]); } if (!Helpers.IsValueType(ExpectedType)) 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.ReturnsValue) { if (Helpers.IsValueType(locals[i].Type)) { 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); } 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 } } } }
private void WriteConstructors(TypeBuilder type, ref int index, SerializerPair[] methodPairs, ref ILGenerator il, int knownTypesCategory, FieldBuilder knownTypes, Type knownTypesLookupType, Compiler.CompilerContext ctx) { type.DefineDefaultConstructor(MethodAttributes.Public); il = type.DefineTypeInitializer().GetILGenerator(); switch (knownTypesCategory) { case KnownTypes_Array: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type))); index = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Dup); Compiler.CompilerContext.LoadValue(il, index); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); il.Emit(OpCodes.Stelem_Ref); index++; } il.Emit(OpCodes.Stsfld, knownTypes); il.Emit(OpCodes.Ret); } break; case KnownTypes_Dictionary: { Compiler.CompilerContext.LoadValue(il, types.Count); //LocalBuilder loc = il.DeclareLocal(knownTypesLookupType); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null); } il.Emit(OpCodes.Ret); } break; case KnownTypes_Hashtable: { Compiler.CompilerContext.LoadValue(il, types.Count); il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); il.Emit(OpCodes.Stsfld, knownTypes); int typeIndex = 0; foreach (SerializerPair pair in methodPairs) { il.Emit(OpCodes.Ldsfld, knownTypes); il.Emit(OpCodes.Ldtoken, pair.Type.Type); il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); int keyIndex = typeIndex++, lastKey = pair.BaseKey; if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type { keyIndex = -1; // assume epic fail for (int j = 0; j < methodPairs.Length; j++) { if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) { keyIndex = j; break; } } } Compiler.CompilerContext.LoadValue(il, keyIndex); il.Emit(OpCodes.Box, MapType(typeof(int))); il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null); } il.Emit(OpCodes.Ret); } break; default: throw new InvalidOperationException(); } }
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using(Compiler.Local valOrNull = ctx.GetLocalWithValue(expectedType, valueFrom)) using(Compiler.Local token = new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) { ctx.LoadNullRef(); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem")); ctx.StoreValue(token); if (Helpers.IsValueType(expectedType)) { ctx.LoadAddress(valOrNull, expectedType); ctx.LoadValue(expectedType.GetProperty("HasValue")); } else { ctx.LoadValue(valOrNull); } Compiler.CodeLabel @end = ctx.DefineLabel(); ctx.BranchIfFalse(@end, false); if (Helpers.IsValueType(expectedType)) { ctx.LoadAddress(valOrNull, expectedType); ctx.EmitCall(expectedType.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); } else { ctx.LoadValue(valOrNull); } Tail.EmitWrite(ctx, null); ctx.MarkLabel(@end); ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem")); } }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ProtoTypeCode typeCode = GetTypeCode(); if (map == null) { ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int))); ctx.ConvertFromInt32(typeCode, false); } else { int[] wireValues = new int[map.Length]; object[] values = new object[map.Length]; for (int i = 0; i < map.Length; i++) { wireValues[i] = map[i].WireValue; values[i] = map[i].RawValue; } using (Compiler.Local result = new Compiler.Local(ctx, ExpectedType)) using (Compiler.Local wireValue = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) { ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int))); ctx.StoreValue(wireValue); Compiler.CodeLabel @continue = ctx.DefineLabel(); foreach (BasicList.Group group in BasicList.GetContiguousGroups(wireValues, values)) { Compiler.CodeLabel tryNextGroup = ctx.DefineLabel(); int groupItemCount = group.Items.Count; if (groupItemCount == 1) { // discreet group; use an equality test ctx.LoadValue(wireValue); ctx.LoadValue(group.First); Compiler.CodeLabel processThisValue = ctx.DefineLabel(); ctx.BranchIfEqual(processThisValue, true); ctx.Branch(tryNextGroup, false); WriteEnumValue(ctx, typeCode, processThisValue, @continue, group.Items[0], @result); } else { // implement as a jump-table-based switch ctx.LoadValue(wireValue); 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(tryNextGroup, false); for (int i = 0; i < groupItemCount; i++) { WriteEnumValue(ctx, typeCode, jmp[i], @continue, group.Items[i], @result); } } ctx.MarkLabel(tryNextGroup); } // throw source.CreateEnumException(ExpectedType, wireValue); ctx.LoadReaderWriter(); ctx.LoadValue(ExpectedType); ctx.LoadValue(wireValue); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("ThrowEnumException")); ctx.MarkLabel(@continue); ctx.LoadValue(result); } } }
private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label) { switch (Helpers.GetTypeCode(ExpectedType)) { case ProtoTypeCode.Boolean: if ((bool)defaultValue) { ctx.BranchIfTrue(label, false); } else { ctx.BranchIfFalse(label, false); } break; case ProtoTypeCode.Byte: if ((byte)defaultValue == (byte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(byte)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.SByte: if ((sbyte)defaultValue == (sbyte)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(sbyte)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.Int16: if ((short)defaultValue == (short)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(short)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.UInt16: if ((ushort)defaultValue == (ushort)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(ushort)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.Int32: if ((int)defaultValue == (int)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.UInt32: if ((uint)defaultValue == (uint)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(uint)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.Char: if ((char)defaultValue == (char)0) { ctx.BranchIfFalse(label, false); } else { ctx.LoadValue((int)(char)defaultValue); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.Int64: ctx.LoadValue((long)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case ProtoTypeCode.UInt64: ctx.LoadValue((long)(ulong)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case ProtoTypeCode.Double: ctx.LoadValue((double)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case ProtoTypeCode.Single: ctx.LoadValue((float)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case ProtoTypeCode.String: ctx.LoadValue((string)defaultValue); EmitBeq(ctx, label, ExpectedType); break; case ProtoTypeCode.Decimal: { decimal d = (decimal)defaultValue; ctx.LoadValue(d); EmitBeq(ctx, label, ExpectedType); } break; case ProtoTypeCode.TimeSpan: { TimeSpan ts = (TimeSpan)defaultValue; if (ts == TimeSpan.Zero) { ctx.LoadValue(typeof(TimeSpan).GetField("Zero")); } else { ctx.LoadValue(ts.Ticks); ctx.EmitCall(ctx.MapType(typeof(TimeSpan)).GetMethod("FromTicks")); } EmitBeq(ctx, label, ExpectedType); break; } case ProtoTypeCode.Guid: { ctx.LoadValue((Guid)defaultValue); EmitBeq(ctx, label, ExpectedType); break; } case ProtoTypeCode.DateTime: { #if FX11 ctx.LoadValue(((DateTime)defaultValue).ToFileTime()); ctx.EmitCall(typeof(DateTime).GetMethod("FromFileTime")); #else ctx.LoadValue(((DateTime)defaultValue).ToBinary()); ctx.EmitCall(ctx.MapType(typeof(DateTime)).GetMethod("FromBinary")); #endif EmitBeq(ctx, label, ExpectedType); break; } default: throw new NotSupportedException("Type cannot be represented as a default value: " + ExpectedType.FullName); } }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Type type = ExpectedType; if (Helpers.IsValueType(type)) { // 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 using (Compiler.Local loc = ctx.GetLocalWithValue(type, valueFrom)) { ctx.LoadAddress(loc, type); ctx.EmitCall(GetCustomToString(type)); } } else { ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("ToString")); } ctx.EmitBasicWrite("WriteString", valueFrom); }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ProtoTypeCode typeCode = GetTypeCode(); if (map == null) { ctx.LoadValue(valueFrom); ctx.ConvertToInt32(typeCode, false); ctx.EmitBasicWrite("WriteInt32", null); } else { using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) { Compiler.CodeLabel @continue = ctx.DefineLabel(); for (int i = 0; i < map.Length; i++) { Compiler.CodeLabel tryNextValue = ctx.DefineLabel(), processThisValue = ctx.DefineLabel(); ctx.LoadValue(loc); WriteEnumValue(ctx, typeCode, map[i].RawValue); ctx.BranchIfEqual(processThisValue, true); ctx.Branch(tryNextValue, true); ctx.MarkLabel(processThisValue); ctx.LoadValue(map[i].WireValue); ctx.EmitBasicWrite("WriteInt32", null); ctx.Branch(@continue, false); ctx.MarkLabel(tryNextValue); } ctx.LoadReaderWriter(); ctx.LoadValue(loc); ctx.CastToObject(ExpectedType); ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("ThrowEnumException")); ctx.MarkLabel(@continue); } } }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicRead("ReadString", ctx.MapType(typeof(string))); ctx.EmitCall(parse); }
bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read) { #if SILVERLIGHT return false; #else MethodBuilder method = ctx.GetDedicatedMethod(key, read); if (method == null) return false; using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) { Type rwType = ctx.MapType(read ? typeof(ProtoReader) : typeof(ProtoWriter)); ctx.LoadValue(valueFrom); if (!read) // write requires the object for StartSubItem; read doesn't { // (if recursion-check is disabled [subtypes] then null is fine too) if (type.IsValueType || !recursionCheck) { ctx.LoadNullRef(); } else { ctx.CopyValue(); } } ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("StartSubItem")); ctx.StoreValue(token); // note: value already on the stack ctx.LoadReaderWriter(); ctx.EmitCall(method); // handle inheritance (we will be calling the *base* version of things, // but we expect Read to return the "type" type) if (read && type != method.ReturnType) ctx.Cast(this.type); ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(rwType.GetMethod("EndSubItem")); } return true; #endif }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { if (!EmitDedicatedMethod(ctx, valueFrom, true)) { ctx.LoadValue(valueFrom); if (type.IsValueType) ctx.CastToObject(type); ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); // re-map for formality, but would expect identical, else dedicated method ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("ReadObject")); ctx.CastFromObject(type); } }
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadValue((int)fieldNumber); ctx.LoadValue((int)wireType); ctx.LoadReaderWriter(); ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader")); Tail.EmitWrite(ctx, valueFrom); }
private void EmitBeq(Compiler.CompilerContext ctx, Compiler.CodeLabel label, Type type) { switch (Helpers.GetTypeCode(type)) { case ProtoTypeCode.Boolean: case ProtoTypeCode.Byte: case ProtoTypeCode.Char: case ProtoTypeCode.Double: case ProtoTypeCode.Int16: case ProtoTypeCode.Int32: case ProtoTypeCode.Int64: case ProtoTypeCode.SByte: case ProtoTypeCode.Single: case ProtoTypeCode.UInt16: case ProtoTypeCode.UInt32: case ProtoTypeCode.UInt64: ctx.BranchIfEqual(label, false); break; default: MethodInfo method = type.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static, null, new Type[] { type, type}, null); if (method == null || method.ReturnType != ctx.MapType(typeof(bool))) { throw new InvalidOperationException("No suitable equality operator found for default-values of type: " + type.FullName); } ctx.EmitCall(method); ctx.BranchIfTrue(label, false); break; } }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { using (Compiler.Local oldList = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : null) using(Compiler.Local builder = new Compiler.Local(ctx, builderFactory.ReturnType)) { ctx.EmitCall(builderFactory); ctx.StoreValue(builder); if(AppendToCollection) { Compiler.CodeLabel done = ctx.DefineLabel(); if(!ExpectedType.IsValueType) { ctx.LoadValue(oldList); ctx.BranchIfFalse(done, false); // old value null; nothing to add } PropertyInfo prop = Helpers.GetProperty(ExpectedType, "Length", false); if(prop == null) prop = Helpers.GetProperty(ExpectedType, "Count", false); #if !NO_GENERICS if (prop == null) prop = Helpers.GetProperty(ResolveIReadOnlyCollection(ExpectedType, Tail.ExpectedType), "Count", false); #endif ctx.LoadAddress(oldList, oldList.Type); ctx.EmitCall(Helpers.GetGetMethod(prop, false, false)); ctx.BranchIfFalse(done, false); // old list is empty; nothing to add Type voidType = ctx.MapType(typeof(void)); if(addRange != null) { ctx.LoadValue(builder); ctx.LoadValue(oldList); 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(oldList, 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(builder, builder.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); } EmitReadList(ctx, builder, Tail, add, packedWireType, false); ctx.LoadAddress(builder, builder.Type); ctx.EmitCall(finish); if(ExpectedType != finish.ReturnType) { ctx.Cast(ExpectedType); } } }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { if (!EmitDedicatedMethod(ctx, valueFrom, false)) { ctx.LoadValue(valueFrom); if (Helpers.IsValueType(type)) ctx.CastToObject(type); ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); // re-map for formality, but would expect identical, else dedicated method ctx.LoadReaderWriter(); ctx.EmitCall(Helpers.GetStaticMethod(ctx.MapType(typeof(ProtoWriter)), recursionCheck ? "WriteObject" : "WriteRecursionSafeObject", new Type[] { ctx.MapType(typeof(object)), ctx.MapType(typeof(int)), ctx.MapType(typeof(ProtoWriter)) })); } }