ILGen.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / ILGen.cs / 1407647 / ILGen.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

#if MICROSOFT_SCRIPTING_CORE || SILVERLIGHT 
using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator; 
#endif
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic.Utils;
using System.Reflection; 
using System.Reflection.Emit;
using System.Runtime.CompilerServices; 
 
#if SILVERLIGHT
using System.Core; 
#endif

namespace System.Linq.Expressions.Compiler {
 
    internal static class ILGen {
 
        internal static void Emit(this ILGenerator il, OpCode opcode, MethodBase methodBase) { 
            Debug.Assert(methodBase is MethodInfo || methodBase is ConstructorInfo);
 
            if (methodBase.MemberType == MemberTypes.Constructor) {
                il.Emit(opcode, (ConstructorInfo)methodBase);
            } else {
                il.Emit(opcode, (MethodInfo)methodBase); 
            }
        } 
 
        #region Instruction helpers
 
        internal static void EmitLoadArg(this ILGenerator il, int index) {
            Debug.Assert(index >= 0);

            switch (index) { 
                case 0:
                    il.Emit(OpCodes.Ldarg_0); 
                    break; 
                case 1:
                    il.Emit(OpCodes.Ldarg_1); 
                    break;
                case 2:
                    il.Emit(OpCodes.Ldarg_2);
                    break; 
                case 3:
                    il.Emit(OpCodes.Ldarg_3); 
                    break; 
                default:
                    if (index <= Byte.MaxValue) { 
                        il.Emit(OpCodes.Ldarg_S, (byte)index);
                    } else {
                        il.Emit(OpCodes.Ldarg, index);
                    } 
                    break;
            } 
        } 

        internal static void EmitLoadArgAddress(this ILGenerator il, int index) { 
            Debug.Assert(index >= 0);

            if (index <= Byte.MaxValue) {
                il.Emit(OpCodes.Ldarga_S, (byte)index); 
            } else {
                il.Emit(OpCodes.Ldarga, index); 
            } 
        }
 
        internal static void EmitStoreArg(this ILGenerator il, int index) {
            Debug.Assert(index >= 0);

            if (index <= Byte.MaxValue) { 
                il.Emit(OpCodes.Starg_S, (byte)index);
            } else { 
                il.Emit(OpCodes.Starg, index); 
            }
        } 

        /// 
        /// Emits a Ldind* instruction for the appropriate type
        ///  
        internal static void EmitLoadValueIndirect(this ILGenerator il, Type type) {
            ContractUtils.RequiresNotNull(type, "type"); 
 
            if (type.IsValueType) {
                if (type == typeof(int)) { 
                    il.Emit(OpCodes.Ldind_I4);
                } else if (type == typeof(uint)) {
                    il.Emit(OpCodes.Ldind_U4);
                } else if (type == typeof(short)) { 
                    il.Emit(OpCodes.Ldind_I2);
                } else if (type == typeof(ushort)) { 
                    il.Emit(OpCodes.Ldind_U2); 
                } else if (type == typeof(long) || type == typeof(ulong)) {
                    il.Emit(OpCodes.Ldind_I8); 
                } else if (type == typeof(char)) {
                    il.Emit(OpCodes.Ldind_I2);
                } else if (type == typeof(bool)) {
                    il.Emit(OpCodes.Ldind_I1); 
                } else if (type == typeof(float)) {
                    il.Emit(OpCodes.Ldind_R4); 
                } else if (type == typeof(double)) { 
                    il.Emit(OpCodes.Ldind_R8);
                } else { 
                    il.Emit(OpCodes.Ldobj, type);
                }
            } else {
                il.Emit(OpCodes.Ldind_Ref); 
            }
        } 
 

        ///  
        /// Emits a Stind* instruction for the appropriate type.
        /// 
        internal static void EmitStoreValueIndirect(this ILGenerator il, Type type) {
            ContractUtils.RequiresNotNull(type, "type"); 

            if (type.IsValueType) { 
                if (type == typeof(int)) { 
                    il.Emit(OpCodes.Stind_I4);
                } else if (type == typeof(short)) { 
                    il.Emit(OpCodes.Stind_I2);
                } else if (type == typeof(long) || type == typeof(ulong)) {
                    il.Emit(OpCodes.Stind_I8);
                } else if (type == typeof(char)) { 
                    il.Emit(OpCodes.Stind_I2);
                } else if (type == typeof(bool)) { 
                    il.Emit(OpCodes.Stind_I1); 
                } else if (type == typeof(float)) {
                    il.Emit(OpCodes.Stind_R4); 
                } else if (type == typeof(double)) {
                    il.Emit(OpCodes.Stind_R8);
                } else {
                    il.Emit(OpCodes.Stobj, type); 
                }
            } else { 
                il.Emit(OpCodes.Stind_Ref); 
            }
        } 

