예제 #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)
        {
            var il = context.Il;

            var source = il.DeclareLocal(typeof(IntPtr));

            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Stloc(source);              // source = &data[index]; stack: []
            context.IncreaseIndexBy1();    // skip type code
            context.SkipValue();
            context.GoToCurrentLocation(); // stack: [&data[index]]
            il.Ldloc(source);              // stack: [&data[index], source]
            il.Sub();                      // stack: [&data[index] - source = data length]
            var length = il.DeclareLocal(typeof(int));

            il.Stloc(length); // length = &data[index] - source; stack: []
            var array = il.DeclareLocal(typeof(byte[]));

            il.Ldloc(length);        // stack: [length]
            il.Newarr(typeof(byte)); // stack: [new byte[length]]
            il.Stloc(array);         // array = new byte[length]; stack: []
            var dest = il.DeclareLocal(typeof(byte).MakeByRefType(), true);

            il.Ldloc(array);          // stack: [array]
            il.Ldc_I4(0);             // stack: [array, 0]
            il.Ldelema(typeof(byte)); // stack: [&array[0]]
            il.Stloc(dest);           // dest = &array[0]; stack: []
            il.Ldloc(dest);           // stack: [dest]
            il.Ldloc(source);         // stack: [dest, source]
            il.Ldloc(length);         // stack: [dest, source, length]
            il.Cpblk();               // dest = source; stack: []
            il.FreePinnedLocal(dest); // dest = null; stack: []

            var argumentType = Type.GetGenericArguments()[0];

            context.LoadResultByRef();                                                       // stack: [ref result]
            context.LoadSerializerId();                                                      // stack: [ref result, serializerId]
            il.Ldloc(array);                                                                 // stack: [ref result, serializerId, array]
            context.LoadReader(argumentType);                                                // stack: [ref result, serializerId, array, reader<arg>]
            context.LoadSerializerId();                                                      // stack: [ref result, serializerId, array, reader<arg>, serializerId]
            il.Newobj(readerInvoker.GetConstructor(new[] { typeof(IntPtr), typeof(long) })); // stack: [ref result, serializerId, array, new ReaderInvoker(reader<arg>, serializerId)]
            il.Ldftn(readerInvoker.GetMethod("Read", BindingFlags.Instance | BindingFlags.Public));
            var readDataFuncType = typeof(Func <,>).MakeGenericType(typeof(byte[]), argumentType);

            il.Newobj(readDataFuncType.GetConstructor(new[] { typeof(object), typeof(IntPtr) })); // stack: [ref result, serializerId, array, new Func<byte[], arg>(..)]
            var rawDataType = typeof(RawData <>).MakeGenericType(argumentType);

            il.Newobj(rawDataType.GetConstructor(new[] { typeof(long), typeof(byte[]), readDataFuncType })); // stack: [ref result, new RawData(serializerId, array, func)]
            il.Ldftn(rawDataType.GetMethod("GetValue", BindingFlags.Instance | BindingFlags.Public));        // stack: [ref result, new RawData(..), RawData.GetValue]
            var factoryType = typeof(Func <>).MakeGenericType(argumentType);

            il.Newobj(factoryType.GetConstructor(new[] { typeof(object), typeof(IntPtr) })); // stack: [ref result, new Func<arg>(new RawData(), RawData.GetValue)]
            il.Newobj(Type.GetConstructor(new[] { factoryType }));                           // stack: [ref result, new Lazy<arg>(new Func<arg>(new RawData(), RawData.GetValue))]
            il.Stind(Type);                                                                  // result = new Lazy<argument>(array, func); stack: []
        }
예제 #3
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: []
        }
예제 #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
        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);
        }
예제 #6
0
        protected override void ReadNotEmpty(ReaderMethodBuilderContext context)
        {
            var constructor = Type.GetConstructor(new[] { typeof(long), typeof(DateTimeKind) });

            if (constructor == null)
            {
                throw new MissingConstructorException(Type, typeof(long), typeof(DateTimeKind));
            }
            var il = context.Il;

            il.Ldloc(context.TypeCode);                 // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.DateTimeNew); // stack: [typeCode, GroBufTypeCode.DateTimeNew]
            var processOldFormatLabel = il.DefineLabel("processOldFormat");

            il.Bne_Un(processOldFormatLabel);  // if(typeCode != GroBufTypeCode.DateTimeNew) goto processOldFormat; stack: []
            context.IncreaseIndexBy1();
            il.Ldc_I4(8);                      // stack: [8]
            context.AssertLength();
            context.LoadResultByRef();         // stack: [ref result]
            context.GoToCurrentLocation();     // stack: [ref result, &data[index]]
            il.Ldind(typeof(long));            // stack: [ref result, (long)data[index]]
            il.Call(dateTimeFromBinaryMethod); // stack: [ref result, DateTime.FromBinary((long)data[index])]
            il.Stobj(Type);                    // result = DateTime.FromBinary((long)data[index])
            context.IncreaseIndexBy8();        // index = index + 8
            il.Ret();

            il.MarkLabel(processOldFormatLabel);
            var okLabel = il.DefineLabel("ok");

            il.Ldloc(context.TypeCode);                 // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [typeCode, GroBufTypeCode.DateTimeOld]
            il.Beq(okLabel);                            // if(typeCode == GroBufTypeCode.DateTimeOld) goto label

            il.Ldloc(context.TypeCode);                 // stack: [typeCode]
            il.Ldc_I4((int)GroBufTypeCode.Int64);       // stack: [typeCode, GroBufTypeCode.Int64]
            il.Beq(okLabel);                            // if(typeCode == GroBufTypeCode.Int64) goto label

            context.SkipValue();
            il.Ret();

            il.MarkLabel(okLabel);

            context.IncreaseIndexBy1();

            il.Ldc_I4(8); // stack: [8]
            context.AssertLength();

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

            context.GoToCurrentLocation(); // stack: [ref result, &data[index]]
            il.Ldind(typeof(long));        // stack: [ref result, (long)&data[index] = ticks]
            il.Dup();                      // stack: [ref result, ticks, ticks]
            il.Ldc_I8(long.MinValue);      // stack: [ref result, ticks, ticks, 0x8000000000000000]
            il.And();                      // stack: [ref result, ticks, ticks & 0x8000000000000000]
            var notUtcLabel = il.DefineLabel("notUtc");

            il.Brtrue(notUtcLabel);           // if(ticks & 0x8000000000000000 != 0) goto notUtc; stack: [ref result, ticks]
            il.Ldc_I4((int)DateTimeKind.Utc); // stack: [ref result, ticks, DateTimeKind.Utc]
            il.Newobj(constructor);           // stack: [ref result, new DateTimeOld(ticks, DateTimeKind.Utc)]
            il.Stobj(Type);
            context.IncreaseIndexBy8();
            il.Ret();

            il.MarkLabel(notUtcLabel);
            context.IncreaseIndexBy8();
            il.Ldc_I4(1);
            context.AssertLength();
            il.Ldc_I8(long.MaxValue);      // stack: [ref result, ticks, 0x7FFFFFFFFFFFFFFF]
            il.And();                      // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF]
            context.GoToCurrentLocation(); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, &data[index]]
            il.Ldind(typeof(byte));        // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, (DateTimeKind)data[index] = kind]
            il.Newobj(constructor);        // stack: [ref result, new DateTimeOld(ticks, kind)]
            il.Stobj(Type);
            context.IncreaseIndexBy1();
        }