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) ? new Compiler.Local(ctx, ExpectedType) : null) { if (!AppendToCollection) { // always new ctx.LoadNullRef(); ctx.StoreValue(list); } else if (returnList) { // 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); } EmitReadList(ctx, list, Tail, add, packedWireType); if (returnList) { if (AppendToCollection) { // 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); } } } }
internal static void EmitReadList(ProtoBuf.Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, WireType packedWireType) { using (Compiler.Local fieldNumber = new Compiler.Local(ctx, typeof(int))) { Compiler.CodeLabel readPacked = packedWireType == WireType.None ? new Compiler.CodeLabel() : ctx.DefineLabel(); if (packedWireType != WireType.None) { ctx.LoadReaderWriter(); ctx.LoadValue(typeof(ProtoReader).GetProperty("WireType")); ctx.LoadValue((int)WireType.String); ctx.BranchIfEqual(readPacked, false); } ctx.LoadReaderWriter(); ctx.LoadValue(typeof(ProtoReader).GetProperty("FieldNumber")); ctx.StoreValue(fieldNumber); Compiler.CodeLabel @continue = ctx.DefineLabel(); ctx.MarkLabel(@continue); EmitReadAndAddItem(ctx, list, tail, add); ctx.LoadReaderWriter(); ctx.LoadValue(fieldNumber); ctx.EmitCall(typeof(ProtoReader).GetMethod("TryReadFieldHeader")); ctx.BranchIfTrue(@continue, false); if (packedWireType != WireType.None) { Compiler.CodeLabel allDone = ctx.DefineLabel(); ctx.Branch(allDone, false); ctx.MarkLabel(readPacked); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoReader).GetMethod("StartSubItem")); Compiler.CodeLabel testForData = ctx.DefineLabel(), noMoreData = ctx.DefineLabel(); ctx.MarkLabel(testForData); ctx.LoadValue((int)packedWireType); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoReader).GetMethod("HasSubValue")); ctx.BranchIfFalse(noMoreData, false); EmitReadAndAddItem(ctx, list, tail, add); ctx.Branch(testForData, false); ctx.MarkLabel(noMoreData); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoReader).GetMethod("EndSubItem")); ctx.MarkLabel(allDone); } } }
protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom)) { MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(out moveNext, out current); Helpers.DebugAssert(moveNext != null); Helpers.DebugAssert(current != null); Helpers.DebugAssert(getEnumerator != null); Type enumeratorType = getEnumerator.ReturnType; bool writePacked = WritePacked; using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, typeof(SubItemToken)) : null) { if (writePacked) { ctx.LoadValue(fieldNumber); ctx.LoadValue((int)WireType.String); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteFieldHeader")); ctx.LoadValue(list); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("StartSubItem")); ctx.StoreValue(token); ctx.LoadValue(fieldNumber); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("SetPackedField")); } ctx.LoadAddress(list, 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(iter, enumeratorType); ctx.EmitCall(current); Type itemType = Tail.ExpectedType; if (itemType != typeof(object) && current.ReturnType == typeof(object)) { ctx.CastFromObject(itemType); } Tail.EmitWrite(ctx, null); ctx.MarkLabel(@next); ctx.LoadAddress(iter, enumeratorType); ctx.EmitCall(moveNext); ctx.BranchIfTrue(body, false); } if (writePacked) { ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("EndSubItem")); } } } }
protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { if (arrayType.GetArrayRank() > 1) { return; } // int i and T[] arr using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom)) using (Compiler.Local len = new Compiler.Local(ctx, typeof(int))) using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, typeof(int))) using (Compiler.Local writeObject = new Compiler.Local(ctx, typeof(bool))) { // int len = arr.Count; ctx.LoadValue(arr); ctx.LoadValue(arrayType.GetProperty("Length")); ctx.StoreValue(len); // writeObject = true; ctx.LoadValue(true); ctx.StoreValue(writeObject); bool writePacked = (options & OPTIONS_WritePacked) != 0; using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, typeof(SubItemToken)) : null) { if (writePacked) { ctx.LoadValue(fieldNumber); ctx.LoadValue((int)WireType.String); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteFieldHeader")); ctx.LoadValue(arr); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("StartSubItem")); ctx.StoreValue(token); ctx.LoadValue(fieldNumber); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("SetPackedField")); } else { ctx.LoadValue(fieldNumber); ctx.LoadValue((int)WireType.Variant); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteFieldHeader")); if (AsReference) { using (Compiler.Local existing = new Compiler.Local(ctx, typeof(bool))) using (Compiler.Local objectKey = new Compiler.Local(ctx, typeof(int))) { //int objectKey = dest.NetCache.AddObjectKey(value, out existing); ctx.LoadReaderWriter(); ctx.LoadValue(typeof(ProtoWriter).GetProperty("NetCache")); //dest.NetCache ctx.LoadValue(arr); ctx.LoadAddress(existing, typeof(bool)); ctx.EmitCall(typeof(NetObjectCache).GetMethod("AddObjectKey", new Type[] { typeof(object), typeof(bool).MakeByRefType() })); ctx.StoreValue(objectKey); //writeObject = !existing; ctx.LoadValue(existing); Compiler.CodeLabel @writeBoolean = ctx.DefineLabel(); Compiler.CodeLabel @trueCase = ctx.DefineLabel(); ctx.BranchIfTrue(@trueCase, true); ctx.LoadValue(true); ctx.Branch(@writeBoolean, true); ctx.MarkLabel(@trueCase); ctx.LoadValue(false); ctx.MarkLabel(@writeBoolean); ctx.StoreValue(writeObject); //ProtoWriter.WriteUInt32(existing ? (uint)objectKey : 0, dest); using (Compiler.Local valueToWrite = new Compiler.Local(ctx, typeof(uint))) { ctx.LoadValue(0); ctx.StoreValue(valueToWrite); Compiler.CodeLabel @endValueWrite = ctx.DefineLabel(); ctx.LoadValue(existing); ctx.BranchIfFalse(@endValueWrite, true); ctx.LoadValue(objectKey); ctx.CastToObject(typeof(uint)); ctx.StoreValue(valueToWrite); ctx.MarkLabel(@endValueWrite); ctx.LoadValue(valueToWrite); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteUInt32")); } } } else { // bool isEmpty = len == 0; // ProtoWriter.WriteBoolean(isEmpty, dest); ctx.LoadValue(len); ctx.LoadValue(0); ctx.TestEqual(); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("WriteBoolean")); } } Compiler.CodeLabel @endWrite = ctx.DefineLabel(); ctx.LoadValue(writeObject); ctx.BranchIfFalse(@endWrite, false); EmitWriteArrayLoop(ctx, i, arr); ctx.MarkLabel(@endWrite); if (writePacked) { ctx.LoadValue(token); ctx.LoadReaderWriter(); ctx.EmitCall(typeof(ProtoWriter).GetMethod("EndSubItem")); } } } }