Example #1
0
        void EmitNonNullWriter(WriterEmitContext ctx)
        {
            var il = ctx.Il;

            if (ctx.HasManifestToWrite)
            {
                ctx.WriteManifest();
            }

            using (ctx.GetLocal <int>(out var offset))
            {
                ctx.LoadCurrentOffset();
                il.Store(offset);

                // add 2 for the length of variable
                il.LoadIntValue(2);
                ctx.AddToCurrentOffset();

                Writer.EmitWrite(ctx);

                // stack empty, value written directly to the buffer

                ctx.LoadBuffer(offset); // stack: byte*

                ctx.LoadCurrentOffset();
                il.Load(offset);
                il.Emit(OpCodes.Sub); // stack: byte*, value

                il.LoadIntValue(2);
                il.Emit(OpCodes.Sub);                        // -2 for length

                il.StoreIndirectLittleEndian(typeof(short)); // save length
            }
        }
Example #2
0
            public void EmitWrite(WriterEmitContext context)
            {
                var il = context.Il;

                foreach (var field in fields)
                {
                    var writer = AllWriters.GetWriter(field);

                    var manifest = GetManifestValue(field);

                    void LoadValue()
                    {
                        il.Emit(writer.RequiresAddress ? OpCodes.Ldflda : OpCodes.Ldfld, field);
                    }

                    using (context.Scope(LoadValue, manifest: manifest))
                    {
                        // if the writer does not write manifest, this will write manifest for the writer
                        if (writer is IWriteManifest == false)
                        {
                            context.WriteManifest();
                        }

                        writer.EmitWrite(context);
                    }

                    if (writer is IUpdateOffset == false)
                    {
                        context.AddToCurrentOffset();
                    }
                }
            }
Example #3
0
        void EmitClassWriter(WriterEmitContext ctx)
        {
            var il      = ctx.Il;
            var nullLbl = il.DefineLabel();
            var end     = il.DefineLabel();

            ctx.LoadValue();
            il.Emit(OpCodes.Brfalse, nullLbl);

            EmitNonNullWriter(ctx);
            il.Emit(OpCodes.Br, end);

            // writing null
            il.MarkLabel(nullLbl);
            if (ctx.HasManifestToWrite == false)
            {
                ctx.LoadBuffer();
                il.LoadIntValue(NullLength);
                il.StoreIndirectLittleEndian(typeof(short));
                il.LoadIntValue(2); // used only 2 bytes for writing null
                ctx.AddToCurrentOffset();
            }
            else
            {
                // no value, nothing to write
            }

            il.MarkLabel(end);
        }
Example #4
0
        public void EmitSizeEstimator(WriterEmitContext context)
        {
            if (Type.IsValueType)
            {
                writer.EmitSizeEstimator(context);
            }
            else
            {
                var il      = context.Il;
                var nullLbl = il.DefineLabel();
                var end     = il.DefineLabel();

                context.LoadValue();
                il.Emit(OpCodes.Brfalse, nullLbl);

                writer.EmitSizeEstimator(context);
                il.LoadIntValue(2);
                il.Emit(OpCodes.Add);

                il.Emit(OpCodes.Br_S, end);

                il.MarkLabel(nullLbl);
                il.LoadIntValue(2);

                il.MarkLabel(end);
            }
        }
Example #5
0
 public void EmitWrite(WriterEmitContext context)
 {
     context.LoadBuffer();
     context.LoadValue();
     context.CallWriteStringUnsafe();
     context.AddToCurrentOffset();
 }
Example #6
0
            public void EmitSizeEstimator(WriterEmitContext ctx)
            {
                var il = ctx.Il;

                using (ctx.GetLocal <int>(out var varSize))
                {
                    il.LoadIntValue(0);
                    il.Store(varSize);

                    foreach (var field in varSizeFields)
                    {
                        var writer = GetVarSizeWriter(field);

                        void LoadValue()
                        {
                            il.Emit(writer.RequiresAddress ? OpCodes.Ldflda : OpCodes.Ldfld, field);
                        }

                        using (ctx.Scope(LoadValue))
                        {
                            writer.EmitSizeEstimator(ctx);
                        }

                        // add to already counted bytes
                        il.Load(varSize);
                        il.Emit(OpCodes.Add);
                        il.Store(varSize);
                    }

                    il.Load(varSize);
                    il.LoadIntValue(size);
                    il.Emit(OpCodes.Add);
                }
            }
