Created
September 22, 2018 19:26
-
-
Save shmolyneaux/41fcbe62f4a989482c24e8ca6a889dea to your computer and use it in GitHub Desktop.
Transcription of Beautiful Code Chapter 8 IL Generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void FilterMethodIL(byte[] src, byte[] dst, int stride, int bytesPerPixel) | |
{ | |
int cBytes = src.Length; | |
DynamicMethod dynameth = new DynamicMethod("Go", typeof(void), | |
new Type[] { typeof(byte[]), typeof(byte[]) }, GetType()); | |
ILGenerator generator = dynameth.GetILGenerator(); | |
generator.DeclareLocal(typeof(int)); // Index 0 = iDst | |
generator.DeclareLocal(typeof(double)); // Index 1 = pixelsAccum | |
generator.DeclareLocal(typeof(double)); // Index 2 = filterAccum | |
generator.Emit(OpCodes.Ldc_I4_0); | |
generator.Emit(OpCodes.Stloc_0); | |
Label labelTop = generator.DefineLabel(); | |
generator.MarkLabel(labelTop); | |
generator.Emit(OpCodes.Ldc_R8, 0.0); | |
generator.Emit(OpCodes.Dup); | |
generator.Emit(OpCodes.Stloc_1); | |
generator.Emit(OpCodes.Stloc_2); | |
for (int iFilter = 0; iFilter < filter.Length; iFilter++) | |
{ | |
if (filter[iFilter] == 0) | |
continue; | |
generator.Emit(OpCodes.Ldarg_0); | |
Label labelLessThanZero = generator.DefineLabel(); | |
Label labelGreaterThan = generator.DefineLabel(); | |
Label labelLoopBottom = generator.DefineLabel(); | |
generator.Emit(OpCodes.Ldloc_0); // dst index on stack | |
generator.Emit(OpCodes.Ldc_I4, offset); // offset on stack | |
generator.Emit(OpCodes.Add); // Add the two | |
generator.Emit(OpCodes.Dup); // Duplicate twice | |
generator.Emit(OpCodes.Dup); | |
generator.Emit(OpCodes.Ldc_I4_0); | |
generator.Emit(OpCodes.Blt_S, labelLessThanZero); | |
generator.Emit(OpCodes.Ldc_I4, cBytes); | |
generator.Emit(OpCodes.Bge_S, labelGreaterThan); | |
generator.Emit(OpCodes.Ldelem_U1); | |
generator.Emit(OpCodes.Conv_R8); | |
if (filter[iFilter] == 1) | |
{ | |
// src element is on stack, so do nothing | |
} | |
else if (filter[iFilter] == -1) | |
{ | |
generator.Emit(OpCodes.Neg); | |
} | |
else | |
{ | |
generator.Emit(OpCodes.Ldc_R8, filter[iFilter]); | |
generator.Emit(OpCodes.Mul); | |
} | |
generator.Emit(OpCodes.Ldloc_1); | |
generator.Emit(OpCodes.Add); | |
generator.Emit(OpCodes.Stloc_1); | |
generator.Emit(OpCodes.Ldc_R8, filter[iFilter]); | |
generator.Emit(OpCodes.Ldloc_2); | |
generator.Emit(OpCodes.Add); | |
generator.Emit(OpCodes.Stloc_2); | |
generator.Emit(OpCodes.Br, labelLoopBottom); | |
generator.MarkLabel(labelLessThanZero); | |
generator.Emit(OpCodes.Pop); | |
generator.MarkLabel(labelGreaterThan); | |
generator.Emit(OpCodes.Pop); | |
generator.Emit(OpCodes.Pop); | |
generator.MarkLabel(labelLoopBottom); | |
} | |
generator.Emit(OpCodes.Ldarg_1); // dst array | |
generator.Emit(OpCodes.Ldloc_0); // iDst index | |
Label labelSkipDivide = generator.DefineLabel(); | |
Label labelCopyQuotient = generator.DefineLabel(); | |
Label labelBlack = generator.DefineLabel(); | |
Label labelWhite = generator.DefineLabel(); | |
Label labelDone = generator.DefineLabel(); | |
generator.Emit(OpCodes.Ldloc_1); // pixelsAccum | |
generator.Emit(OpCodes.Ldloc_2); // filterAccum | |
generator.Emit(OpCodes.Dup); // Make a copy | |
generator.Emit(OpCodes.Ldc_R8, 0.0); // Put 0 on stack | |
generator.Emit(OpCodes.Beq_S, labelSkipDivide); | |
generator.Emit(OpCodes.Div); | |
generator.Emit(OpCodes.Br_S, labelCopyQuotient); | |
generator.MarkLabel(labelSkipDivide); | |
generator.Emit(OpCodes.Pop); // Pop filterAccum | |
generator.MarkLabel(labelCopyQuotient); | |
generator.Emit(OpCodes.Dup); // Make a copy of quotient | |
generator.Emit(OpCodes.Dup); // And another | |
generator.Emit(OpCodes.Ldc_R8, 0.0); | |
generator.Emit(OpCodes.Blt_S, labelBlack); | |
generator.Emit(OpCodes.Ldc_R8, 255.0); | |
generator.Emit(OpCodes.Bgt_S, labelWhite); | |
generator.Emit(OpCodes.Conv_U1); | |
generator.Emit(OpCodes.Br_S, labelDone); | |
generator.MarkLabel(labelBlack); | |
generator.Emit(OpCodes.Pop); | |
generator.Emit(OpCodes.Pop); | |
generator.Emit(OpCodes.Ldc_I4_S, 0); | |
generator.Emit(OpCodes.Br_S, labelDone); | |
generator.MarkLabel(labelWhite); | |
generator.Emit(OpCodes.Pop); | |
generator.Emit(OpCodes.Ldc_I4_S, 255); | |
generator.MarkLabel(labelDone); | |
generator.Emit(OpCodes.Stelem_I1); | |
generator.Emit(OpCodes.Ldloc_0); // Put iDst on stack | |
generator.Emit(OpCodes.Ldc_I4_1); // Put 1 on stack | |
generator.Emit(OpCodes.Add); // Add 1 to iDst | |
generator.Emit(OpCodes.Dup); // Duplicate | |
generator.Emit(OpCodes.Stloc_0); // Store result in iDst | |
generator.Emit(OpCodes.Ldc_I4, cBytes); // Put cBytes value on stack | |
generator.Emit(OpCodes.Blt, labelTop); // Go to top if iDst < cBytes | |
generator.Emit(OpCodes.Ret); | |
dynameth.Invoke(this, new object[] { src, dst }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment