protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            context.IncreaseIndexBy1();
            context.AssertTypeCode(GroBufTypeCode.DateTimeOffset); // Assert typeCode == TypeCode.DateTimeOffset
            var il = context.Il;

            context.LoadResultByRef(); // stack: [ref result]
            il.Dup();                  // stack: [ref result, ref result]
            il.Initobj(Type);          // result = default(DateTimeOffset); stack: [ref result]

            context.LoadData();        // stack: [ref result, data]
            context.LoadIndexByRef();  // stack: [ref result, data, ref index]
            var dateTime = il.DeclareLocal(typeof(DateTime));

            il.Ldloca(dateTime);                                                                   // stack: [ref result, data, ref index, ref dateTime]
            context.LoadContext();                                                                 // stack: [ref result, data, ref index, ref dateTime, context]
            context.CallReader(typeof(DateTime));                                                  // reader(pinnedData, ref index, ref dateTime, context); stack: [ref result]
            il.Dup();                                                                              // stack: [ref result, ref result]
            il.Ldloc(dateTime);                                                                    // stack: [ref result, ref result, dateTime]
            il.Stfld(Type.GetField("m_dateTime", BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_dateTime = dateTime; stack: [ref result]

            context.LoadData();                                                                    // stack: [ref result, data]
            context.LoadIndexByRef();                                                              // stack: [ref result, data, ref index]
            var offset = il.DeclareLocal(typeof(short));

            il.Ldloca(offset);                                                                          // stack: [ref result, data, ref index, ref offset]
            context.LoadContext();                                                                      // stack: [ref result, data, ref index, ref offset, context]
            context.CallReader(typeof(short));                                                          // reader(pinnedData, ref index, ref offset, context); stack: [ref result]
            il.Ldloc(offset);                                                                           // stack: [ref result, ref result, offset]
            il.Stfld(Type.GetField("m_offsetMinutes", BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_offsetMinutes = offset; stack: [ref result]
        }
Beispiel #2
0
        private static KeyValuePair <Delegate, IntPtr> GetReader(ReaderMethodBuilderContext context, Type type)
        {
            var method = new DynamicMethod("Read_" + type.Name + "_AndCastToObject_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)
            }, context.Context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(2);      // stack: [ref result]
                il.Ldarg(0);      // stack: [ref result, data]
                il.Ldarg(1);      // stack: [ref result, data, ref index]
                var value = il.DeclareLocal(type);
                il.Ldloca(value); // stack: [ref result, data, ref index, ref value]
                il.Ldarg(3);      // stack: [ref result, data, ref index, ref value, context]

                ReaderMethodBuilderContext.CallReader(il, type, context.Context);

                il.Ldloc(value); // stack: [ref result, value]
                if (type.IsValueType)
                {
                    il.Box(type); // stack: [ref result, (object)value]
                }
                else
                {
                    il.Castclass(type);
                }
                il.Stind(typeof(object)); // result = (object)value
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
Beispiel #3
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            context.LoadResultByRef(); // stack: [ref result]

            context.LoadData();        // stack: [ref result, data]
            context.LoadIndexByRef();  // stack: [ref result, data, ref index]
            var value = il.DeclareLocal(typeof(byte[]));

            il.Ldloca(value);                   // stack: [ref result, data, ref index, ref value]
            context.LoadContext();              // stack: [ref result, data, ref index, ref value, context]
            context.CallReader(typeof(byte[])); // reader(pinnedData, ref index, ref value, context); stack: [ref result]
            il.Ldloc(value);                    // stack: [ref result, value]
            var constructor = Type.GetConstructor(new[] { typeof(byte[]) });

            if (constructor == null)
            {
                throw new MissingConstructorException(Type, typeof(byte[]));
            }
            il.Newobj(constructor); // stack: [ref result, new IPAddress(value)]
            il.Stind(Type);         // result = new IPAddress(value)
        }
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            context.AssertTypeCode(GroBufTypeCode.Tuple);

            context.IncreaseIndexBy1();
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [array length]
            il.Stloc(length);              // length = array length; stack: []

            context.LoadResultByRef();     // stack: [ref result]
            var genericArguments = Type.GetGenericArguments();

            // stack: [ref result, args]
            for (int i = 0; i < genericArguments.Length; ++i)
            {
                context.LoadData();                           // stack: [ref result, args, data]
                context.LoadIndexByRef();                     // stack: [ref result, args, data, ref index]
                var arg = il.DeclareLocal(genericArguments[i]);
                il.Ldloca(arg);                               // stack: [ref result, args, data, ref index, ref arg]
                context.LoadContext();                        // stack: [ref result, args, data, ref index, ref arg, context]
                context.CallReader(genericArguments[i]);      // reader(pinnedData, ref index, ref arg, context); stack: [ref result, args]
                il.Ldloc(arg);                                // stack: [ref result, {args, arg} => args]
            }
            il.Newobj(Type.GetConstructor(genericArguments)); // stack: [ref result, new Tuple(args)]
            il.Stind(Type);                                   // result = new Tuple(args); stack: []

            context.StoreObject(Type);
        }
Beispiel #5
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            context.LoadResultByRef(); // stack: [ref result]

            context.LoadData();        // stack: [ref result, data]
            context.LoadIndexByRef();  // stack: [ref result, data, ref index]
            var argumentType = Type.GetGenericArguments()[0];
            var value        = il.DeclareLocal(argumentType);

            il.Ldloca(value);                 // stack: [ref result, data, ref index, ref value]
            context.LoadContext();            // stack: [ref result, data, ref index, ref value, context]
            context.CallReader(argumentType); // reader(pinnedData, ref index, ref value, context); stack: [ref result]
            il.Ldloc(value);                  // stack: [ref result, value]
            var constructor = Type.GetConstructor(new[] { argumentType });

            if (constructor == null)
            {
                throw new MissingConstructorException(Type, argumentType);
            }
            il.Newobj(constructor); // stack: [ref result, new elementType?(value)]
            il.Stobj(Type);         // result = new elementType?(value)
        }
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            il.Ldloc(context.TypeCode);           // stack: [type code]
            il.Ldc_I4((int)GroBufTypeCode.Array); // stack: [type code, GroBufTypeCode.Array]
            var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement");

            il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode.Array) goto tryReadArrayElement; stack: []

            context.IncreaseIndexBy1();
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [data length]

            context.AssertLength();
            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [array length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [array length]
            il.Stloc(length);              // length = array length; stack: []

            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: []
            }

            context.StoreObject(Type);

            il.Ldloc(length); // stack: [length]
            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: []
            var i = il.DeclareLocal(typeof(uint));

            il.Ldc_I4(0); // stack: [0]
            il.Stloc(i);  // i = 0; stack: []
            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

            context.LoadData();              // stack: [pinnedData]
            context.LoadIndexByRef();        // stack: [pinnedData, ref index]
            context.LoadResult(Type);        // stack: [pinnedData, ref index, result]
            il.Ldloc(i);                     // stack: [pinnedData, ref index, result, i]

            il.Ldelema(elementType);         // stack: [pinnedData, ref index, ref result[i]]
            context.LoadContext();           // stack: [pinnedData, ref index, ref result[i], context]

            context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: []
            il.Ldloc(i);                     // stack: [i]
            il.Ldc_I4(1);                    // stack: [i, 1]
            il.Add();                        // stack: [i + 1]
            il.Dup();                        // stack: [i + 1, i + 1]
            il.Stloc(i);                     // i = i + 1; stack: [i]
            il.Ldloc(length);                // stack: [i, length]
            il.Blt(cycleStartLabel, true);   // if(i < length) goto cycleStart
            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, length)
                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.StoreObject(Type);

            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: []
        }
        private KeyValuePair <Delegate, IntPtr> GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member)
        {
            var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, context.Module, true);

            using (var il = new GroboIL(method))
            {
                il.Ldarg(0); // stack: [data]
                il.Ldarg(1); // stack: [data, ref index]
                switch (member.MemberType)
                {
                case MemberTypes.Field:
                    var field = (FieldInfo)member;
                    var done  = false;
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType)
                    {
                        var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (field.FieldType.IsPrimitive || equalityOperator != null)
                        {
                            var fieldValue = il.DeclareLocal(field.FieldType);
                            il.Ldarg(2); // stack: [data, ref index, ref result]
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldfld(field);
                            il.Stloc(fieldValue);
                            il.Ldloca(fieldValue);
                            il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                            ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []

                            var temp = il.DeclareLocal(field.FieldType);
                            il.Ldloca(temp);
                            il.Initobj(field.FieldType);
                            il.Ldloc(temp);
                            il.Ldloc(fieldValue);
                            if (field.FieldType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                            il.Ldarg(2);
                            if (!Type.IsValueType)
                            {
                                il.Ldind(Type); // stack: [data, ref index, result]
                            }
                            il.Ldloc(fieldValue);
                            il.Stfld(field);
                            done = true;
                        }
                    }
                    if (!done)
                    {
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                  // stack: [data, ref index, result]
                        }
                        il.Ldflda(field);                                                    // stack: [data, ref index, ref result.field]
                        il.Ldarg(3);                                                         // stack: [data, ref index, ref result.field, context]
                        ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: []
                    }
                    break;

                case MemberTypes.Property:
                    var property      = (PropertyInfo)member;
                    var propertyValue = il.DeclareLocal(property.PropertyType);
                    if (context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead))
                    {
                        var getter = property.GetGetMethod(true);
                        if (getter == null)
                        {
                            throw new MissingMethodException(Type.Name, property.Name + "_get");
                        }
                        il.Ldarg(2); // stack: [data, ref index, ref result]
                        if (!Type.IsValueType)
                        {
                            il.Ldind(Type);                                                    // stack: [data, ref index, result]
                        }
                        il.Call(getter, Type);                                                 // stack: [ data, ref index, result.property]
                        il.Stloc(propertyValue);                                               // propertyValue = result.property; stack: [data, ref index]
                    }
                    il.Ldloca(propertyValue);                                                  // stack: [data, ref index, ref propertyValue]
                    il.Ldarg(3);                                                               // stack: [data, ref index, ref propertyValue, context]
                    ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: []
                    if (member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType)
                    {
                        var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                        if (property.PropertyType.IsPrimitive || equalityOperator != null)
                        {
                            var temp = il.DeclareLocal(property.PropertyType);
                            il.Ldloca(temp);
                            il.Initobj(property.PropertyType);
                            il.Ldloc(temp);
                            il.Ldloc(propertyValue);
                            if (property.PropertyType.IsPrimitive)
                            {
                                il.Ceq();
                            }
                            else
                            {
                                il.Call(equalityOperator);
                            }
                            var notDefaultLabel = il.DefineLabel("notDefault");
                            il.Brfalse(notDefaultLabel);
                            il.Ret();
                            il.MarkLabel(notDefaultLabel);
                        }
                    }
                    il.Ldarg(2); // stack: [ref result]
                    if (!Type.IsValueType)
                    {
                        il.Ldind(Type);      // stack: [result]
                    }
                    il.Ldloc(propertyValue); // stack: [result, propertyValue]
                    var setter = property.GetSetMethod(true);
                    if (setter == null)
                    {
                        throw new MissingMethodException(Type.Name, property.Name + "_set");
                    }
                    il.Call(setter, Type); // result.property = propertyValue
                    break;

                default:
                    throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported");
                }
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));

            return(new KeyValuePair <Delegate, IntPtr>(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)));
        }