Example #7
0
        public override void EmitSizeEstimator(WriterEmitContext context)
        {
            using (context.GetLocal <int>(out var sum))
            {
                LoopOver(context, (ctx, loadValue) =>
                {
                    using (context.Scope(loadValue))
                    {
                        itemWriter.EmitSizeEstimator(ctx);
                    }

                    // stack: size
                    ctx.Il.Load(sum);
                    ctx.Il.Emit(OpCodes.Add);
                    ctx.Il.Store(sum); // add and store in the sum
                });

                var il = context.Il;

                il.Load(sum);
                // add 2 for the count
                il.LoadIntValue(2);
                il.Emit(OpCodes.Add);
            }
        }
Example #8
0
        public override void EmitWriteImpl(WriterEmitContext context)
        {
            //IL_0001: brtrue.s IL_0006
            //IL_0003: ldc.i4.0
            //IL_0004: br.s IL_0007
            //IL_0006: ldc.i4.1
            //IL_0007: conv.u1

            var il = context.Il;

            var load1 = il.DefineLabel();

            var conversionU1 = il.DefineLabel();

            il.Emit(OpCodes.Brtrue_S, load1);
            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Br_S, conversionU1);

            il.MarkLabel(load1);
            il.Emit(OpCodes.Ldc_I4_1);

            il.MarkLabel(conversionU1);
            il.Emit(OpCodes.Conv_U1);

            // store
            il.Emit(OpCodes.Stind_I1);
        }
Example #9
0
        public void EmitWrite(WriterEmitContext context)
        {
            context.LoadBuffer();
            context.LoadValue();

            EmitWriteImpl(context);
        }
Example #10
0
 public EmitScope(WriterEmitContext context, Action loadValue, EmitScope parent, bool chainUp, ushort?manifest)
 {
     this.context   = context;
     this.loadValue = loadValue;
     this.parent    = parent;
     this.chainUp   = chainUp;
     this.manifest  = manifest;
 }
Example #11
0
        void WriteValue(WriterEmitContext context)
        {
            itemWriter.EmitWrite(context);

            if (itemWriter is IUpdateOffset == false)
            {
                context.AddToCurrentOffset();
            }
        }
Example #12
0
        public void EmitWrite(WriterEmitContext context)
        {
            var nullable = typeof(TPrimitive?);

            var il = context.Il;

            var hasValue = il.DefineLabel();
            var end      = il.DefineLabel();

            context.LoadValue();
            il.EmitCall(OpCodes.Call, nullable.GetProperty(nameof(Nullable <int> .HasValue)).GetGetMethod(), null);
            il.Emit(OpCodes.Brtrue_S, hasValue);

            // no value, just store 0 and return length = 1

            if (context.HasManifestToWrite == false)
            {
                context.LoadBuffer();
                il.LoadIntValue(0);
                il.Emit(OpCodes.Stind_I1);
                il.LoadIntValue(1);
                il.Emit(OpCodes.Br, end); // jump to the end of writing
            }
            else
            {
                il.LoadIntValue(0);
                il.Emit(OpCodes.Br, end); // jump to the end of writing
            }

            // has value, store 1, then store value
            il.MarkLabel(hasValue);

            if (context.HasManifestToWrite == false)
            {
                context.LoadBuffer();
                il.LoadIntValue(1);
                il.Emit(OpCodes.Stind_I1);

                il.LoadIntValue(1);
                context.AddToCurrentOffset();
            }
            else
            {
                context.WriteManifest();
            }

            // load shifted buffer and value
            context.LoadBuffer();
            context.LoadValue();
            il.EmitCall(OpCodes.Call, nullable.GetProperty(nameof(Nullable <int> .Value)).GetGetMethod(), null);

            // emit regular
            Emit(context);
            il.MarkLabel(end);
        }
Example #13
0
 public void EmitWrite(WriterEmitContext context)
 {
     if (Type.IsValueType)
     {
         EmitNonNullWriter(context);
     }
     else
     {
         EmitClassWriter(context);
     }
 }
Example #14
0
        void WriteValue(WriterEmitContext context, Action loadValue)
        {
            using (context.Scope(loadValue))
            {
                itemWriter.EmitWrite(context);
            }

            if (itemWriter is IUpdateOffset == false)
            {
                context.AddToCurrentOffset();
            }
        }
Example #15
0
        public void EmitWrite(WriterEmitContext context)
        {
            using (context.GetLocal(typeof(Span <T>), out var span))
            {
                context.LoadValue();
                context.Il.EmitCall(OpCodes.Call, Type.GetProperty(nameof(Memory <T> .Span)).GetGetMethod(), null);
                context.Il.Store(span);

                using (context.OverrideScope(spanWriter, span))
                {
                    spanWriter.EmitWrite(context);
                }
            }
        }
Example #16
0
        protected void LoopOver(WriterEmitContext context, Action <WriterEmitContext, Action> useValue)
        {
            var il = context.Il;

            using (context.GetLocal <int>(out var i))
            {
                var check = il.DefineLabel();
                var start = il.DefineLabel();

                il.LoadIntValue(0);
                il.Store(i);

                il.Emit(OpCodes.Br, check);

                il.MarkLabel(start);

                void LoadElementValue()
                {
                    il.Load(i);

                    if (itemWriter.RequiresAddress)
                    {
                        il.Emit(OpCodes.Ldelema, typeof(T));
                    }
                    else
                    {
                        il.LoadElem(typeof(T));
                    }
                }

                useValue(context, LoadElementValue);

                // i++
                il.LoadIntValue(1);
                il.Load(i);
                il.Emit(OpCodes.Add);
                il.Store(i);

                // check boundaries
                il.MarkLabel(check);

                il.Load(i);
                context.LoadValue();
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Conv_I4);
                il.Emit(OpCodes.Blt, start);
            }
        }
Example #17
0
        public override void EmitSizeEstimator(WriterEmitContext context)
        {
            context.LoadValue();

            var il = context.Il;

            il.Emit(OpCodes.Ldlen);
            il.Emit(OpCodes.Conv_I4);

            il.LoadIntValue(itemWriter.Size);
            il.Emit(OpCodes.Mul);
            il.Emit(OpCodes.Conv_Ovf_I2);

            // add 2 for the count
            il.LoadIntValue(2);
            il.Emit(OpCodes.Add);
        }
Example #18
0
        public void EmitSizeEstimator(WriterEmitContext ctx)
        {
            var il = ctx.Il;

            if (itemWriter is IBoundedSizeWriter bounded)
            {
                EmitCount(ctx);
                il.LoadIntValue(bounded.Size);
                il.Emit(OpCodes.Mul);
                il.Emit(OpCodes.Conv_Ovf_I2);

                // add 2 for the count
                il.LoadIntValue(2);
                il.Emit(OpCodes.Add);
            }
            else if (itemWriter is IVarSizeWriter varSize)
            {
                using (ctx.GetLocal <int>(out var sum))
                {
                    // zero value
                    il.LoadIntValue(0);
                    il.Store(sum);

                    Enumerate(ctx, () =>
                    {
                        varSize.EmitSizeEstimator(ctx);

                        // stack: size
                        ctx.Il.Load(sum);
                        ctx.Il.Emit(OpCodes.Add);
                        ctx.Il.Store(sum); // add and store in the sum
                    });

                    il.Load(sum);
                    // add 2 for the count
                    il.LoadIntValue(2);
                    il.Emit(OpCodes.Add);
                }
            }
            else
            {
                throw new NotImplementedException($"The type of writer {itemWriter.GetType()} is not currently handled");
            }
        }
Example #19
0
        public void EmitWrite(WriterEmitContext context)
        {
            var il = context.Il;

            using (context.GetLocal <int>(out var length))
            {
                context.LoadValue();
                il.EmitCall(OpCodes.Call, typeof(Span <byte>).GetProperty(nameof(Span <byte> .Length)).GetGetMethod(), null);
                il.Store(length);

                context.LoadValue();                                                                                                // stack: span

                context.LoadBuffer();                                                                                               // stack: span, buffer
                il.Load(length);                                                                                                    // stack: span, buffer, length

                il.Emit(OpCodes.Newobj, typeof(Span <byte>).GetConstructor(new[] { typeof(void).MakePointerType(), typeof(int) })); //stack: span-source, span-dest

                il.EmitCall(OpCodes.Call, typeof(Span <byte>).GetMethod(nameof(Span <byte> .CopyTo)), null);
                il.Load(length);
                context.AddToCurrentOffset();
            }
        }
Example #20
0
 public override void EmitWriteImpl(WriterEmitContext context)
 {
     context.Il.Emit(OpCodes.Stobj, typeof(Guid));
 }
Example #21
0
 protected abstract void Emit(WriterEmitContext context);
Example #22
0
 public override void EmitWriteImpl(WriterEmitContext context)
 {
     context.Il.Emit(OpCodes.Stind_I1);
 }
Example #23
0
 protected override void Emit(WriterEmitContext context)
 {
     wrapped.EmitWriteImpl(context);
 }
