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(); } } }
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); } }
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); } }
void WriteValue(WriterEmitContext context, Action loadValue) { using (context.Scope(loadValue)) { itemWriter.EmitWrite(context); } if (itemWriter is IUpdateOffset == false) { context.AddToCurrentOffset(); } }
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); } } }