/// <summary>
        /// Emits a macro
        /// </summary>
        /// <param name="writer">The MSIL writer to write to.</param>
        /// <param name="value">The constant <see cref="Int32"/> value to load onto the evaluation stack.</param>
        /// <exception cref="ArgumentNullException">
        ///	<para><paramref name="writer"/> is <see langword="null"/>.</para>
        /// </exception>
        public static void EmitLdcI4(this ICilWriter writer, int value)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            OpCode opCode;

            switch (value)
            {
            case -1: opCode = OpCodes.Ldc_I4_M1; break;

            case 0: opCode = OpCodes.Ldc_I4_0; break;

            case 1: opCode = OpCodes.Ldc_I4_1; break;

            case 2: opCode = OpCodes.Ldc_I4_2; break;

            case 3: opCode = OpCodes.Ldc_I4_3; break;

            case 4: opCode = OpCodes.Ldc_I4_4; break;

            case 5: opCode = OpCodes.Ldc_I4_5; break;

            case 6: opCode = OpCodes.Ldc_I4_6; break;

            case 7: opCode = OpCodes.Ldc_I4_7; break;

            case 8: opCode = OpCodes.Ldc_I4_8; break;

            default:
                opCode =
                    value <= byte.MaxValue
                                                ? OpCodes.Ldc_I4_S
                                                : OpCodes.Ldc_I4;
                break;
            }

            switch (opCode.OperandType)
            {
            case OperandType.InlineNone:
                writer.Emit(opCode);
                break;

            case OperandType.ShortInlineI:
                writer.Emit(opCode, (byte)value);
                break;

            case OperandType.InlineI:
                writer.Emit(opCode, value);
                break;

            default:
                throw new InvalidOperationException("Unexpected OperandType. This is an indication of a bug.");
            }
        }
        /// <summary>
        /// Emits <see langword="OpCodes.Ldloca"/> or the best alternative macro depending on the operand.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="localIndex">The index of the local variable operand.</param>
        public static void EmitLdloca(this ICilWriter writer, int localIndex)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (localIndex < 0)
            {
                throw new ArgumentOutOfRangeException("localIndex", "localIndex may not be negative");
            }

            if (localIndex <= byte.MaxValue)
            {
                writer.Emit(OpCodes.Ldloca_S, (byte)localIndex);
                return;
            }
            writer.Emit(OpCodes.Ldloca, localIndex);
        }
        /// <summary>
        /// Emits <see langword="OpCodes.Starg"/> or the best alternative macro depending on the operand.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="argumentIndex">The index of the parameter operand.</param>
        public static void EmitStarg(this ICilWriter writer, int argumentIndex)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (argumentIndex < 0)
            {
                throw new ArgumentOutOfRangeException("argumentIndex", "argumentIndex may not be negative");
            }

            if (argumentIndex <= byte.MaxValue)
            {
                writer.Emit(OpCodes.Starg_S, (byte)argumentIndex);
                return;
            }
            writer.Emit(OpCodes.Starg, argumentIndex);
        }
        internal static void EmitStelem(this ICilWriter writer, Type elementType)
        {
            OpCode opCode;

            if (elementType.IsPrimitive && _primitiveStelemOpCodes.TryGetValue(elementType, out opCode))
            {
                writer.Emit(opCode);
                return;
            }

            if (elementType.IsValueType || elementType.IsGenericParameter)
            {
                writer.Emit(OpCodes.Stelem, elementType);
            }
            else
            {
                writer.Emit(OpCodes.Stelem_Ref);
            }
        }
        internal static void EmitStobj(this ICilWriter writer, Type type)
        {
            OpCode opCode;

            if (type.IsPrimitive && _primitiveStobjOpCodes.TryGetValue(type, out opCode))
            {
                writer.Emit(opCode);
                return;
            }

            if (type.IsValueType || type.IsGenericParameter)
            {
                writer.Emit(OpCodes.Stobj, type);
            }
            else
            {
                writer.Emit(OpCodes.Stind_Ref);
            }
        }
        /// <summary>
        /// Emits <see cref="OpCodes.Callvirt"/> or <see cref="OpCodes.Call"/> depending on
        /// which is appropriate for <paramref name="method"/>.
        /// </summary>
        /// <param name="writer">The MSIL writer to write to.</param>
        /// <param name="method">The method to call in the output MSIL.</param>
        /// <exception cref="ArgumentNullException">
        ///	<para><paramref name="writer"/> is <see langword="null"/>.</para>
        ///	<para>- or -</para>
        ///	<para><paramref name="method"/> is <see langword="null"/>.</para>
        /// </exception>
        public static void EmitCall(this ICilWriter writer, MethodInfo method)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            OpCode opCode = !method.IsStatic && method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call;

            writer.Emit(opCode, method);
        }
        /// <summary>
        /// Emits <see langword="OpCodes.Stloc"/> or the best alternative macro depending on the operand.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="localIndex">The index of the local variable operand.</param>
        public static void EmitStloc(this ICilWriter writer, int localIndex)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (localIndex < 0)
            {
                throw new ArgumentOutOfRangeException("localIndex", "localIndex may not be negative");
            }

            switch (localIndex)
            {
            case 0:
                writer.Emit(OpCodes.Stloc_0);
                return;

            case 1:
                writer.Emit(OpCodes.Stloc_1);
                return;

            case 2:
                writer.Emit(OpCodes.Stloc_2);
                return;

            case 3:
                writer.Emit(OpCodes.Stloc_3);
                return;

            default:
                if (localIndex <= byte.MaxValue)
                {
                    writer.Emit(OpCodes.Stloc_S, (byte)localIndex);
                    return;
                }
                writer.Emit(OpCodes.Stloc, localIndex);
                return;
            }
        }
        /// <summary>
        /// Emits <see langword="OpCodes.Ldarg"/> or the best alternative macro depending on the operand.
        /// </summary>
        /// <param name="writer">The writer to write to.</param>
        /// <param name="argumentIndex">The index of the parameter operand.</param>
        public static void EmitLdarg(this ICilWriter writer, int argumentIndex)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
            if (argumentIndex < 0)
            {
                throw new ArgumentOutOfRangeException("argumentIndex", "argumentIndex may not be negative");
            }

            switch (argumentIndex)
            {
            case 0:
                writer.Emit(OpCodes.Ldarg_0);
                return;

            case 1:
                writer.Emit(OpCodes.Ldarg_1);
                return;

            case 2:
                writer.Emit(OpCodes.Ldarg_2);
                return;

            case 3:
                writer.Emit(OpCodes.Ldarg_3);
                return;

            default:
                if (argumentIndex <= byte.MaxValue)
                {
                    writer.Emit(OpCodes.Ldarg_S, (byte)argumentIndex);
                    return;
                }
                writer.Emit(OpCodes.Ldarg, argumentIndex);
                return;
            }
        }