Beautiful Code [28]
generator.Emit(OpCodes.Ldloc_2);
generator.Emit(OpCodes.Add);
generator.Emit(OpCodes.Stloc_2);
generator.Emit(OpCodes.Br, labelLoopBottom);
At this point, we're at the bottom of the inner for loop, equivalent to line 24 of Example 8-2. We are essentially finished with the processing for each filter element, except that the stack has to be cleaned up for cases where the calculated iSrc index is outside the bounds of the bitmap. This section of the generated code (at the bottom of the C# for loop for iFilter) marks the three labels and performs cleanup by popping unused items from the stack:
generator.MarkLabel(labelLessThanZero);
generator.Emit(OpCodes.Pop);
generator.MarkLabel(labelGreaterThan);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Pop);
generator.MarkLabel(labelLoopBottom);
}
So far, all the code has been generated to calculate pixelsAccum and filterAccum for a particular destination pixel. The result is almost ready to be transferred into the dst array. The array reference (which has a method argument index of 1) and the iDst index (which has a local variable index of 0) are both loaded on the stack:
generator.Emit(OpCodes.Ldarg_1); // dst array
generator.Emit(OpCodes.Ldloc_0); // iDst index
There will be some branching involved, so the following labels are defined:
Label labelSkipDivide = generator.DefineLabel();
Label labelCopyQuotient = generator.DefineLabel();
Label labelBlack = generator.DefineLabel();
Label labelWhite = generator.DefineLabel();
Label labelDone = generator.DefineLabel();
The following code loads both the pixelsAccum and filterAccum local variables on the stack in preparation for division. The first task is to check for a potential zero-divide by comparing filterAccum with 0. This code is equivalent to line 25 in Example 8-2:
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);
If the denominator is not 0, the division is executed and the quotient remains on the stack:
generator.Emit(OpCodes.Div);
generator.Emit(OpCodes.Br_S, labelCopyQuotient);
If filterAccum is 0, the following code is executed and the original instance of filterAccum is popped from the stack:
generator.MarkLabel(labelSkipDivide);
generator.Emit(OpCodes.Pop); // Pop filterAccum
In either case, what remains on the stack is pixelsAccum, either divided by filterAccum or not. Two copies of that quotient are made:
generator.MarkLabel(labelCopyQuotient);
generator.Emit(OpCodes.Dup); // Make a copy of quotient
generator.Emit(OpCodes.Dup); // And another
Most of what follows is the Intermediate Language equivalent of the statement in lines 28 and 29 of Example 8-2. If the quotient is less than zero, the code branches to a label where the destination pixel will be set to 0:
generator.Emit(OpCodes.Ldc_R8, 0.0);
generator.Emit(OpCodes.Blt_S, labelBlack);
If the quotient is greater than 255, the following code branches to a label where the destination pixel will be set to 255:
generator.Emit(OpCodes.Ldc_R8, 255.0);
generator.Emit(OpCodes.Bgt_S, labelWhite);
Otherwise, the value on the stack is converted to an unsigned one-byte value:
generator.Emit(OpCodes.Conv_U1);
generator.Emit(OpCodes.Br_S, labelDone);
The following code is for the case where a zero byte must be stored in the destination array. The Ldc_I4_S instruction puts a one-byte value on the stack, but it goes onto the stack as a four-byte integer because the slot widths on the stack are in increments of four bytes:
generator.MarkLabel(labelBlack);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldc_I4_S, 0);
generator.Emit(OpCodes.Br_S, labelDone);
This part of the code is similar to the part in which 255 must be stored in the destination array:
generator.MarkLabel(labelWhite);
generator.Emit(OpCodes.Pop);