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); }
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); } }
public void EmitWrite(WriterEmitContext context) { context.LoadBuffer(); context.LoadValue(); EmitWriteImpl(context); }
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); }
public void EmitWrite(WriterEmitContext context) { context.LoadBuffer(); context.LoadValue(); context.CallWriteStringUnsafe(); context.AddToCurrentOffset(); }
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(); } }
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); } } }
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); } }
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); }
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); } } }
public void EmitSizeEstimator(WriterEmitContext context) { context.LoadValue(); context.Il.EmitCall(OpCodes.Call, typeof(Memory <T>).GetProperty(nameof(Memory <T> .Length)).GetGetMethod(), null); }
public void EmitSizeEstimator(WriterEmitContext context) { context.LoadValue(); context.Il.EmitCall(OpCodes.Call, typeof(StringWriter).GetMethod(nameof(CalculateSize)), null); }
protected override void EmitCount(WriterEmitContext context) { context.LoadValue(); context.Il.EmitCall(OpCodes.Call, CountMethod, null); }
protected override void EmitCount(WriterEmitContext context) { context.LoadValue(); context.Il.EmitCall(OpCodes.Call, typeof(Span <T>).GetProperty(nameof(Span <T> .Length)).GetGetMethod(), null); }