Ejemplo n.º 1
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: []
        }