I'm trying to write a DynamicMethod
to wrap the cpblk
IL opcode. I need to copy chunks of byte arrays and on x64 platforms, this is supposedly the fastest way to do it. Array.Copy
and Buffer.BlockCopy
both work, but I'd like to explore all options.
My goal is to copy managed memory from one byte array to a new managed byte array. My concern is how do I know how to correctly "pin" memory location. I don't want the garbage collector to move the arrays and break everything. SO far it works but I'm not sure how to test if this is GC safe.
// copying 'count' bytes from offset 'index' in 'source' to offset 0 in 'target'
// i.e. void _copy(byte[] source, int index, int count, byte[] target)
static Action<byte[], int, int, byte[]> Init()
{
var dmethod = new DynamicMethod("copy", typeof(void), new[] { typeof(object),typeof(byte[]), typeof(int), typeof(int),typeof(byte[]) },typeof(object), true);
var il = dmethod.GetILGenerator();
il.DeclareLocal(typeof(byte).MakeByRefType(), true);
il.DeclareLocal(typeof(byte).MakeByRefType(), true);
// pin the source
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Ldelema, typeof(byte));
il.Emit(OpCodes.Stloc_0);
// pin the target
il.Emit(OpCodes.Ldarg_S,(byte)4);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldelema, typeof(byte));
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_0);
// load the length
il.Emit(OpCodes.Ldarg_3);
// perform the memcpy
il.Emit(OpCodes.Unaligned,(byte)1);
il.Emit(OpCodes.Cpblk);
il.Emit(OpCodes.Ret);
return dmethod.CreateDelegate(typeof(Action<byte[], int, int, byte[]>)) as Action<byte[], int, int, byte[]>;
}
I believe that your usage of pinned local variables is correct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With