Example #24
0
 public abstract void EmitWriteImpl(WriterEmitContext context);
Example #25
0
 protected override void Emit(WriterEmitContext context)
 {
     wrapped.EmitWriteImpl(context);
     context.Il.LoadIntValue(wrapped.Size);
 }
Example #26
0
 public override void EmitWriteImpl(WriterEmitContext context)
 {
     context.CallZigInt();
     context.CallWriteUInt32Variant();
 }
Example #27
0
        protected void Enumerate(WriterEmitContext context, Action consumeValue)
        {
            var il = context.Il;

            var getEnumerator = Type.GetMethod(nameof(IEnumerable <int> .GetEnumerator), BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);

            var enumeratorType        = getEnumerator.ReturnType;
            var enumeratorCurrentType = enumeratorType.GetProperty(nameof(IEnumerator <int> .Current)).PropertyType;

            var isEnumeratorByRef = enumeratorCurrentType.IsByRef;

            var current  = enumeratorType.GetProperty(nameof(IEnumerator <int> .Current)).GetMethod;
            var moveNext = enumeratorType.GetMethod(nameof(IEnumerator <int> .MoveNext), BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);

            if (moveNext == null && enumeratorType.IsGenericType && enumeratorType.GetGenericTypeDefinition() == typeof(IEnumerator <>))
            {
                moveNext = typeof(IEnumerator).GetMethod(nameof(IEnumerator.MoveNext));
            }

            using (context.GetLocal(enumeratorType, out var enumerator))
            {
                context.LoadValue();
                il.EmitCall(enumeratorType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, getEnumerator, null);
                il.Store(enumerator);

                // try
                var enumeratorIsDisposable = typeof(IDisposable).IsAssignableFrom(enumeratorType);
                if (enumeratorIsDisposable)
                {
                    il.BeginExceptionBlock();
                }

                // iterate over values

                var processLbl   = il.DefineLabel();
                var loadLbl      = il.DefineLabel();
                var outOfFinally = il.DefineLabel();

                il.Emit(OpCodes.Br, loadLbl);

                il.MarkLabel(processLbl);

                // true, false
                if (itemWriter.RequiresAddress & !isEnumeratorByRef)
                {
                    using (context.GetLocal(itemWriter.Type, out var value))
                    {
                        il.CallOn(enumerator, current);
                        il.Store(value);

                        using (context.OverrideScope(itemWriter, value))
                        {
                            consumeValue();
                        }
                    }
                }

                // true, true
                // false, false
                if (itemWriter.RequiresAddress ^ isEnumeratorByRef == false)
                {
                    void LoadValue()
                    {
                        il.CallOn(enumerator, current);
                    }

                    using (context.Scope(LoadValue, false))
                    {
                        consumeValue();
                    }
                }

                // false, true
                if (!itemWriter.RequiresAddress & isEnumeratorByRef)
                {
                    void LoadValue()
                    {
                        il.CallOn(enumerator, current);
                        il.LoadIndirect(itemWriter.Type);
                    }

                    using (context.Scope(LoadValue, false))
                    {
                        consumeValue();
                    }
                }

                il.MarkLabel(loadLbl);

                il.CallOn(enumerator, moveNext);

                il.Emit(OpCodes.Brtrue, processLbl);

                if (enumeratorIsDisposable)
                {
                    il.Emit(OpCodes.Leave, outOfFinally);

                    // finally
                    il.BeginFinallyBlock();
                    var nullLbl = il.DefineLabel();

                    il.Load(enumerator);
                    il.Emit(OpCodes.Brfalse, nullLbl);

                    il.Load(enumerator);
                    il.EmitCall(OpCodes.Callvirt, typeof(IDisposable).GetMethod(nameof(IDisposable.Dispose)), null);
                    il.MarkLabel(nullLbl);

                    il.EndExceptionBlock();

                    il.MarkLabel(outOfFinally);
                }
            }
        }
Example #28
0
 public void EmitWrite(WriterEmitContext context)
 {
     Enumerate(context, () => WriteValue(context));
 }
Example #29
0
 public override void EmitWriteImpl(WriterEmitContext context)
 {
     context.Il.StoreIndirectLittleEndian(typeof(ushort));
 }
Example #30
0
 public void EmitSizeEstimator(WriterEmitContext context)
 {
     context.LoadValue();
     context.Il.EmitCall(OpCodes.Call, typeof(Memory <T>).GetProperty(nameof(Memory <T> .Length)).GetGetMethod(), null);
 }