        // Emits the Ldelem* instruction for the appropriate type

        internal static void EmitLoadElement(this ILGenerator il, Type type) { 
            ContractUtils.RequiresNotNull(type, "type");
 
            if (!type.IsValueType) { 
                il.Emit(OpCodes.Ldelem_Ref);
            } else if (type.IsEnum) { 
                il.Emit(OpCodes.Ldelem, type);
            } else {
                switch (Type.GetTypeCode(type)) {
                    case TypeCode.Boolean: 
                    case TypeCode.SByte:
                        il.Emit(OpCodes.Ldelem_I1); 
                        break; 
                    case TypeCode.Byte:
                        il.Emit(OpCodes.Ldelem_U1); 
                        break;
                    case TypeCode.Int16:
                        il.Emit(OpCodes.Ldelem_I2);
                        break; 
                    case TypeCode.Char:
                    case TypeCode.UInt16: 
                        il.Emit(OpCodes.Ldelem_U2); 
                        break;
                    case TypeCode.Int32: 
                        il.Emit(OpCodes.Ldelem_I4);
                        break;
                    case TypeCode.UInt32:
                        il.Emit(OpCodes.Ldelem_U4); 
                        break;
                    case TypeCode.Int64: 
                    case TypeCode.UInt64: 
                        il.Emit(OpCodes.Ldelem_I8);
                        break; 
                    case TypeCode.Single:
                        il.Emit(OpCodes.Ldelem_R4);
                        break;
                    case TypeCode.Double: 
                        il.Emit(OpCodes.Ldelem_R8);
                        break; 
                    default: 
                        il.Emit(OpCodes.Ldelem, type);
                        break; 
                }
            }
        }
 
        /// 
        /// Emits a Stelem* instruction for the appropriate type. 
        ///  
        internal static void EmitStoreElement(this ILGenerator il, Type type) {
            ContractUtils.RequiresNotNull(type, "type"); 

            if (type.IsEnum) {
                il.Emit(OpCodes.Stelem, type);
                return; 
            }
            switch (Type.GetTypeCode(type)) { 
                case TypeCode.Boolean: 
                case TypeCode.SByte:
                case TypeCode.Byte: 
                    il.Emit(OpCodes.Stelem_I1);
                    break;
                case TypeCode.Char:
                case TypeCode.Int16: 
                case TypeCode.UInt16:
                    il.Emit(OpCodes.Stelem_I2); 
                    break; 
                case TypeCode.Int32:
                case TypeCode.UInt32: 
                    il.Emit(OpCodes.Stelem_I4);
                    break;
                case TypeCode.Int64:
                case TypeCode.UInt64: 
                    il.Emit(OpCodes.Stelem_I8);
                    break; 
                case TypeCode.Single: 
                    il.Emit(OpCodes.Stelem_R4);
                    break; 
                case TypeCode.Double:
                    il.Emit(OpCodes.Stelem_R8);
                    break;
                default: 
                    if (type.IsValueType) {
                        il.Emit(OpCodes.Stelem, type); 
                    } else { 
                        il.Emit(OpCodes.Stelem_Ref);
                    } 
                    break;
            }
        }
 
        internal static void EmitType(this ILGenerator il, Type type) {
            ContractUtils.RequiresNotNull(type, "type"); 
 
            il.Emit(OpCodes.Ldtoken, type);
            il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); 
        }

        #endregion
 
        #region Fields, properties and methods
 
        internal static void EmitFieldAddress(this ILGenerator il, FieldInfo fi) { 
            ContractUtils.RequiresNotNull(fi, "fi");
 
            if (fi.IsStatic) {
                il.Emit(OpCodes.Ldsflda, fi);
            } else {
                il.Emit(OpCodes.Ldflda, fi); 
            }
        } 
 