Beispiel #8
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            context.IncreaseIndexBy1();
            context.AssertTypeCode(GroBufTypeCode.Array);

            var il     = context.Il;
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [data length]

            context.AssertLength();
            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [array length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [array length]
            il.Stloc(length);              // length = array length; stack: []

            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.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items]
                il.Ldlen();                                                                        // stack: [result._items.Length]
                il.Ldloc(length);                                                                  // stack: [result._items.Length, length]

                var arrayCreatedLabel = il.DefineLabel("arrayCreated");
                il.Bge(arrayCreatedLabel, false);                                                   // if(result._items.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._items, 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: []
            }

            context.StoreObject(Type);

            il.Ldloc(length); // stack: [length]
            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel);                                                             // if(length == 0) goto allDone; stack: []
            context.LoadResult(Type);                                                          // stack: [result]
            il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items]
            var items = il.DeclareLocal(elementType.MakeArrayType());

            il.Stloc(items); // items = result._items; stack: []
            var i = il.DeclareLocal(typeof(uint));

            il.Ldc_I4(0); // stack: [0]
            il.Stloc(i);  // i = 0; stack: []
            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

            context.LoadData();              // stack: [pinnedData]
            context.LoadIndexByRef();        // stack: [pinnedData, ref index]
            il.Ldloc(items);                 // stack: [pinnedData, ref index, items]
            il.Ldloc(i);                     // stack: [pinnedData, ref index, items, i]

            il.Ldelema(elementType);         // stack: [pinnedData, ref index, ref items[i]]
            context.LoadContext();           // stack: [pinnedData, ref index, ref items[i], context]

            context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: []
            il.Ldloc(i);                     // stack: [i]
            il.Ldc_I4(1);                    // stack: [i, 1]
            il.Add();                        // stack: [i + 1]
            il.Dup();                        // stack: [i + 1, i + 1]
            il.Stloc(i);                     // i = i + 1; stack: [i]
            il.Ldloc(length);                // stack: [i, length]
            il.Blt(cycleStartLabel, true);   // if(i < length) goto cycleStart

            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: []
        }
Beispiel #9
0
        public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext)
        {
            var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void),
                                           new[]
            {
                typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)
            }, readerTypeBuilderContext.Module, true);

            readerTypeBuilderContext.SetReaderMethod(Type, method);
            using (var il = new GroboIL(method))
            {
                var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference);

                ReadTypeCodeAndCheck(context); // Read TypeCode and check

                if (!Type.IsValueType && IsReference)
                {
                    // Read reference
                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    var notReadLabel = il.DefineLabel("notRead");
                    il.Brfalse(notReadLabel);
                    context.LoadIndex();                  // stack: [external index]
                    context.LoadContext();                // stack: [external index, context]
                    il.Ldfld(ReaderContext.StartField);   // stack: [external index, context.start]
                    il.Sub();                             // stack: [external index - context.start]
                    il.Stloc(context.Index);              // index = external index - context.start; stack: []

                    context.LoadContext();                // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects]
                    il.Ldloc(context.Index);              // stack: [context.objects, index]
                    var obj = il.DeclareLocal(typeof(object));
                    il.Ldloca(obj);
                    object dummy;
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)]
                    il.Brfalse(notReadLabel);                                                                                     // if(!context.objects.TryGetValue(index, out obj)) goto notRead;
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    context.IncreaseIndexBy1();                                                                                   // Skip type code
                    context.SkipValue();                                                                                          // Skip value - it has already been read
                    il.Ret();
                    il.MarkLabel(notReadLabel);
                    il.Ldloc(context.TypeCode);               // stack: [typeCode]
                    il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference]
                    var readUsualLabel = il.DefineLabel("readUsual");
                    il.Bne_Un(readUsualLabel);                // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: []

                    context.LoadContext();                    // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);     // stack: [context.objects]
                    var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull");
                    il.Brtrue(objectsIsNotNullLabel);         // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects]
                    il.Ldstr("Reference is not valid at this point");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(objectsIsNotNullLabel);

                    context.IncreaseIndexBy1(); // index = index + 1; stack: []
                    il.Ldc_I4(4);
                    context.AssertLength();
                    context.GoToCurrentLocation();
                    var reference = il.DeclareLocal(typeof(int));
                    il.Ldind(typeof(int));             // stack: [*(int*)data[index]]
                    il.Stloc(reference);               // reference = *(int*)data[index]; stack: []
                    context.IncreaseIndexBy4();        // index = index + 4; stack: []
                    il.Ldloc(context.Index);           // stack: [index]
                    il.Ldloc(reference);               // stack: [index, reference]
                    var goodReferenceLabel = il.DefineLabel("goodReference");
                    il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: []
                    il.Ldstr("Bad reference");
                    il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] { typeof(string) }));
                    il.Throw();
                    il.MarkLabel(goodReferenceLabel);
                    context.LoadContext();                                                                                        // stack: [context]
                    il.Ldfld(ReaderContext.ObjectsField);                                                                         // stack: [context.objects]
                    il.Ldloc(reference);                                                                                          // stack: [context.objects, reference]
                    il.Ldloca(obj);                                                                                               // stack: [context.objects, reference, ref obj]
                    il.Call(HackHelpers.GetMethodDefinition <Dictionary <int, object> >(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)]
                    var readObjectLabel = il.DefineLabel("readObject");
                    il.Brfalse(readObjectLabel);                                                                                  // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: []
                    context.LoadResultByRef();                                                                                    // stack: [ref result]
                    il.Ldloc(obj);                                                                                                // stack: [ref result, obj]
                    il.Castclass(Type);                                                                                           // stack: [ref result, (Type)obj]
                    il.Stind(Type);                                                                                               // result = (Type)obj; stack: []
                    il.Ret();
                    il.MarkLabel(readObjectLabel);

                    // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted
                    context.LoadData();                 // stack: [data]
                    il.Ldloc(reference);                // stack: [data, reference]
                    context.LoadContext();              // stack: [data, reference, context]
                    il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start]
                    il.Add();                           // stack: [data, reference + context.start]
                    il.Stloc(reference);                // reference += context.start; stack: [data]
                    il.Ldloca(reference);               // stack: [data, ref reference]
                    context.LoadResultByRef();          // stack: [data, ref reference, ref result]
                    context.LoadContext();              // stack: [data, ref reference, ref result, context]
                    context.CallReader(Type);
                    il.Ret();
                    il.MarkLabel(readUsualLabel);
                }

                ReadNotEmpty(context); // Read obj
                il.Ret();
            }
            var @delegate = method.CreateDelegate(typeof(ReaderDelegate <>).MakeGenericType(Type));
            var pointer   = GroBufHelpers.ExtractDynamicMethodPointer(method);

            readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate);
        }
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            context.IncreaseIndexBy1();
            context.AssertTypeCode(GroBufTypeCode.Array);

            var il     = context.Il;
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [data length]

            context.AssertLength();
            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation();                   // stack: [&data[index]]
            il.Ldind(typeof(uint));                          // stack: [array length]
            context.IncreaseIndexBy4();                      // index = index + 4; stack: [array length]
            il.Stloc(length);                                // length = array length; stack: []

            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(length);                                // stack: [ref result, hashSet, hashSet, length]
            var initializeMethod = Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic);

            il.Call(initializeMethod); // hashSet.Initialize(length); 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: []

            context.StoreObject(Type);

            il.Ldloc(length); // stack: [length]
            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: []
            var i = il.DeclareLocal(typeof(uint));

            il.Ldc_I4(0); // stack: [0]
            il.Stloc(i);  // i = 0; stack: []
            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

            context.LoadData();       // stack: [pinnedData]
            context.LoadIndexByRef(); // stack: [pinnedData, ref index]
            var value = il.DeclareLocal(elementType);

            il.Ldloca(value);                // stack: [pinnedData, ref index, ref value]
            context.LoadContext();           // stack: [pinnedData, ref index, ref value, context]
            context.CallReader(elementType); // reader(pinnedData, ref index, ref value, context); stack: []

            context.LoadResult(Type);        // stack: [result]
            il.Ldloc(value);                 // stack: [result, value]
            il.Call(Type.GetMethod("Add"));  // stack: [result.Add(value)]
            il.Pop();                        // stack: []

            if (!elementType.IsValueType)
            {
                il.Ldnull();
                il.Stloc(value);
            }

            il.Ldloc(i);                   // stack: [i]
            il.Ldc_I4(1);                  // stack: [i, 1]
            il.Add();                      // stack: [i + 1]
            il.Dup();                      // stack: [i + 1, i + 1]
            il.Stloc(i);                   // i = i + 1; stack: [i]
            il.Ldloc(length);              // stack: [i, length]
            il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart
            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: []
        }
Beispiel #12
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            int[]   values;
            ulong[] hashCodes;
            EnumHelpers.BuildValuesTable(Type, out values, out hashCodes);
            var valuesField    = context.Context.InitConstField(Type, 0, values);
            var hashCodesField = context.Context.InitConstField(Type, 1, hashCodes);
            var il             = context.Il;

            il.Ldloc(context.TypeCode); // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.Enum);
            var tryParseLabel = il.DefineLabel("tryParse");

            il.Bne_Un(tryParseLabel);      // if(typeCode != GroBufTypeCode.Enum) goto tryParse;
            context.IncreaseIndexBy1();
            il.Ldc_I4(8);                  // stack: [8]
            context.AssertLength();
            context.LoadResultByRef();     // stack: [ref result]
            context.GoToCurrentLocation(); // stack: [ref result, &result[index]]
            il.Ldind(typeof(long));        // stack: [ref result, *(int64*)result[index] = hashCode]
            context.IncreaseIndexBy8();    // index = index + 8; stack: [ref result, hashCode]

            var parseByHashCodeLabel = il.DefineLabel("parseByHashCode");

            il.MarkLabel(parseByHashCodeLabel);

            il.Dup();                    // stack: [ref result, hashCode, hashCode]
            il.Ldc_I8(hashCodes.Length); // stack: [ref result, hashCode, hashCode, (int64)hashCodes.Length]
            il.Rem(true);                // stack: [ref result, hashCode, hashCode % hashCodes.Length = idx]
            il.Conv <int>();             // stack: [ref result, hashCode, (int)(hashCode % hashCodes.Length)]
            var idx = context.Length;

            il.Stloc(idx);                     // idx = (int)(hashCode % hashCodes.Length); stack: [ref result, hashCode]

            context.LoadField(hashCodesField); // stack: [ref result, hashCode, hashCodes]
            il.Ldloc(idx);                     // stack: [ref result, hashCode, hashCodes, idx]
            il.Ldelem(typeof(long));           // stack: [ref result, hashCode, hashCodes[idx]]
            var returnDefaultLabel = il.DefineLabel("returnDefault");

            il.Bne_Un(returnDefaultLabel);  // if(hashCode != hashCodes[idx]) goto returnDefault; stack: [ref result]
            context.LoadField(valuesField); // stack: [ref result, values]
            il.Ldloc(idx);                  // stack: [ref result, values, idx]
            il.Ldelem(typeof(int));         // stack: [ref result, values[idx]]
            il.Stind(typeof(int));          // result = values[idx]; stack: []
            il.Ret();
            il.MarkLabel(returnDefaultLabel);
            il.Ldc_I4(0);          // stack: [0]
            il.Stind(typeof(int)); // result = 0
            il.Ret();

            il.MarkLabel(tryParseLabel);
            il.Ldloc(context.TypeCode);            // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.String); // stack: [typeCode, GroBufTypeCode.String]
            var readAsIntLabel = il.DefineLabel("readAsInt");

            il.Bne_Un(readAsIntLabel); // if(typeCode != GroBufTypeCode.String) goto readAsInt;
            var str = il.DeclareLocal(typeof(string));

            context.LoadData();                                                                              // stack: [pinnedData]
            context.LoadIndexByRef();                                                                        // stack: [pinnedData, ref index]
            il.Ldloca(str);                                                                                  // stack: [pinnedData, ref index, ref str]
            context.LoadContext();                                                                           // stack: [pinnedData, ref index, ref str, context]
            context.CallReader(typeof(string));                                                              // reader<string>(pinnedData, ref index, ref str, context); stack: []
            context.LoadResultByRef();                                                                       // stack: [ref result]
            il.Ldloc(str);                                                                                   // stack: [ref result, str]
            il.Call(typeof(GroBufHelpers).GetMethod("CalcHash", BindingFlags.Public | BindingFlags.Static)); // stack: [ref result, GroBufHelpers.CalcHash(str)]
            il.Br(parseByHashCodeLabel);

            il.MarkLabel(readAsIntLabel);

            context.LoadData();              // stack: [pinnedData]
            context.LoadIndexByRef();        // stack: [pinnedData, ref index]
            context.LoadResultByRef();       // stack: [pinnedData, ref index, ref result]
            context.LoadContext();           // stack: [pinnedData, ref index, ref result, context]
            context.CallReader(typeof(int)); // reader<int>(pinnedData, ref index, ref result, context)
        }
Beispiel #13
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            il.Ldloc(context.TypeCode);           // stack: [type code]
            il.Ldc_I4((int)GroBufTypeCode.Array); // stack: [type code, GroBufTypeCode.Array]
            var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement");

            il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode.Array) goto tryReadArrayElement; stack: []

            context.IncreaseIndexBy1();
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [data length]

            context.AssertLength();
            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [array length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [array length]
            il.Stloc(length);              // length = array length; stack: []

            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);          // stack: [length]
            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: []
            var i = il.DeclareLocal(typeof(uint));

            il.Ldc_I4(0); // stack: [0]
            il.Stloc(i);  // i = 0; stack: []
            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

            context.LoadData();              // stack: [pinnedData]
            context.LoadIndexByRef();        // stack: [pinnedData, ref index]
            il.Ldloc(array);                 // stack: [pinnedData, ref index, array]
            il.Ldloc(i);                     // stack: [pinnedData, ref index, array, i]

            il.Ldelema(elementType);         // stack: [pinnedData, ref index, ref array[i]]
            context.LoadContext();           // stack: [pinnedData, ref index, ref array[i], context]

            context.CallReader(elementType); // reader(pinnedData, ref index, ref array[i], context); stack: []
            il.Ldloc(i);                     // stack: [i]
            il.Ldc_I4(1);                    // stack: [i, 1]
            il.Add();                        // stack: [i + 1]
            il.Dup();                        // stack: [i + 1, i + 1]
            il.Stloc(i);                     // i = i + 1; stack: [i]
            il.Ldloc(length);                // stack: [i, length]
            il.Blt(cycleStartLabel, true);   // if(i < length) goto cycleStart
            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: []
        }
