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 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: []
        }
        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 void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            MemberInfo[] dataMembers;
            ulong[]      hashCodes;
            BuildMembersTable(context.Context, out hashCodes, out dataMembers);

            var il       = context.Il;
            var end      = context.Length;
            var typeCode = context.TypeCode;

            var setters = dataMembers.Select(member => member == null ? default(KeyValuePair <Delegate, IntPtr>) : GetMemberSetter(context.Context, member)).ToArray();

            var settersField = context.Context.InitConstField(Type, 0, setters.Select(pair => pair.Value).ToArray());

            context.Context.InitConstField(Type, 1, setters.Select(pair => pair.Key).ToArray());
            var hashCodesField = context.Context.InitConstField(Type, 2, hashCodes);

            context.IncreaseIndexBy1(); // index = index + 1
            context.AssertTypeCode(GroBufTypeCode.Object);

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

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

            il.Dup();                      // stack: [data length, data length]
            il.Stloc(end);                 // end = data length; stack: [data length]

            if (!Type.IsValueType)
            {
                context.LoadResultByRef(); // stack: [data length, ref result]
                il.Ldind(Type);            // stack: [data length, result]
                var notNullLabel = il.DefineLabel("notNull");
                il.Brtrue(notNullLabel);   // if(result != null) goto notNull; stack: [data length]
                context.LoadResultByRef(); // stack: [data length, ref result]
                ObjectConstructionHelper.EmitConstructionOfType(Type, il);
                il.Stind(Type);            // result = new type(); stack: [data length]
                il.MarkLabel(notNullLabel);
            }

            context.StoreObject(Type);

            var doneLabel = il.DefineLabel("done");

            il.Brfalse(doneLabel);  // if(data length == 0) goto done; stack: []
            il.Ldloc(end);          // stack: [data length]

            context.AssertLength(); // stack: []

            il.Ldloc(end);          // stack: [data length]
            context.LoadIndex();    // stack: [data length, index]
            il.Add();               // stack: [data length + index]
            il.Stloc(end);          // end = data length + index

            var cycleStartLabel = il.DefineLabel("cycleStart");

            il.MarkLabel(cycleStartLabel);

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

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(long));        // stack: [*(int64*)&data[index] = hashCode]
            context.IncreaseIndexBy8();    // index = index + 8; stack: [*(int64*)&data[index] = hashCode]

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

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

            context.LoadField(hashCodesField); // stack: [hashCode, hashCodes]
            il.Ldloc(idx);                     // stack: [hashCode, hashCodes, idx]
            il.Ldelem(typeof(long));           // stack: [hashCode, hashCodes[idx]]

            var skipDataLabel = il.DefineLabel("skipData");

            il.Bne_Un(skipDataLabel); // if(hashCode != hashCodes[idx]) goto skipData; stack: []

            // Read data
            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.LoadField(settersField); // stack: [pinnedData, ref index, ref result, context, setters]
            il.Ldloc(idx);                   // stack: [pinnedData, ref index, ref result, context, setters, idx]
            il.Ldelem(typeof(IntPtr));       // stack: [pinnedData, ref index, ref result, context, setters[idx]]
            var parameterTypes = new[] { typeof(byte *), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) };

            il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // setters[idx](pinnedData, ref index, ref result, context); stack: []

            var checkIndexLabel = il.DefineLabel("checkIndex");

            il.Br(checkIndexLabel); // goto checkIndex

            il.MarkLabel(skipDataLabel);
            // Skip data
            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldind(typeof(byte));        // stack: [data[index]]
            il.Stloc(typeCode);            // typeCode = data[index]; stack: []
            context.IncreaseIndexBy1();    // index = index + 1
            context.CheckTypeCode();
            context.SkipValue();

            il.MarkLabel(checkIndexLabel);

            context.LoadIndex();           // stack: [index]
            il.Ldloc(end);                 // stack: [index, end]
            il.Blt(cycleStartLabel, true); // if(index < end) goto cycleStart; stack: []

            var onDeserializedMethod = Type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                       .SingleOrDefault(method => method.GetCustomAttribute <OnDeserializedAttribute>() != null);

            if (onDeserializedMethod != null)
            {
                var parameters = onDeserializedMethod.GetParameters();
                if (parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
                {
                    throw new InvalidOperationException(string.Format("The method '{0}' marked with 'OnDeserialized' attribute must accept exactly one parameter of type '{1}'", onDeserializedMethod, typeof(StreamingContext).FullName));
                }
                context.LoadResult(Type);
                il.Ldc_I4((int)StreamingContextStates.Other);
                il.Newobj(typeof(StreamingContext).GetConstructor(new[] { typeof(StreamingContextStates) }));
                il.Call(onDeserializedMethod);
            }

            il.MarkLabel(doneLabel);
        }
示例#5
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: []
        }
示例#6
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: []

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