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 } }
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(); } } }
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 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(); context.CallWriteStringUnsafe(); 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); } }
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); }
public void EmitWrite(WriterEmitContext context) { context.LoadBuffer(); context.LoadValue(); EmitWriteImpl(context); }
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; }
void WriteValue(WriterEmitContext context) { itemWriter.EmitWrite(context); if (itemWriter is IUpdateOffset == false) { context.AddToCurrentOffset(); } }
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 EmitWrite(WriterEmitContext context) { if (Type.IsValueType) { EmitNonNullWriter(context); } else { EmitClassWriter(context); } }
void WriteValue(WriterEmitContext context, Action loadValue) { using (context.Scope(loadValue)) { itemWriter.EmitWrite(context); } if (itemWriter is IUpdateOffset == false) { 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); }
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"); } }
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 override void EmitWriteImpl(WriterEmitContext context) { context.Il.Emit(OpCodes.Stobj, typeof(Guid)); }
protected abstract void Emit(WriterEmitContext context);
public override void EmitWriteImpl(WriterEmitContext context) { context.Il.Emit(OpCodes.Stind_I1); }
protected override void Emit(WriterEmitContext context) { wrapped.EmitWriteImpl(context); }
public abstract void EmitWriteImpl(WriterEmitContext context);
protected override void Emit(WriterEmitContext context) { wrapped.EmitWriteImpl(context); context.Il.LoadIntValue(wrapped.Size); }
public override void EmitWriteImpl(WriterEmitContext context) { context.CallZigInt(); context.CallWriteUInt32Variant(); }
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 EmitWrite(WriterEmitContext context) { Enumerate(context, () => WriteValue(context)); }
public override void EmitWriteImpl(WriterEmitContext context) { context.Il.StoreIndirectLittleEndian(typeof(ushort)); }
public void EmitSizeEstimator(WriterEmitContext context) { context.LoadValue(); context.Il.EmitCall(OpCodes.Call, typeof(Memory <T>).GetProperty(nameof(Memory <T> .Length)).GetGetMethod(), null); }