        internal static void EmitFieldGet(this ILGenerator il, FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi"); 

            if (fi.IsStatic) {
                il.Emit(OpCodes.Ldsfld, fi);
            } else { 
                il.Emit(OpCodes.Ldfld, fi);
            } 
        } 

        internal static void EmitFieldSet(this ILGenerator il, FieldInfo fi) { 
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                il.Emit(OpCodes.Stsfld, fi); 
            } else {
                il.Emit(OpCodes.Stfld, fi); 
            } 
        }
 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
        internal static void EmitNew(this ILGenerator il, ConstructorInfo ci) {
            ContractUtils.RequiresNotNull(ci, "ci");
 
            if (ci.DeclaringType.ContainsGenericParameters) {
                throw Error.IllegalNewGenericParams(ci.DeclaringType); 
            } 

            il.Emit(OpCodes.Newobj, ci); 
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
        internal static void EmitNew(this ILGenerator il, Type type, Type[] paramTypes) { 
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(paramTypes, "paramTypes"); 
 
            ConstructorInfo ci = type.GetConstructor(paramTypes);
            if (ci == null) throw Error.TypeDoesNotHaveConstructorForTheSignature(); 
            il.EmitNew(ci);
        }

        #endregion 

        #region Constants 
 
        internal static void EmitNull(this ILGenerator il) {
            il.Emit(OpCodes.Ldnull); 
        }

        internal static void EmitString(this ILGenerator il, string value) {
            ContractUtils.RequiresNotNull(value, "value"); 
            il.Emit(OpCodes.Ldstr, value);
        } 
 
        internal static void EmitBoolean(this ILGenerator il, bool value) {
            if (value) { 
                il.Emit(OpCodes.Ldc_I4_1);
            } else {
                il.Emit(OpCodes.Ldc_I4_0);
            } 
        }
 
        internal static void EmitChar(this ILGenerator il, char value) { 
            il.EmitInt(value);
            il.Emit(OpCodes.Conv_U2); 
        }

        internal static void EmitByte(this ILGenerator il, byte value) {
            il.EmitInt(value); 
            il.Emit(OpCodes.Conv_U1);
        } 
 
        internal static void EmitSByte(this ILGenerator il, sbyte value) {
            il.EmitInt(value); 
            il.Emit(OpCodes.Conv_I1);
        }

        internal static void EmitShort(this ILGenerator il, short value) { 
            il.EmitInt(value);
            il.Emit(OpCodes.Conv_I2); 
        } 

        internal static void EmitUShort(this ILGenerator il, ushort value) { 
            il.EmitInt(value);
            il.Emit(OpCodes.Conv_U2);
        }
 
        internal static void EmitInt(this ILGenerator il, int value) {
            OpCode c; 
            switch (value) { 
                case -1:
                    c = OpCodes.Ldc_I4_M1; 
                    break;
                case 0:
                    c = OpCodes.Ldc_I4_0;
                    break; 
                case 1:
                    c = OpCodes.Ldc_I4_1; 
                    break; 
                case 2:
                    c = OpCodes.Ldc_I4_2; 
                    break;
                case 3:
                    c = OpCodes.Ldc_I4_3;
                    break; 
                case 4:
                    c = OpCodes.Ldc_I4_4; 
                    break; 
                case 5:
                    c = OpCodes.Ldc_I4_5; 
                    break;
                case 6:
                    c = OpCodes.Ldc_I4_6;
                    break; 
                case 7:
                    c = OpCodes.Ldc_I4_7; 
                    break; 
                case 8:
                    c = OpCodes.Ldc_I4_8; 
                    break;
                default:
                    if (value >= -128 && value <= 127) {
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); 
                    } else {
                        il.Emit(OpCodes.Ldc_I4, value); 
                    } 
                    return;
            } 
            il.Emit(c);
        }

        internal static void EmitUInt(this ILGenerator il, uint value) { 
            il.EmitInt((int)value);
            il.Emit(OpCodes.Conv_U4); 
        } 

        internal static void EmitLong(this ILGenerator il, long value) { 
            il.Emit(OpCodes.Ldc_I8, value);

            //
            // Now, emit convert to give the constant type information. 
            //
            // Otherwise, it is treated as unsigned and overflow is not 
            // detected if it's used in checked ops. 
            //
            il.Emit(OpCodes.Conv_I8); 
        }

        internal static void EmitULong(this ILGenerator il, ulong value) {
            il.Emit(OpCodes.Ldc_I8, (long)value); 
            il.Emit(OpCodes.Conv_U8);
        } 
 
        internal static void EmitDouble(this ILGenerator il, double value) {
            il.Emit(OpCodes.Ldc_R8, value); 
        }

        internal static void EmitSingle(this ILGenerator il, float value) {
            il.Emit(OpCodes.Ldc_R4, value); 
        }
 
        // matches TryEmitConstant 
        internal static bool CanEmitConstant(object value, Type type) {
            if (value == null || CanEmitILConstant(type)) { 
                return true;
            }

            Type t = value as Type; 
            if (t != null && ShouldLdtoken(t)) {
                return true; 
            } 

            MethodBase mb = value as MethodBase; 
            if (mb != null && ShouldLdtoken(mb)) {
                return true;
            }
 
            return false;
        } 
 
        // matches TryEmitILConstant
        private static bool CanEmitILConstant(Type type) { 
            switch (Type.GetTypeCode(type)) {
                case TypeCode.Boolean:
                case TypeCode.SByte:
                case TypeCode.Int16: 
                case TypeCode.Int32:
                case TypeCode.Int64: 
                case TypeCode.Single: 
                case TypeCode.Double:
                case TypeCode.Char: 
                case TypeCode.Byte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64: 
                case TypeCode.Decimal:
                case TypeCode.String: 
                    return true; 
            }
            return false; 
        }

        internal static void EmitConstant(this ILGenerator il, object value) {
            Debug.Assert(value != null); 
            EmitConstant(il, value, value.GetType());
        } 
 

        // 
        // Note: we support emitting more things as IL constants than
        // Linq does
        internal static void EmitConstant(this ILGenerator il, object value, Type type) {
            if (value == null) { 
                // Smarter than the Linq implementation which uses the initobj
                // pattern for all value types (works, but requires a local and 
                // more IL) 
                il.EmitDefault(type);
                return; 
            }

            // Handle the easy cases
            if (il.TryEmitILConstant(value, type)) { 
                return;
            } 
 
            // Check for a few more types that we support emitting as constants
            Type t = value as Type; 
            if (t != null && ShouldLdtoken(t)) {
                il.EmitType(t);
                if (type != typeof(Type)) {
                    il.Emit(OpCodes.Castclass, type); 
                }
                return; 
            } 

            MethodBase mb = value as MethodBase; 
            if (mb != null && ShouldLdtoken(mb)) {
                il.Emit(OpCodes.Ldtoken, mb);
                Type dt = mb.DeclaringType;
                if (dt != null && dt.IsGenericType) { 
                    il.Emit(OpCodes.Ldtoken, dt);
                    il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); 
                } else { 
                    il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) }));
                } 
                if (type != typeof(MethodBase)) {
                    il.Emit(OpCodes.Castclass, type);
                }
                return; 
            }
 
            throw ContractUtils.Unreachable; 
        }
 
        internal static bool ShouldLdtoken(Type t) {
            return t is TypeBuilder || t.IsGenericParameter || t.IsVisible;
        }
 
        internal static bool ShouldLdtoken(MethodBase mb) {
            // Can't ldtoken on a DynamicMethod 
            if (mb is DynamicMethod) { 
                return false;
            } 

            Type dt = mb.DeclaringType;
            return dt == null || ShouldLdtoken(dt);
        } 

 
        private static bool TryEmitILConstant(this ILGenerator il, object value, Type type) { 
            switch (Type.GetTypeCode(type)) {
                case TypeCode.Boolean: 
                    il.EmitBoolean((bool)value);
                    return true;
                case TypeCode.SByte:
                    il.EmitSByte((sbyte)value); 
                    return true;
                case TypeCode.Int16: 
                    il.EmitShort((short)value); 
                    return true;
                case TypeCode.Int32: 
                    il.EmitInt((int)value);
                    return true;
                case TypeCode.Int64:
                    il.EmitLong((long)value); 
                    return true;
                case TypeCode.Single: 
                    il.EmitSingle((float)value); 
                    return true;
                case TypeCode.Double: 
                    il.EmitDouble((double)value);
                    return true;
                case TypeCode.Char:
                    il.EmitChar((char)value); 
                    return true;
                case TypeCode.Byte: 
                    il.EmitByte((byte)value); 
                    return true;
                case TypeCode.UInt16: 
                    il.EmitUShort((ushort)value);
                    return true;
                case TypeCode.UInt32:
                    il.EmitUInt((uint)value); 
                    return true;
                case TypeCode.UInt64: 
                    il.EmitULong((ulong)value); 
                    return true;
                case TypeCode.Decimal: 
                    il.EmitDecimal((decimal)value);
                    return true;
                case TypeCode.String:
                    il.EmitString((string)value); 
                    return true;
                default: 
                    return false; 
            }
        } 

        #endregion

        #region Linq Conversions 

        internal static void EmitConvertToType(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) { 
            if (TypeUtils.AreEquivalent(typeFrom, typeTo)) { 
                return;
            } 

            if (typeFrom == typeof(void) || typeTo == typeof(void)) {
                throw ContractUtils.Unreachable;
            } 

            bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom); 
            bool isTypeToNullable = TypeUtils.IsNullableType(typeTo); 

            Type nnExprType = TypeUtils.GetNonNullableType(typeFrom); 
            Type nnType = TypeUtils.GetNonNullableType(typeTo);

            if (typeFrom.IsInterface || // interface cast
               typeTo.IsInterface || 
               typeFrom == typeof(object) || // boxing cast
               typeTo == typeof(object) || 
               TypeUtils.IsLegalExplicitVariantDelegateConversion(typeFrom, typeTo)) 
            {
                il.EmitCastToType(typeFrom, typeTo); 
            } else if (isTypeFromNullable || isTypeToNullable) {
                il.EmitNullableConversion(typeFrom, typeTo, isChecked);
            } else if (!(TypeUtils.IsConvertible(typeFrom) && TypeUtils.IsConvertible(typeTo)) // primitive runtime conversion
                       && 
                       (nnExprType.IsAssignableFrom(nnType) || // down cast
                       nnType.IsAssignableFrom(nnExprType))) // up cast 
            { 
                il.EmitCastToType(typeFrom, typeTo);
            } else if (typeFrom.IsArray && typeTo.IsArray) { 
                // See DevDiv Bugs #94657.
                il.EmitCastToType(typeFrom, typeTo);
            } else {
                il.EmitNumericConversion(typeFrom, typeTo, isChecked); 
            }
        } 
 

        private static void EmitCastToType(this ILGenerator il, Type typeFrom, Type typeTo) { 
            if (!typeFrom.IsValueType && typeTo.IsValueType) {
                il.Emit(OpCodes.Unbox_Any, typeTo);
            } else if (typeFrom.IsValueType && !typeTo.IsValueType) {
                il.Emit(OpCodes.Box, typeFrom); 
                if (typeTo != typeof(object)) {
                    il.Emit(OpCodes.Castclass, typeTo); 
                } 
            } else if (!typeFrom.IsValueType && !typeTo.IsValueType) {
                il.Emit(OpCodes.Castclass, typeTo); 
            } else {
                throw Error.InvalidCast(typeFrom, typeTo);
            }
        } 

 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        private static void EmitNumericConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
            bool isFromUnsigned = TypeUtils.IsUnsigned(typeFrom); 
            bool isFromFloatingPoint = TypeUtils.IsFloatingPoint(typeFrom);
            if (typeTo == typeof(Single)) {
                if (isFromUnsigned)
                    il.Emit(OpCodes.Conv_R_Un); 
                il.Emit(OpCodes.Conv_R4);
            } else if (typeTo == typeof(Double)) { 
                if (isFromUnsigned) 
                    il.Emit(OpCodes.Conv_R_Un);
                il.Emit(OpCodes.Conv_R8); 
            } else {
                TypeCode tc = Type.GetTypeCode(typeTo);
                if (isChecked) {
                    // Overflow checking needs to know if the source value on the IL stack is unsigned or not. 
                    if (isFromUnsigned) {
                        switch (tc) { 
                            case TypeCode.SByte: 
                                il.Emit(OpCodes.Conv_Ovf_I1_Un);
                                break; 
                            case TypeCode.Int16:
                                il.Emit(OpCodes.Conv_Ovf_I2_Un);
                                break;
                            case TypeCode.Int32: 
                                il.Emit(OpCodes.Conv_Ovf_I4_Un);
                                break; 
                            case TypeCode.Int64: 
                                il.Emit(OpCodes.Conv_Ovf_I8_Un);
                                break; 
                            case TypeCode.Byte:
                                il.Emit(OpCodes.Conv_Ovf_U1_Un);
                                break;
                            case TypeCode.UInt16: 
                            case TypeCode.Char:
                                il.Emit(OpCodes.Conv_Ovf_U2_Un); 
                                break; 
                            case TypeCode.UInt32:
                                il.Emit(OpCodes.Conv_Ovf_U4_Un); 
                                break;
                            case TypeCode.UInt64:
                                il.Emit(OpCodes.Conv_Ovf_U8_Un);
                                break; 
                            default:
                                throw Error.UnhandledConvert(typeTo); 
                        } 
                    } else {
                        switch (tc) { 
                            case TypeCode.SByte:
                                il.Emit(OpCodes.Conv_Ovf_I1);
                                break;
                            case TypeCode.Int16: 
                                il.Emit(OpCodes.Conv_Ovf_I2);
                                break; 
                            case TypeCode.Int32: 
                                il.Emit(OpCodes.Conv_Ovf_I4);
                                break; 
                            case TypeCode.Int64:
                                il.Emit(OpCodes.Conv_Ovf_I8);
                                break;
                            case TypeCode.Byte: 
                                il.Emit(OpCodes.Conv_Ovf_U1);
                                break; 
                            case TypeCode.UInt16: 
                            case TypeCode.Char:
                                il.Emit(OpCodes.Conv_Ovf_U2); 
                                break;
                            case TypeCode.UInt32:
                                il.Emit(OpCodes.Conv_Ovf_U4);
                                break; 
                            case TypeCode.UInt64:
                                il.Emit(OpCodes.Conv_Ovf_U8); 
                                break; 
                            default:
                                throw Error.UnhandledConvert(typeTo); 
                        }
                    }
                } else {
                    switch (tc) { 
                        case TypeCode.SByte:
                            il.Emit(OpCodes.Conv_I1); 
                            break; 
                        case TypeCode.Byte:
                            il.Emit(OpCodes.Conv_U1); 
                            break;
                        case TypeCode.Int16:
                            il.Emit(OpCodes.Conv_I2);
                            break; 
                        case TypeCode.UInt16:
                        case TypeCode.Char: 
                            il.Emit(OpCodes.Conv_U2); 
                            break;
                        case TypeCode.Int32: 
                            il.Emit(OpCodes.Conv_I4);
                            break;
                        case TypeCode.UInt32:
                            il.Emit(OpCodes.Conv_U4); 
                            break;
                        case TypeCode.Int64: 
                            if (isFromUnsigned) { 
                                il.Emit(OpCodes.Conv_U8);
                            } else { 
                                il.Emit(OpCodes.Conv_I8);
                            }
                            break;
                        case TypeCode.UInt64: 
                            if (isFromUnsigned || isFromFloatingPoint) {
                                il.Emit(OpCodes.Conv_U8); 
                            } else { 
                                il.Emit(OpCodes.Conv_I8);
                            } 
                            break;
                        default:
                            throw Error.UnhandledConvert(typeTo);
                    } 
                }
            } 
        } 

        private static void EmitNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) { 
            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
            Debug.Assert(TypeUtils.IsNullableType(typeTo));
            Label labIfNull = default(Label);
            Label labEnd = default(Label); 
            LocalBuilder locFrom = null;
            LocalBuilder locTo = null; 
            locFrom = il.DeclareLocal(typeFrom); 
            il.Emit(OpCodes.Stloc, locFrom);
            locTo = il.DeclareLocal(typeTo); 
            // test for null
            il.Emit(OpCodes.Ldloca, locFrom);
            il.EmitHasValue(typeFrom);
            labIfNull = il.DefineLabel(); 
            il.Emit(OpCodes.Brfalse_S, labIfNull);
            il.Emit(OpCodes.Ldloca, locFrom); 
            il.EmitGetValueOrDefault(typeFrom); 
            Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo); 
            il.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked);
            // construct result type
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
            il.Emit(OpCodes.Newobj, ci); 
            il.Emit(OpCodes.Stloc, locTo);
            labEnd = il.DefineLabel(); 
            il.Emit(OpCodes.Br_S, labEnd); 
            // if null then create a default one
            il.MarkLabel(labIfNull); 
            il.Emit(OpCodes.Ldloca, locTo);
            il.Emit(OpCodes.Initobj, typeTo);
            il.MarkLabel(labEnd);
            il.Emit(OpCodes.Ldloc, locTo); 
        }
 
 
        private static void EmitNonNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
            Debug.Assert(!TypeUtils.IsNullableType(typeFrom)); 
            Debug.Assert(TypeUtils.IsNullableType(typeTo));
            LocalBuilder locTo = null;
            locTo = il.DeclareLocal(typeTo);
            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo); 
            il.EmitConvertToType(typeFrom, nnTypeTo, isChecked);
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo }); 
            il.Emit(OpCodes.Newobj, ci); 
            il.Emit(OpCodes.Stloc, locTo);
            il.Emit(OpCodes.Ldloc, locTo); 
        }


        private static void EmitNullableToNonNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) { 
            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
            Debug.Assert(!TypeUtils.IsNullableType(typeTo)); 
            if (typeTo.IsValueType) 
                il.EmitNullableToNonNullableStructConversion(typeFrom, typeTo, isChecked);
            else 
                il.EmitNullableToReferenceConversion(typeFrom);
        }

 
        private static void EmitNullableToNonNullableStructConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
            Debug.Assert(TypeUtils.IsNullableType(typeFrom)); 
            Debug.Assert(!TypeUtils.IsNullableType(typeTo)); 
            Debug.Assert(typeTo.IsValueType);
            LocalBuilder locFrom = null; 
            locFrom = il.DeclareLocal(typeFrom);
            il.Emit(OpCodes.Stloc, locFrom);
            il.Emit(OpCodes.Ldloca, locFrom);
            il.EmitGetValue(typeFrom); 
            Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
            il.EmitConvertToType(nnTypeFrom, typeTo, isChecked); 
        } 

 
        private static void EmitNullableToReferenceConversion(this ILGenerator il, Type typeFrom) {
            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
            // We've got a conversion from nullable to Object, ValueType, Enum, etc.  Just box it so that
            // we get the nullable semantics. 
            il.Emit(OpCodes.Box, typeFrom);
        } 
 

        private static void EmitNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) { 
            bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom);
            bool isTypeToNullable = TypeUtils.IsNullableType(typeTo);
            Debug.Assert(isTypeFromNullable || isTypeToNullable);
            if (isTypeFromNullable && isTypeToNullable) 
                il.EmitNullableToNullableConversion(typeFrom, typeTo, isChecked);
            else if (isTypeFromNullable) 
                il.EmitNullableToNonNullableConversion(typeFrom, typeTo, isChecked); 
            else
                il.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked); 
        }


        internal static void EmitHasValue(this ILGenerator il, Type nullableType) { 
            MethodInfo mi = nullableType.GetMethod("get_HasValue", BindingFlags.Instance | BindingFlags.Public);
            Debug.Assert(nullableType.IsValueType); 
            il.Emit(OpCodes.Call, mi); 
        }
 

        internal static void EmitGetValue(this ILGenerator il, Type nullableType) {
            MethodInfo mi = nullableType.GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public);
            Debug.Assert(nullableType.IsValueType); 
            il.Emit(OpCodes.Call, mi);
        } 
 

        internal static void EmitGetValueOrDefault(this ILGenerator il, Type nullableType) { 
            MethodInfo mi = nullableType.GetMethod("GetValueOrDefault", System.Type.EmptyTypes);
            Debug.Assert(nullableType.IsValueType);
            il.Emit(OpCodes.Call, mi);
        } 

        #endregion 
 
        #region Arrays
 
        /// 
        /// Emits an array of constant values provided in the given list.
        /// The array is strongly typed.
        ///  
        internal static void EmitArray(this ILGenerator il, IList items) {
            ContractUtils.RequiresNotNull(items, "items"); 
 
            il.EmitInt(items.Count);
            il.Emit(OpCodes.Newarr, typeof(T)); 
            for (int i = 0; i < items.Count; i++) {
                il.Emit(OpCodes.Dup);
                il.EmitInt(i);
                il.EmitConstant(items[i], typeof(T)); 
                il.EmitStoreElement(typeof(T));
            } 
        } 

        ///  
        /// Emits an array of values of count size.  The items are emitted via the callback
        /// which is provided with the current item index to emit.
        /// 
        internal static void EmitArray(this ILGenerator il, Type elementType, int count, Action emit) { 
            ContractUtils.RequiresNotNull(elementType, "elementType");
            ContractUtils.RequiresNotNull(emit, "emit"); 
            if (count < 0) throw Error.CountCannotBeNegative(); 

            il.EmitInt(count); 
            il.Emit(OpCodes.Newarr, elementType);
            for (int i = 0; i < count; i++) {
                il.Emit(OpCodes.Dup);
                il.EmitInt(i); 

                emit(i); 
 
                il.EmitStoreElement(elementType);
            } 
        }

        /// 
        /// Emits an array construction code. 
        /// The code assumes that bounds for all dimensions
        /// are already emitted. 
        ///  
        internal static void EmitArray(this ILGenerator il, Type arrayType) {
            ContractUtils.RequiresNotNull(arrayType, "arrayType"); 
            if (!arrayType.IsArray) throw Error.ArrayTypeMustBeArray();

            int rank = arrayType.GetArrayRank();
            if (rank == 1) { 
                il.Emit(OpCodes.Newarr, arrayType.GetElementType());
            } else { 
                Type[] types = new Type[rank]; 
                for (int i = 0; i < rank; i++) {
                    types[i] = typeof(int); 
                }
                il.EmitNew(arrayType, types);
            }
        } 

        #endregion 
 
        #region Support for emitting constants
 
        internal static void EmitDecimal(this ILGenerator il, decimal value) {
            if (Decimal.Truncate(value) == value) {
                if (Int32.MinValue <= value && value <= Int32.MaxValue) {
                    int intValue = Decimal.ToInt32(value); 
                    il.EmitInt(intValue);
                    il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(int) })); 
                } else if (Int64.MinValue <= value && value <= Int64.MaxValue) { 
                    long longValue = Decimal.ToInt64(value);
                    il.EmitLong(longValue); 
                    il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(long) }));
                } else {
                    il.EmitDecimalBits(value);
                } 
            } else {
                il.EmitDecimalBits(value); 
            } 
        }
 
        private static void EmitDecimalBits(this ILGenerator il, decimal value) {
            int[] bits = Decimal.GetBits(value);
            il.EmitInt(bits[0]);
            il.EmitInt(bits[1]); 
            il.EmitInt(bits[2]);
            il.EmitBoolean((bits[3] & 0x80000000) != 0); 
            il.EmitByte((byte)(bits[3] >> 16)); 
            il.EmitNew(typeof(decimal).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte) }));
        } 

        /// 
        /// Emits default(T)
        /// Semantics match C# compiler behavior 
        /// 
        internal static void EmitDefault(this ILGenerator il, Type type) { 
            switch (Type.GetTypeCode(type)) { 
                case TypeCode.Object:
                case TypeCode.DateTime: 
                    if (type.IsValueType) {
                        // Type.GetTypeCode on an enum returns the underlying
                        // integer TypeCode, so we won't get here.
                        Debug.Assert(!type.IsEnum); 

                        // This is the IL for default(T) if T is a generic type 
                        // parameter, so it should work for any type. It's also 
                        // the standard pattern for structs.
                        LocalBuilder lb = il.DeclareLocal(type); 
                        il.Emit(OpCodes.Ldloca, lb);
                        il.Emit(OpCodes.Initobj, type);
                        il.Emit(OpCodes.Ldloc, lb);
                    } else { 
                        il.Emit(OpCodes.Ldnull);
                    } 
                    break; 

                case TypeCode.Empty: 
                case TypeCode.String:
                case TypeCode.DBNull:
                    il.Emit(OpCodes.Ldnull);
                    break; 

                case TypeCode.Boolean: 
                case TypeCode.Char: 
                case TypeCode.SByte:
                case TypeCode.Byte: 
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32: 
                    il.Emit(OpCodes.Ldc_I4_0);
                    break; 
 
                case TypeCode.Int64:
                case TypeCode.UInt64: 
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Conv_I8);
                    break;
 
                case TypeCode.Single:
                    il.Emit(OpCodes.Ldc_R4, default(Single)); 
                    break; 

                case TypeCode.Double: 
                    il.Emit(OpCodes.Ldc_R8, default(Double));
                    break;

                case TypeCode.Decimal: 
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Newobj, typeof(Decimal).GetConstructor(new Type[] { typeof(int) })); 
                    break; 

                default: 
                    throw ContractUtils.Unreachable;
            }
        }
 
        #endregion
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK