lundi 20 mai 2019

Baking a byte array into dynamic IL

I am writing a performance-oriented data deserializer by emitting IL. The serialized data is UTF8, and the fields are denoted as strings.

[FieldA]: 22
[FieldB]: 16

I have already written a custom reader that properly tokenizes the serialized data and provides a ReadOnlySpan<byte> as it steps through the serialized data.

I would like to have a static, inline deserializer that is able to have the byte signatures of the fields packed in so that I can easily create a jump table and set the appropriate fields.

How non-dynamic code might look:

// byteSpan is a ReadOnlySpan<byte> containing the signature

var signatureA = Encoding.UTF8.GetBytes( "FieldA" );
var signatureB = Encoding.UTF8.GetBytes( "FieldB" );
if( byteSpan.SequenceEqual( signatureA ) )
  DoSomething();
else if ( byteSpan.SequenceEqual( signatureB ) )
  DoSomething();
...

How the jump table is being emitted:

var fieldSignatures = GetTypeSignatures<T>(); // Returns a Tuple<byte[], FieldInfo>
var setFieldLabels = new List<Tuple<FieldInfo, Label>>();

foreach( (byte[] signature, FieldInfo field) in fieldSignatures )
{
  var setFieldLabel = il.DefineLabel();
  setFieldLabels.Add( Tuple.Create( field, setFieldLabel ) );

  il.Emit( OpCodes.Ldloc_1 ); // Load the current ReadOnlySpan<byte>
  // Inline load byte[] signature here
  il.Emit( OpCodes.Call, METHOD_SEQUENCEEQUAL );
  il.Emit( OpCodes.Brtrue, setFieldLabel );
}

EmitFieldSetters( setFieldLabels, ref il );

Is there a way I can bake the signature byte arrays directly into the IL that I am emitting so that they are a part of the delegate?

These signatures are generated at runtime based on type information, so manually defining them in a static class isn't feasible. A workaround could be to define a new dynamic Assembly and Type and store the bytes in there, but I would like to avoid having to do that if possible.





Aucun commentaire:

Enregistrer un commentaire