コード例 #1
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();
                    }
                }
            }
コード例 #2
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);
                }
            }
コード例 #3
0
ファイル: ArrayWriter.cs プロジェクト: lanicon/Enzyme
        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);
            }
        }
コード例 #4
0
ファイル: ArrayWriter.cs プロジェクト: lanicon/Enzyme
        void WriteValue(WriterEmitContext context, Action loadValue)
        {
            using (context.Scope(loadValue))
            {
                itemWriter.EmitWrite(context);
            }

            if (itemWriter is IUpdateOffset == false)
            {
                context.AddToCurrentOffset();
            }
        }
コード例 #5
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);
                }
            }
        }