Exemplo n.º 1
0
        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);
        }
Exemplo n.º 4
0
        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");
            }
        }
Exemplo n.º 6
0
        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
        }
Exemplo n.º 9
0
        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: []
        }