private static KeyValuePair <Delegate, IntPtr>[] GetReaders(ReaderMethodBuilderContext context) { var result = new KeyValuePair <Delegate, IntPtr> [256]; foreach (var type in GroBufHelpers.LeafTypes.Where(type => type != null)) { result[(int)GroBufTypeCodeMap.GetTypeCode(type)] = GetReader(context, type); } result[(int)GroBufTypeCode.DateTimeOld] = result[(int)GroBufTypeCode.DateTimeNew]; return(result); }
protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); context.WriteTypeCode(typeCode); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], ref obj] il.Ldfld(countField); // stack: [&result[index], obj._count] CountArraySize(elementType, il); // stack: [&result[index], obj size] il.Dup(); // stack: [&result[index], obj size, obj size] il.Stloc(size); // size = obj size; stack: [&result[index], obj size] il.Stind(typeof(int)); // result[index] = size; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] var doneLabel = il.DefineLabel("done"); il.Ldloc(size); // stack: [size] il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] il.Ldloc(size); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], ref obj] il.Ldfld(arrayField); // stack: [&result[index], obj._array] context.LoadObjByRef(); // stack: [&result[index], obj._array, ref obj] il.Ldfld(offsetField); // stack: [&result[index], obj._array, obj._offset] il.Ldelema(elementType); // stack: [&result[index], &obj._array[obj._offset]] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); il.Stloc(arr); // arr = &obj._array[obj._offset]; stack: [&result[index]] il.Ldloc(arr); // stack: [&result[index], arr] il.Ldloc(size); // stack: [&result[index], arr + obj._offset, size] il.Cpblk(); // &result[index] = arr il.FreePinnedLocal(arr); // arr = null; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size il.MarkLabel(doneLabel); }
protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); il.Ldc_I4(4); context.AssertLength(); var size = il.DeclareLocal(typeof(int)); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObj(); // stack: [&result[index], obj] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj.Count] CountArraySize(elementType, il); // stack: [&result[index], obj size] il.Dup(); // stack: [&result[index], obj size, obj size] il.Stloc(size); // size = obj size; stack: [&result[index], obj size] il.Stind(typeof(int)); // result[index] = size; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(size); // stack: [size] var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] il.Ldloc(size); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObj(); // stack: [&result[index], obj] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj._items] il.Ldc_I4(0); // stack: [&result[index], obj._items, 0] il.Ldelema(elementType); // stack: [&result[index], &obj._items[0]] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); il.Stloc(arr); // arr = &obj._items[0]; stack: [&result[index]] il.Ldloc(arr); // stack: [&result[index], arr] il.Ldloc(size); // stack: [&result[index], arr, size] il.Cpblk(); // &result[index] = arr il.FreePinnedLocal(arr); // arr = null; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size il.MarkLabel(doneLabel); }
protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) { var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); var il = context.Il; switch (typeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Ldc_I4(2); break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Ldc_I4(3); break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Ldc_I4(5); break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Ldc_I4(9); break; case GroBufTypeCode.Single: il.Ldc_I4(5); break; case GroBufTypeCode.Double: il.Ldc_I4(9); break; case GroBufTypeCode.Decimal: il.Ldc_I4(17); break; default: throw new NotSupportedException("Type '" + Type + "' is not supported"); } }
private static void MakeShift(Type elementType, GroboIL il) { var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); switch (typeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Ldc_I4(1); il.Shl(); break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Ldc_I4(2); il.Shl(); break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Ldc_I4(3); il.Shl(); break; case GroBufTypeCode.Single: il.Ldc_I4(2); il.Shl(); break; case GroBufTypeCode.Double: il.Ldc_I4(3); il.Shl(); break; default: throw new NotSupportedException("Type '" + elementType + "' is not supported"); } }
private KeyValuePair <Delegate, IntPtr> BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode) { var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] { typeof(IntPtr), Type.MakeByRefType() }, module, true); using (var il = new GroboIL(method)) { var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type); il.Ldarg(1); // stack: [ref result] if (typeCode == GroBufTypeCode.Decimal) { if (expectedTypeCode == GroBufTypeCode.Boolean) { il.Ldarg(0); // stack: [ref result, &temp, address] il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] il.Ldarg(0); // stack: [ref result, &temp + 8, address] il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] il.Add(); // stack: [ref result, &temp + 8, address + 8] il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] il.Or(); il.Ldc_I4(0); // stack: [ref result, value, 0] il.Conv <long>(); il.Ceq(); // stack: [ref result, value == 0] il.Ldc_I4(1); // stack: [ref result, value == 0, 1] il.Xor(); // stack: [ref result, value != 0] } else { var temp = il.DeclareLocal(typeof(decimal)); il.Ldloca(temp); // stack: [ref result, &temp] il.Ldarg(0); // stack: [ref result, &temp, address] il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] il.Stind(typeof(long)); // *temp = *address; il.Ldloca(temp); // stack: [ref result, &temp] il.Ldc_I4(8); // stack: [ref result, &temp, 8] il.Add(); // stack: [ref result, &temp + 8] il.Ldarg(0); // stack: [ref result, &temp + 8, address] il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] il.Add(); // stack: [ref result, &temp + 8, address + 8] il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] il.Stind(typeof(long)); // *(temp + 8) = *(address + 8); il.Ldloc(temp); // stack: [ref result, ref temp] switch (expectedTypeCode) { case GroBufTypeCode.Int8: il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp] break; case GroBufTypeCode.UInt8: il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp] break; case GroBufTypeCode.Int16: il.Call(decimalToInt16Method); // stack: [ref result, (short)temp] break; case GroBufTypeCode.UInt16: il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp] break; case GroBufTypeCode.Int32: il.Call(decimalToInt32Method); // stack: [ref result, (int)temp] break; case GroBufTypeCode.UInt32: il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp] break; case GroBufTypeCode.Int64: il.Call(decimalToInt64Method); // stack: [ref result, (long)temp] break; case GroBufTypeCode.UInt64: il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp] break; case GroBufTypeCode.Single: il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp] break; case GroBufTypeCode.Double: il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp] break; case GroBufTypeCode.Decimal: break; default: throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); } } } else { il.Ldarg(0); // stack: [ref result, address] EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value] if (Type == typeof(bool)) { il.Conv <long>(); il.Ldc_I4(0); // stack: [ref result, value, 0] il.Conv <long>(); il.Ceq(); // stack: [ref result, value == 0] il.Ldc_I4(1); // stack: [ref result, value == 0, 1] il.Xor(); // stack: [ref result, value != 0] } else { EmitConvertValue(il, typeCode, expectedTypeCode); } } switch (expectedTypeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Stind(typeof(byte)); // result = value break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Stind(typeof(short)); // result = value break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Stind(typeof(int)); // result = value break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Stind(typeof(long)); // result = value break; case GroBufTypeCode.Single: il.Stind(typeof(float)); // result = value break; case GroBufTypeCode.Double: il.Stind(typeof(double)); // result = value break; case GroBufTypeCode.Decimal: il.Stobj(typeof(decimal)); // result = value break; default: throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); } il.Ret(); } var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate <>).MakeGenericType(Type)); return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method))); }
protected override void ReadNotEmpty(ReaderMethodBuilderContext context) { context.IncreaseIndexBy1(); context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); var il = context.Il; var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] il.Dup(); // stack: [data length, data length] il.Stloc(size); // size = data length; stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); var count = context.Length; il.Ldloc(size); // stack: [size] CountArrayLength(elementType, il); // stack: [array length] il.Stloc(count); // count = array length context.LoadResultByRef(); // stack: [ref result] il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] il.Dup(); // stack: [ref result, hashSet, hashSet] il.Ldloc(count); // stack: [ref result, hashSet, hashSet, count] var initializeMethod = Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic); il.Call(initializeMethod); // hashSet.Initialize(count); stack: [ref result, hashSet] or [ref result, hashSet, actualHashSetSize] if (initializeMethod.ReturnType != typeof(void)) { il.Pop(); // stack: [ref result, hashSet] } il.Stind(Type); // result = hashSet; stack: [] il.Ldloc(count); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(count == 0) goto allDone; stack: [] var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); context.LoadResult(Type); // stack: [result] context.GoToCurrentLocation(); // stack: [result, &data[index]] il.Ldloc(i); // stack: [result, &data[index], i] MakeShift(elementType, il); // stack: [result, &data[index], i << x] il.Add(); // stack: [result, current] il.Ldind(elementType); // stack: [result, *current] il.Call(Type.GetMethod("Add")); // stack: [result.Add(*current)] il.Pop(); // stack: [] il.Ldloc(count); // stack: [count] il.Ldloc(i); // stack: [current, count, i] il.Ldc_I4(1); // stack: [current, count, i, 1] il.Add(); // stack: [current, count, i + 1] il.Dup(); // stack: [current, count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [current, count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size il.MarkLabel(doneLabel); // stack: [] }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var il = context.Il; context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [obj] il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] CountArraySize(elementType, il); // stack: [obj size] il.Stloc(size); // size = obj size; stack: [] context.GoToCurrentLocation(); // stack: [&result[index]] il.Ldloc(size); // stack: [&result[index], size] il.Stind(typeof(int)); // result[index] = size; stack: [] context.IncreaseIndexBy4(); // index = index + 4; stack: [] il.Ldloc(size); context.AssertLength(); context.LoadObj(); // stack: [obj] var slotType = Type.GetNestedType(PlatformHelpers.HashSetSlotTypeName, BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); var slots = il.DeclareLocal(slotType.MakeArrayType()); il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetSlotsFieldNames)); il.Stloc(slots); context.LoadObj(); // stack: [obj] il.Ldfld(Type.GetPrivateInstanceField(PlatformHelpers.HashSetCountFieldNames)); // stack: [obj.m_lastIndex] il.Dup(); var count = context.LocalInt; il.Stloc(count); // count = obj.m_lastIndex; stack: [count] var writeDataLengthLabel = il.DefineLabel("writeDataLength"); il.Brfalse(writeDataLengthLabel); var i = il.DeclareLocal(typeof(int)); il.Ldc_I4(0); // stack: [0] il.Stloc(i); // i = 0; stack: [] context.GoToCurrentLocation(); // stack: [&result[index]] var cycleStartLabel = il.DefineLabel("cycleStart"); il.MarkLabel(cycleStartLabel); il.Ldloc(slots); // stack: [current, slots] il.Ldloc(i); // stack: [current, slots, i] il.Ldelema(slotType); // stack: [current, &slots[i]] il.Dup(); // stack: [current, &slots[i], &slots[i]] var slot = il.DeclareLocal(slotType.MakeByRefType()); il.Stloc(slot); // slot = &slots[i]; stack: [current, slot] if (PlatformHelpers.IsDotNet50OrGreater) { il.Ldfld(slotType.GetField("Next")); // stack: [current, slot.Next] il.Ldc_I4(-1); // stack: [current, slot.Next, -1] } else { il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, slot.hashCode] il.Ldc_I4(0); // stack: [current, slot.hashCode, 0] } var nextLabel = il.DefineLabel("next"); il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [current] il.Dup(); // stack: [current, current] il.Ldloc(slot); // stack: [current, current, slot] il.Ldfld(slotType.GetField(PlatformHelpers.HashSetSlotValueFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); // stack: [current, current, slot.value] il.Stind(elementType); // *current = slot.value; stack: [current] LoadItemSize(elementType, il); // stack: [current, item size] il.Add(); // stack: [current + item size] il.MarkLabel(nextLabel); il.Ldloc(count); // stack: [current, count] il.Ldloc(i); // stack: [current, count, i] il.Ldc_I4(1); // stack: [current, count, i, 1] il.Add(); // stack: [current, count, i + 1] il.Dup(); // stack: [current, count, i + 1, i + 1] il.Stloc(i); // i = i + 1; stack: [current, count, i] il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] il.Pop(); // stack: [] il.MarkLabel(writeDataLengthLabel); context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size }
protected override void WriteNotEmpty(WriterMethodBuilderContext context) { var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); context.WriteTypeCode(typeCode); context.GoToCurrentLocation(); // stack: [&result[index]] var il = context.Il; switch (typeCode) { case GroBufTypeCode.Int8: case GroBufTypeCode.UInt8: case GroBufTypeCode.Boolean: il.Ldc_I4(1); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(byte)); // result[index] = obj context.IncreaseIndexBy1(); // index = index + 1 break; case GroBufTypeCode.Int16: case GroBufTypeCode.UInt16: il.Ldc_I4(2); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(short)); // result[index] = obj context.IncreaseIndexBy2(); // index = index + 2 break; case GroBufTypeCode.Int32: case GroBufTypeCode.UInt32: il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(int)); // result[index] = obj context.IncreaseIndexBy4(); // index = index + 4 break; case GroBufTypeCode.Int64: case GroBufTypeCode.UInt64: il.Ldc_I4(8); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(long)); // result[index] = obj context.IncreaseIndexBy8(); // index = index + 8 break; case GroBufTypeCode.Single: il.Ldc_I4(4); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(float)); // result[index] = obj context.IncreaseIndexBy4(); // index = index + 4 break; case GroBufTypeCode.Double: il.Ldc_I4(8); context.AssertLength(); context.LoadObj(); // stack: [&result[index], obj] il.Stind(typeof(double)); // result[index] = obj context.IncreaseIndexBy8(); // index = index + 8 break; case GroBufTypeCode.Decimal: il.Ldc_I4(16); context.AssertLength(); context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] il.Stind(typeof(long)); // result[index] = (int64)*obj context.IncreaseIndexBy8(); // index = index + 8 context.GoToCurrentLocation(); // stack: [&result[index]] context.LoadObjByRef(); // stack: [&result[index], &obj] il.Ldc_I4(8); // stack: [&result[index], &obj, 8] il.Add(); // stack: [&result[index], &obj + 8] il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) context.IncreaseIndexBy8(); // index = index + 8 break; default: throw new NotSupportedException(); } }
protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) { context.IncreaseIndexBy1(); context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); var il = context.Il; var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] il.Dup(); // stack: [data length, data length] il.Stloc(size); // size = data length; stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); var length = context.Length; il.Ldloc(size); // stack: [size] CountArrayLength(elementType, il); // stack: [array length] il.Stloc(length); // length = array length if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; stack: [] context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] il.Ldlen(); // stack: [result._items.Length] il.Ldloc(length); // stack: [result.Length, length] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; context.LoadResult(Type); // stack: [result] il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] il.Ldloc(length); // stack: [ref result, length] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] il.Stind(Type); // result = new List(length); stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] il.Stind(Type); // result = new List(length); stack: [] } il.Ldloc(length); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] il.Ldc_I4(0); // stack: [result._items, 0] il.Ldelema(elementType); // stack: [&result._items[0]] il.Stloc(arr); // arr = &result._items[0]; stack: [] il.Ldloc(arr); // stack: [arr] context.GoToCurrentLocation(); // stack: [arr, &data[index]] il.Ldloc(length); // stack: [arr, &data[index], length] CountArraySize(elementType, il); // stack: [arr, &data[index], size] il.Cpblk(); // arr = &data[index] il.FreePinnedLocal(arr); // arr = null; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { context.LoadResult(Type); // stack: [result] il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] il.Ldloc(length); // stack: [result.Count, length] il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] } context.LoadResult(Type); // stack: [result] il.Ldloc(length); // stack: [result.Count, length] il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] il.MarkLabel(doneLabel); // stack: [] }
protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) { var il = context.Il; il.Ldloc(context.TypeCode); // stack: [type code] il.Ldc_I4((int)GroBufTypeCodeMap.GetTypeCode(Type)); // stack: [type code, GroBufTypeCode(Type)] var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode(Type)) goto tryReadArrayElement; stack: [] context.IncreaseIndexBy1(); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] il.Dup(); // stack: [data length, data length] il.Stloc(size); // size = data length; stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); var length = context.Length; il.Ldloc(size); // stack: [size] CountArrayLength(elementType, il); // stack: [array length] il.Stloc(length); // length = array length var array = il.DeclareLocal(elementType.MakeArrayType()); context.LoadResultByRef(); // stack: [ref result] il.Dup(); // stack: [ref result, ref result] il.Ldc_I4(0); // stack: [ref result, ref result, 0] il.Stfld(offsetField); // result._offset = 0; stack: [ref result] il.Dup(); // stack: [ref result, ref result] il.Ldloc(length); // stack: [ref result, ref result, length] il.Stfld(countField); // result._count = length; stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newarr(elementType); // stack: [ref result, new type[length]] il.Dup(); il.Stloc(array); // array = new type[length]; stack: [ref result] il.Stfld(arrayField); // result._array = array; stack: [] il.Ldloc(length); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); il.Ldloc(array); // stack: [array] il.Ldc_I4(0); // stack: [array, 0] il.Ldelema(elementType); // stack: [&array[0]] il.Stloc(arr); // arr = &array[0]; stack: [] il.Ldloc(arr); // stack: [arr] context.GoToCurrentLocation(); // stack: [arr, &data[index]] il.Ldloc(length); // stack: [arr, &data[index], length] CountArraySize(elementType, il); // stack: [arr, &data[index], size] il.Cpblk(); // arr = &data[index] il.FreePinnedLocal(arr); // arr = null; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size il.Br(doneLabel); il.MarkLabel(tryReadArrayElementLabel); context.LoadResultByRef(); // stack: [ref result] il.Dup(); // stack: [ref result, ref result] il.Ldc_I4(0); // stack: [ref result, ref result, 0] il.Stfld(offsetField); // result._offset = 0; stack: [ref result] il.Dup(); // stack: [ref result, ref result] il.Ldc_I4(1); // stack: [ref result, ref result, 1] il.Stfld(countField); // result._count = 1; stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Newarr(elementType); // stack: [ref result, new type[1]] il.Dup(); il.Stloc(array); // array = new type[1]; stack: [ref result] il.Stfld(arrayField); // result._array = array; stack: [] context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] il.Ldloc(array); // stack: [pinnedData, ref index, array] il.Ldc_I4(0); // stack: [pinnedData, ref index, array, 0] il.Ldelema(elementType); // stack: [pinnedData, ref index, ref array[0]] context.LoadContext(); // stack: [pinnedData, ref index, ref array[0], context] context.CallReader(elementType); // reader(pinnedData, ref index, ref array[0], context); stack: [] il.MarkLabel(doneLabel); // stack: [] }
protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) { var il = context.Il; il.Ldloc(context.TypeCode); // stack: [type code] il.Ldc_I4((int)GroBufTypeCodeMap.GetTypeCode(Type)); // stack: [type code, GroBufTypeCode(Type)] var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode(Type)) goto tryReadArrayElement; stack: [] context.IncreaseIndexBy1(); var size = il.DeclareLocal(typeof(int)); il.Ldc_I4(4); context.AssertLength(); context.GoToCurrentLocation(); // stack: [&data[index]] il.Ldind(typeof(uint)); // stack: [data length] il.Dup(); // stack: [data length, data length] il.Stloc(size); // size = data length; stack: [data length] context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] context.AssertLength(); var length = context.Length; il.Ldloc(size); // stack: [size] CountArrayLength(elementType, il); // stack: [array length] il.Stloc(length); // length = array length if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; context.LoadResult(Type); // stack: [result] il.Ldlen(); // stack: [result.Length] il.Ldloc(length); // stack: [result.Length, length] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newarr(elementType); // stack: [ref result, new type[length]] il.Stind(Type); // result = new type[length]; stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldloc(length); // stack: [ref result, length] il.Newarr(elementType); // stack: [ref result, new type[length]] il.Stind(Type); // result = new type[length]; stack: [] } il.Ldloc(length); var doneLabel = il.DefineLabel("done"); il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] var arr = il.DeclareLocal(elementType.MakeByRefType(), true); context.LoadResult(Type); // stack: [result] il.Ldc_I4(0); // stack: [result, 0] il.Ldelema(elementType); // stack: [&result[0]] il.Stloc(arr); // arr = &result[0]; stack: [] il.Ldloc(arr); // stack: [arr] context.GoToCurrentLocation(); // stack: [arr, &data[index]] il.Ldloc(length); // stack: [arr, &data[index], length] CountArraySize(elementType, il); // stack: [arr, &data[index], size] il.Cpblk(); // arr = &data[index] il.FreePinnedLocal(arr); // arr = null; stack: [] context.LoadIndexByRef(); // stack: [ref index] context.LoadIndex(); // stack: [ref index, index] il.Ldloc(size); // stack: [ref index, index, size] il.Add(); // stack: [ref index, index + size] il.Stind(typeof(int)); // index = index + size il.Br(doneLabel); il.MarkLabel(tryReadArrayElementLabel); if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) { var createArrayLabel = il.DefineLabel("createArray"); context.LoadResult(Type); // stack: [result] il.Brfalse(createArrayLabel); // if(result == null) goto createArray; context.LoadResult(Type); // stack: [result] il.Ldlen(); // stack: [result.Length] il.Ldc_I4(1); // stack: [result.Length, 1] var arrayCreatedLabel = il.DefineLabel("arrayCreated"); il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, 1) il.Br(arrayCreatedLabel); // goto arrayCreated il.MarkLabel(createArrayLabel); context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Newarr(elementType); // stack: [ref result, new type[1]] il.Stind(Type); // result = new type[1]; stack: [] il.MarkLabel(arrayCreatedLabel); } else { context.LoadResultByRef(); // stack: [ref result] il.Ldc_I4(1); // stack: [ref result, 1] il.Newarr(elementType); // stack: [ref result, new type[1]] il.Stind(Type); // result = new type[1]; stack: [] } context.LoadData(); // stack: [pinnedData] context.LoadIndexByRef(); // stack: [pinnedData, ref index] context.LoadResult(Type); // stack: [pinnedData, ref index, result] il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] il.MarkLabel(doneLabel); // stack: [] }