void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { EmitRead(ctx, valueFrom); }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicRead("ReadString", typeof(string)); ctx.EmitCall(parse); }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicRead("ReadBoolean", ExpectedType); }
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Tail.EmitRead(ctx, valueFrom); }
protected override void EmitRead(CompilerContext ctx, Local valueFrom) { using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : new Compiler.Local(ctx, typeof(TDictionary))) using (Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken))) using (Compiler.Local key = new Compiler.Local(ctx, typeof(TKey))) using (Compiler.Local @value = new Compiler.Local(ctx, typeof(TValue))) using (Compiler.Local fieldNumber = new Compiler.Local(ctx, typeof(int))) { if (!AppendToCollection) { // always new ctx.LoadNullRef(); ctx.StoreValue(list); } if (concreteType != null) { ctx.LoadValue(list); Compiler.CodeLabel notNull = ctx.DefineLabel(); ctx.BranchIfTrue(notNull, true); ctx.EmitCtor(concreteType); ctx.StoreValue(list); ctx.MarkLabel(notNull); } var redoFromStart = ctx.DefineLabel(); ctx.MarkLabel(redoFromStart); // key = default(TKey); value = default(TValue); if (typeof(TKey) == typeof(string)) { ctx.LoadValue(""); ctx.StoreValue(key); } else { ctx.InitLocal(typeof(TKey), key); } if (typeof(TValue) == typeof(string)) { ctx.LoadValue(""); ctx.StoreValue(value); } else { ctx.InitLocal(typeof(TValue), @value); } // token = ProtoReader.StartSubItem(reader); ctx.LoadReader(true); ctx.EmitCall(typeof(ProtoReader).GetMethod("StartSubItem", Compiler.ReaderUtil.ReaderStateTypeArray)); ctx.StoreValue(token); Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(); // while ... ctx.Branch(@continue, false); // switch(fieldNumber) ctx.MarkLabel(processField); ctx.LoadValue(fieldNumber); CodeLabel @default = ctx.DefineLabel(), one = ctx.DefineLabel(), two = ctx.DefineLabel(); ctx.Switch(new[] { @default, one, two }); // zero based, hence explicit 0 // case 0: default: reader.SkipField(); ctx.MarkLabel(@default); ctx.LoadReader(true); ctx.EmitCall(typeof(ProtoReader).GetMethod("SkipField", Compiler.ReaderUtil.StateTypeArray)); ctx.Branch(@continue, false); // case 1: key = ... ctx.MarkLabel(one); keyTail.EmitRead(ctx, null); ctx.StoreValue(key); ctx.Branch(@continue, false); // case 2: value = ... ctx.MarkLabel(two); Tail.EmitRead(ctx, Tail.RequiresOldValue ? @value : null); ctx.StoreValue(value); // (fieldNumber = reader.ReadFieldHeader()) > 0 ctx.MarkLabel(@continue); ctx.EmitBasicRead("ReadFieldHeader", typeof(int)); ctx.CopyValue(); ctx.StoreValue(fieldNumber); ctx.LoadValue(0); ctx.BranchIfGreater(processField, false); // ProtoReader.EndSubItem(token, reader); ctx.LoadValue(token); ctx.LoadReader(true); ctx.EmitCall(typeof(ProtoReader).GetMethod("EndSubItem", new[] { typeof(SubItemToken), typeof(ProtoReader), Compiler.ReaderUtil.ByRefStateType })); // list[key] = value; ctx.LoadAddress(list, ExpectedType); ctx.LoadValue(key); ctx.LoadValue(@value); ctx.EmitCall(indexerSet); // while reader.TryReadFieldReader(fieldNumber) ctx.LoadReader(true); ctx.LoadValue(this.fieldNumber); ctx.EmitCall(typeof(ProtoReader).GetMethod("TryReadFieldHeader", new[] { Compiler.ReaderUtil.ByRefStateType, typeof(int) })); ctx.BranchIfTrue(redoFromStart, false); if (ReturnsValue) { ctx.LoadValue(list); } } }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitWrite(typeof(BclHelpers), "WriteDateTime", valueFrom); }
} // updates field directly #if FEAT_COMPILER void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Type expected = ExpectedType; using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom)) { // 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 != forType) { 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); ser.EmitWrite(ctx, null); ctx.Branch(startFields, false); ctx.MarkLabel(nextTest); } } if (constructType != null && constructType != forType) { 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(forType); 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(forType); ctx.BranchIfEqual(startFields, true); } // unexpected, then... note that this *might* be a proxy, which // is handled by ThrowUnexpectedSubtype ctx.LoadValue(forType); 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 == forType) { 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); } }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), wellKnown ? nameof(BclHelpers.WriteTimestamp) : includeKind ? nameof(BclHelpers.WriteDateTimeWithKind) : nameof(BclHelpers.WriteDateTime), valueFrom); }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadValue(valueFrom); ctx.EmitCall(toTail); rootTail.EmitWrite(ctx, null); }
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) => head.EmitCallback(ctx, valueFrom, callbackType);
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadAddress(valueFrom, ExpectedType); ctx.LoadValue(field); ctx.WriteNullCheckedTail(field.FieldType, Tail, null); }
void IProtoTypeSerializer.EmitReadRoot(Compiler.CompilerContext ctx, Compiler.Local valueFrom) => head.EmitReadRoot(ctx, valueFrom);
void IRuntimeProtoSerializerNode.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) => head.EmitRead(ctx, valueFrom);
protected abstract void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom);
void IRuntimeProtoSerializerNode.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitStateBasedWrite(nameof(ProtoWriter.State.WriteInt16), valueFrom); }
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, MuffinProtoBuf.Meta.TypeModel.CallbackType callbackType) { }
void IRuntimeProtoSerializerNode.EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity) { ctx.EmitStateBasedRead(nameof(ProtoReader.State.ReadInt16), ExpectedType); }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDecimal", valueFrom); }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicRead(typeof(BclHelpers), "ReadDateTime", ExpectedType); }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDecimal", ExpectedType); }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { Type expected = ExpectedType; Helpers.DebugAssert(valueFrom != null); using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom)) using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) { // pre-callbacks if (HasCallbacks(TypeModel.CallbackType.BeforeDeserialize)) { if (Helpers.IsValueType(ExpectedType)) { 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, expected, 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, expected, 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); if (valueFrom != null && !loc.IsSame(valueFrom)) { ctx.LoadValue(loc); ctx.Cast(valueFrom.Type); ctx.StoreValue(valueFrom); } } }
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { TypeCode typeCode = GetTypeCode(); if (map == null) { ctx.EmitBasicRead("ReadInt32", typeof(int)); ctx.ConvertFromInt32(typeCode); } 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].Value; } using (Compiler.Local result = new Compiler.Local(ctx, ExpectedType)) using (Compiler.Local wireValue = new Compiler.Local(ctx, typeof(int))) { ctx.EmitBasicRead("ReadInt32", 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(typeof(ProtoReader).GetMethod("ThrowEnumException")); ctx.MarkLabel(@continue); ctx.LoadValue(result); } } }
protected override void EmitWrite(CompilerContext ctx, Local valueFrom) { Type itemType = typeof(KeyValuePair <TKey, TValue>); MethodInfo moveNext, current, getEnumerator = ListDecorator.GetEnumeratorInfo( ExpectedType, itemType, out moveNext, out current); Type enumeratorType = getEnumerator.ReturnType; MethodInfo key = itemType.GetProperty(nameof(KeyValuePair <TKey, TValue> .Key)).GetGetMethod(), @value = itemType.GetProperty(nameof(KeyValuePair <TKey, TValue> .Value)).GetGetMethod(); using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom)) using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) using (Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken))) using (Compiler.Local kvp = new Compiler.Local(ctx, itemType)) { ctx.LoadAddress(list, ExpectedType); ctx.EmitCall(getEnumerator, ExpectedType); ctx.StoreValue(iter); using (ctx.Using(iter)) { Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel(); ctx.Branch(next, false); ctx.MarkLabel(body); ctx.LoadAddress(iter, enumeratorType); ctx.EmitCall(current, enumeratorType); if (itemType != typeof(object) && current.ReturnType == typeof(object)) { ctx.CastFromObject(itemType); } ctx.StoreValue(kvp); ctx.LoadValue(fieldNumber); ctx.LoadValue((int)wireType); ctx.LoadWriter(true); ctx.EmitCall(Compiler.WriterUtil.GetStaticMethod("WriteFieldHeader")); ctx.LoadNullRef(); ctx.LoadWriter(true); ctx.EmitCall(Compiler.WriterUtil.GetStaticMethod("StartSubItem")); ctx.StoreValue(token); ctx.LoadAddress(kvp, itemType); ctx.EmitCall(key, itemType); ctx.WriteNullCheckedTail(typeof(TKey), keyTail, null); ctx.LoadAddress(kvp, itemType); ctx.EmitCall(value, itemType); ctx.WriteNullCheckedTail(typeof(TValue), Tail, null); ctx.LoadValue(token); ctx.LoadWriter(true); ctx.EmitCall(Compiler.WriterUtil.GetStaticMethod("EndSubItem")); ctx.MarkLabel(@next); ctx.LoadAddress(iter, enumeratorType); ctx.EmitCall(moveNext, enumeratorType); ctx.BranchIfTrue(body, false); } } }
private static void WriteEnumValue(Compiler.CompilerContext ctx, TypeCode typeCode, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, object value, Compiler.Local local) { ctx.MarkLabel(handler); WriteEnumValue(ctx, typeCode, value); ctx.StoreValue(local); ctx.Branch(@continue, false); // "continue" }
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.LoadValue(valueFrom); ctx.LoadValue(typeof(Uri).GetProperty("AbsoluteUri")); Tail.EmitWrite(ctx, null); }
private void EmitWriteArrayLoop(Compiler.CompilerContext ctx, Compiler.Local i, Compiler.Local arr) { // i = 0 ctx.LoadValue(0); ctx.StoreValue(i); // range test is last (to minimise branches) Compiler.CodeLabel loopTest = ctx.DefineLabel(), processItem = ctx.DefineLabel(); ctx.Branch(loopTest, false); ctx.MarkLabel(processItem); // {...} ctx.LoadArrayValue(arr, i); if (SupportNull) { Tail.EmitWrite(ctx, null); } else { ctx.WriteNullCheckedTail(itemType, Tail, null); } // i++ ctx.LoadValue(i); ctx.LoadValue(1); ctx.Add(); ctx.StoreValue(i); // i < arr.Length ctx.MarkLabel(loopTest); ctx.LoadValue(i); ctx.LoadLength(arr, false); ctx.BranchIfLess(processItem, false); }
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { ctx.EmitBasicWrite("WriteBoolean", valueFrom); }
protected override void EmitRead(UcAsp.RPC.ProtoBuf.Compiler.CompilerContext ctx, UcAsp.RPC.ProtoBuf.Compiler.Local valueFrom) { Type listType; #if NO_GENERICS listType = typeof(BasicList); #else listType = ctx.MapType(typeof(System.Collections.Generic.List <>)).MakeGenericType(itemType); #endif Type expected = ExpectedType; using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null) using (Compiler.Local newArr = new Compiler.Local(ctx, expected)) using (Compiler.Local list = new Compiler.Local(ctx, listType)) { ctx.EmitCtor(listType); ctx.StoreValue(list); ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false); // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList using (Compiler.Local oldLen = AppendToCollection ? new UcAsp.RPC.ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) { Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) }; if (AppendToCollection) { ctx.LoadLength(oldArr, true); ctx.CopyValue(); ctx.StoreValue(oldLen); ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.Add(); ctx.CreateArray(itemType, null); // length is on the stack ctx.StoreValue(newArr); ctx.LoadValue(oldLen); Compiler.CodeLabel nothingToCopy = ctx.DefineLabel(); ctx.BranchIfFalse(nothingToCopy, true); ctx.LoadValue(oldArr); ctx.LoadValue(newArr); ctx.LoadValue(0); // index in target ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args)); ctx.MarkLabel(nothingToCopy); ctx.LoadValue(list); ctx.LoadValue(newArr); ctx.LoadValue(oldLen); } else { ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.CreateArray(itemType, null); ctx.StoreValue(newArr); ctx.LoadAddress(list, listType); ctx.LoadValue(newArr); ctx.LoadValue(0); } copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int) MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); if (copyTo == null) { // fallback: CopyTo(Array, int) copyToArrayInt32Args[1] = ctx.MapType(typeof(Array)); copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); } ctx.EmitCall(copyTo); } ctx.LoadValue(newArr); } }
protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { /* This looks more complex than it is. Look at the non-compiled Read to * see what it is trying to do, but note that it needs to cope with a * few more scenarios. Note that it picks the **most specific** Add, * unlike the runtime version that uses IList when possible. The core * is just a "do {list.Add(readValue())} while {thereIsMore}" * * The complexity is due to: * - value types vs reference types (boxing etc) * - initialization if we need to pass in a value to the tail * - handling whether or not the tail *returns* the value vs updates the input */ bool returnList = ReturnList; using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : new Compiler.Local(ctx, declaredType)) using (Compiler.Local origlist = (returnList && AppendToCollection && !Helpers.IsValueType(ExpectedType)) ? new Compiler.Local(ctx, ExpectedType) : null) { if (!AppendToCollection) { // always new ctx.LoadNullRef(); ctx.StoreValue(list); } else if (returnList && origlist != null) { // need a copy ctx.LoadValue(list); ctx.StoreValue(origlist); } if (concreteType != null) { ctx.LoadValue(list); Compiler.CodeLabel notNull = ctx.DefineLabel(); ctx.BranchIfTrue(notNull, true); ctx.EmitCtor(concreteType); ctx.StoreValue(list); ctx.MarkLabel(notNull); } bool castListForAdd = !add.DeclaringType.IsAssignableFrom(declaredType); EmitReadList(ctx, list, Tail, add, packedWireType, castListForAdd); if (returnList) { if (AppendToCollection && origlist != null) { // remember ^^^^ we had a spare copy of the list on the stack; now we'll compare ctx.LoadValue(origlist); ctx.LoadValue(list); // [orig] [new-value] Compiler.CodeLabel sameList = ctx.DefineLabel(), allDone = ctx.DefineLabel(); ctx.BranchIfEqual(sameList, true); ctx.LoadValue(list); ctx.Branch(allDone, true); ctx.MarkLabel(sameList); ctx.LoadNullRef(); ctx.MarkLabel(allDone); } else { ctx.LoadValue(list); } } } }
protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { // int i and T[] arr using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom)) using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int)))) { bool writePacked = (options & OPTIONS_WritePacked) != 0; using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null) { Type mappedWriter = ctx.MapType(typeof(ProtoWriter)); if (writePacked) { ctx.LoadValue(fieldNumber); ctx.LoadValue((int)WireType.String); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader")); ctx.LoadValue(arr); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("StartSubItem")); ctx.StoreValue(token); ctx.LoadValue(fieldNumber); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("SetPackedField")); } EmitWriteArrayLoop(ctx, i, arr); if (writePacked) { ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(mappedWriter.GetMethod("EndSubItem")); } } } }