Пример #1
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var il = context.Il;

            var readers      = GetReaders(context);
            var readersField = context.Context.InitConstField(Type, 0, readers.Select(pair => pair.Value).ToArray());

            context.Context.InitConstField(Type, 1, readers.Select(pair => pair.Key).ToArray());

            context.LoadData();              // stack: [data]
            context.LoadIndexByRef();        // stack: [data, ref index]
            context.LoadResultByRef();       // stack: [data, ref index, ref result]
            context.LoadContext();           // stack: [data, ref index, ref result, context]
            context.LoadField(readersField); // stack: [data, ref index, ref result, context, readers]
            il.Ldloc(context.TypeCode);      // stack: [data, ref index, ref result, context, readers, typeCode]
            il.Ldelem(typeof(IntPtr));       // stack: [data, ref index, ref result, context, readers[typeCode]]
            il.Dup();                        // stack: [data, ref index, ref result, context, readers[typeCode], readers[typeCode]]
            var skipValueLabel = il.DefineLabel("skipValue");

            il.Brfalse(skipValueLabel); // if(readers[typeCode] == 0) goto skipValue;
            var parameterTypes = new[] { typeof(byte *), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext) };

            il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // readers[typeCode](data, ref index, ref result, context); stack: []
            il.Ret();
            il.MarkLabel(skipValueLabel);
            il.Pop();
            il.Pop();
            il.Pop();
            il.Pop();
            il.Pop();
            context.IncreaseIndexBy1();
            context.SkipValue();
        }
Пример #2
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            context.IncreaseIndexBy1();
            var readersField = context.Context.InitConstField(Type, 0, primitiveReaders.Select(pair => pair.Value).ToArray());

            context.Context.InitConstField(Type, 1, primitiveReaders.Select(pair => pair.Key).ToArray());
            var il = context.Il;

            context.GoToCurrentLocation();                                                                       // stack: [&data[index]]
            context.LoadResultByRef();                                                                           // stack: [&data[index], ref result]
            context.SkipValue();
            context.LoadField(readersField);                                                                     // stack: [&data[index], ref result, readers]
            il.Ldloc(context.TypeCode);                                                                          // stack: [&data[index], ref result, readers, typeCode]
            il.Ldelem(typeof(IntPtr));                                                                           // stack: [&data[index], ref result, readers[typeCode]]
            il.Calli(CallingConventions.Standard, typeof(void), new[] { typeof(byte *), Type.MakeByRefType() }); // readers[typeCode](&data[index], ref result); stack: []
        }
Пример #3
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer);
            var il = context.Il;

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

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

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

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

            var local = il.DeclareLocal(typeof(object));

            context.LoadField(customSerializerField); // stack: [customSerializer]
            context.LoadData();                       // stack: [customSerializer, data]
            context.LoadIndexByRef();                 // stack: [customSerializer, data, ref index]
            il.Ldloca(local);                         // stack: [customSerializer, data, ref index, ref local]
            context.LoadContext();                    // stack: [customSerializer, data, ref index, ref local, context]
            int    dummy      = 0;
            object dummyObj   = null;
            var    readMethod = HackHelpers.GetMethodDefinition <IGroBufCustomSerializer>(serializer => serializer.Read(IntPtr.Zero, ref dummy, ref dummyObj, null));

            il.Call(readMethod);       // customSerializer.Read(data, ref index, length, ref local); stack: []

            context.LoadResultByRef(); // stack: [ref result]
            il.Ldloc(local);           // stack: [ref result, ref local]
            if (!Type.IsValueType)
            {
                il.Castclass(Type);
                il.Stind(Type);
            }
            else
            {
                il.Unbox_Any(Type); // stack: [ref result, (Type)local]
                il.Stobj(Type);     // result = (Type)local
            }

            context.StoreObject(Type);
        }
Пример #4
0
        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)
        {
            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)
        }