Beispiel #14
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            context.IncreaseIndexBy1();
            context.AssertTypeCode(GroBufTypeCode.Dictionary);

            var il     = context.Il;
            var length = context.Length;

            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(uint));        // stack: [data length]
            context.IncreaseIndexBy4();    // index = index + 4; stack: [data length]

            context.AssertLength();
            il.Ldc_I4(4);
            context.AssertLength();

            context.GoToCurrentLocation();                         // stack: [&data[index]]
            il.Ldind(typeof(uint));                                // stack: [array length]
            context.IncreaseIndexBy4();                            // index = index + 4; stack: [array length]
            il.Stloc(length);                                      // length = array length; stack: []

            context.LoadResultByRef();                             // stack: [ref result]
            il.Ldloc(length);                                      // stack: [ref result, length]
            il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new Dictionary(length)]
            il.Stind(Type);                                        // result = new Dictionary(length); stack: []

            context.StoreObject(Type);

            il.Ldloc(length); // stack: [length]
            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: []
            var i = il.DeclareLocal(typeof(uint));

            il.Ldc_I4(0); // stack: [0]
            il.Stloc(i);  // i = 0; stack: []
            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

            context.LoadData();       // stack: [pinnedData]
            context.LoadIndexByRef(); // stack: [pinnedData, ref index]
            var key   = il.DeclareLocal(Type.GetGenericArguments()[0]);
            var value = il.DeclareLocal(Type.GetGenericArguments()[1]);

            il.Ldloca(key);                // stack: [pinnedData, ref index, ref key]
            context.LoadContext();         // stack: [pinnedData, ref index, ref key, context]
            context.CallReader(keyType);   // reader(pinnedData, ref index, ref key, context); stack: []

            context.LoadData();            // stack: [pinnedData]
            context.LoadIndexByRef();      // stack: [pinnedData, ref index]
            il.Ldloca(value);              // stack: [pinnedData, ref index, ref value]
            context.LoadContext();         // stack: [pinnedData, ref index, ref value, context]
            context.CallReader(valueType); // reader(pinnedData, ref index, ref value, context); stack: []

            context.LoadResult(Type);
            il.Ldloc(key);
            il.Ldloc(value);
            il.Call(Type.GetMethod("Add"));

            if (!keyType.IsValueType)
            {
                il.Ldnull();
                il.Stloc(key);
            }
            if (!valueType.IsValueType)
            {
                il.Ldnull();
                il.Stloc(value);
            }

            il.Ldloc(i);                   // stack: [i]
            il.Ldc_I4(1);                  // stack: [i, 1]
            il.Add();                      // stack: [i + 1]
            il.Dup();                      // stack: [i + 1, i + 1]
            il.Stloc(i);                   // i = i + 1; stack: [i]
            il.Ldloc(length);              // stack: [i, length]
            il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart
            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: []
        }