PageRenderTime 214ms CodeModel.GetById 136ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting.Core/Compiler/ILGen.cs

https://bitbucket.org/stefanrusek/xronos
C# | 1059 lines | 863 code | 127 blank | 69 comment | 199 complexity | 1ce3bfd5e8911226a3eb99a4180dc6d8 MD5 | raw file
   1/* ****************************************************************************
   2 *
   3 * Copyright (c) Microsoft Corporation. 
   4 *
   5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
   6 * copy of the license can be found in the License.html file at the root of this distribution. If 
   7 * you cannot locate the  Microsoft Public License, please send an email to 
   8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
   9 * by the terms of the Microsoft Public License.
  10 *
  11 * You must not remove this notice, or any other, from this software.
  12 *
  13 *
  14 * ***************************************************************************/
  15using System; using Microsoft;
  16
  17
  18#if CODEPLEX_40
  19using ILGenerator = System.Linq.Expressions.Compiler.OffsetTrackingILGenerator;
  20#else
  21using ILGenerator = Microsoft.Linq.Expressions.Compiler.OffsetTrackingILGenerator;
  22#endif
  23
  24using System.Collections.Generic;
  25using System.Diagnostics;
  26#if CODEPLEX_40
  27using System.Dynamic.Utils;
  28#else
  29using Microsoft.Scripting.Utils;
  30#endif
  31using System.Reflection;
  32using System.Reflection.Emit;
  33using System.Runtime.CompilerServices;
  34#if !CODEPLEX_40
  35using Microsoft.Runtime.CompilerServices;
  36#endif
  37
  38
  39#if CODEPLEX_40
  40namespace System.Linq.Expressions.Compiler {
  41#else
  42namespace Microsoft.Linq.Expressions.Compiler {
  43#endif
  44
  45    internal static class ILGen {
  46
  47        internal static void Emit(this ILGenerator il, OpCode opcode, MethodBase methodBase) {
  48            Debug.Assert(methodBase is MethodInfo || methodBase is ConstructorInfo);
  49
  50            if (methodBase.MemberType == MemberTypes.Constructor) {
  51                il.Emit(opcode, (ConstructorInfo)methodBase);
  52            } else {
  53                il.Emit(opcode, (MethodInfo)methodBase);
  54            }
  55        }
  56
  57        #region Instruction helpers
  58
  59        internal static void EmitLoadArg(this ILGenerator il, int index) {
  60            Debug.Assert(index >= 0);
  61
  62            switch (index) {
  63                case 0:
  64                    il.Emit(OpCodes.Ldarg_0);
  65                    break;
  66                case 1:
  67                    il.Emit(OpCodes.Ldarg_1);
  68                    break;
  69                case 2:
  70                    il.Emit(OpCodes.Ldarg_2);
  71                    break;
  72                case 3:
  73                    il.Emit(OpCodes.Ldarg_3);
  74                    break;
  75                default:
  76                    if (index <= Byte.MaxValue) {
  77                        il.Emit(OpCodes.Ldarg_S, (byte)index);
  78                    } else {
  79                        il.Emit(OpCodes.Ldarg, index);
  80                    }
  81                    break;
  82            }
  83        }
  84
  85        internal static void EmitLoadArgAddress(this ILGenerator il, int index) {
  86            Debug.Assert(index >= 0);
  87
  88            if (index <= Byte.MaxValue) {
  89                il.Emit(OpCodes.Ldarga_S, (byte)index);
  90            } else {
  91                il.Emit(OpCodes.Ldarga, index);
  92            }
  93        }
  94
  95        internal static void EmitStoreArg(this ILGenerator il, int index) {
  96            Debug.Assert(index >= 0);
  97
  98            if (index <= Byte.MaxValue) {
  99                il.Emit(OpCodes.Starg_S, (byte)index);
 100            } else {
 101                il.Emit(OpCodes.Starg, index);
 102            }
 103        }
 104
 105        /// <summary>
 106        /// Emits a Ldind* instruction for the appropriate type
 107        /// </summary>
 108        internal static void EmitLoadValueIndirect(this ILGenerator il, Type type) {
 109            ContractUtils.RequiresNotNull(type, "type");
 110
 111            if (type.IsValueType) {
 112                if (type == typeof(int)) {
 113                    il.Emit(OpCodes.Ldind_I4);
 114                } else if (type == typeof(uint)) {
 115                    il.Emit(OpCodes.Ldind_U4);
 116                } else if (type == typeof(short)) {
 117                    il.Emit(OpCodes.Ldind_I2);
 118                } else if (type == typeof(ushort)) {
 119                    il.Emit(OpCodes.Ldind_U2);
 120                } else if (type == typeof(long) || type == typeof(ulong)) {
 121                    il.Emit(OpCodes.Ldind_I8);
 122                } else if (type == typeof(char)) {
 123                    il.Emit(OpCodes.Ldind_I2);
 124                } else if (type == typeof(bool)) {
 125                    il.Emit(OpCodes.Ldind_I1);
 126                } else if (type == typeof(float)) {
 127                    il.Emit(OpCodes.Ldind_R4);
 128                } else if (type == typeof(double)) {
 129                    il.Emit(OpCodes.Ldind_R8);
 130                } else {
 131                    il.Emit(OpCodes.Ldobj, type);
 132                }
 133            } else {
 134                il.Emit(OpCodes.Ldind_Ref);
 135            }
 136        }
 137
 138
 139        /// <summary>
 140        /// Emits a Stind* instruction for the appropriate type.
 141        /// </summary>
 142        internal static void EmitStoreValueIndirect(this ILGenerator il, Type type) {
 143            ContractUtils.RequiresNotNull(type, "type");
 144
 145            if (type.IsValueType) {
 146                if (type == typeof(int)) {
 147                    il.Emit(OpCodes.Stind_I4);
 148                } else if (type == typeof(short)) {
 149                    il.Emit(OpCodes.Stind_I2);
 150                } else if (type == typeof(long) || type == typeof(ulong)) {
 151                    il.Emit(OpCodes.Stind_I8);
 152                } else if (type == typeof(char)) {
 153                    il.Emit(OpCodes.Stind_I2);
 154                } else if (type == typeof(bool)) {
 155                    il.Emit(OpCodes.Stind_I1);
 156                } else if (type == typeof(float)) {
 157                    il.Emit(OpCodes.Stind_R4);
 158                } else if (type == typeof(double)) {
 159                    il.Emit(OpCodes.Stind_R8);
 160                } else {
 161                    il.Emit(OpCodes.Stobj, type);
 162                }
 163            } else {
 164                il.Emit(OpCodes.Stind_Ref);
 165            }
 166        }
 167
 168        // Emits the Ldelem* instruction for the appropriate type
 169
 170        internal static void EmitLoadElement(this ILGenerator il, Type type) {
 171            ContractUtils.RequiresNotNull(type, "type");
 172
 173            if (!type.IsValueType) {
 174                il.Emit(OpCodes.Ldelem_Ref);
 175            } else if (type.IsEnum) {
 176                il.Emit(OpCodes.Ldelem, type);
 177            } else {
 178                switch (Type.GetTypeCode(type)) {
 179                    case TypeCode.Boolean:
 180                    case TypeCode.SByte:
 181                        il.Emit(OpCodes.Ldelem_I1);
 182                        break;
 183                    case TypeCode.Byte:
 184                        il.Emit(OpCodes.Ldelem_U1);
 185                        break;
 186                    case TypeCode.Int16:
 187                        il.Emit(OpCodes.Ldelem_I2);
 188                        break;
 189                    case TypeCode.Char:
 190                    case TypeCode.UInt16:
 191                        il.Emit(OpCodes.Ldelem_U2);
 192                        break;
 193                    case TypeCode.Int32:
 194                        il.Emit(OpCodes.Ldelem_I4);
 195                        break;
 196                    case TypeCode.UInt32:
 197                        il.Emit(OpCodes.Ldelem_U4);
 198                        break;
 199                    case TypeCode.Int64:
 200                    case TypeCode.UInt64:
 201                        il.Emit(OpCodes.Ldelem_I8);
 202                        break;
 203                    case TypeCode.Single:
 204                        il.Emit(OpCodes.Ldelem_R4);
 205                        break;
 206                    case TypeCode.Double:
 207                        il.Emit(OpCodes.Ldelem_R8);
 208                        break;
 209                    default:
 210                        il.Emit(OpCodes.Ldelem, type);
 211                        break;
 212                }
 213            }
 214        }
 215
 216        /// <summary>
 217        /// Emits a Stelem* instruction for the appropriate type.
 218        /// </summary>
 219        internal static void EmitStoreElement(this ILGenerator il, Type type) {
 220            ContractUtils.RequiresNotNull(type, "type");
 221
 222            if (type.IsEnum) {
 223                il.Emit(OpCodes.Stelem, type);
 224                return;
 225            }
 226            switch (Type.GetTypeCode(type)) {
 227                case TypeCode.Boolean:
 228                case TypeCode.SByte:
 229                case TypeCode.Byte:
 230                    il.Emit(OpCodes.Stelem_I1);
 231                    break;
 232                case TypeCode.Char:
 233                case TypeCode.Int16:
 234                case TypeCode.UInt16:
 235                    il.Emit(OpCodes.Stelem_I2);
 236                    break;
 237                case TypeCode.Int32:
 238                case TypeCode.UInt32:
 239                    il.Emit(OpCodes.Stelem_I4);
 240                    break;
 241                case TypeCode.Int64:
 242                case TypeCode.UInt64:
 243                    il.Emit(OpCodes.Stelem_I8);
 244                    break;
 245                case TypeCode.Single:
 246                    il.Emit(OpCodes.Stelem_R4);
 247                    break;
 248                case TypeCode.Double:
 249                    il.Emit(OpCodes.Stelem_R8);
 250                    break;
 251                default:
 252                    if (type.IsValueType) {
 253                        il.Emit(OpCodes.Stelem, type);
 254                    } else {
 255                        il.Emit(OpCodes.Stelem_Ref);
 256                    }
 257                    break;
 258            }
 259        }
 260
 261        internal static void EmitType(this ILGenerator il, Type type) {
 262            ContractUtils.RequiresNotNull(type, "type");
 263
 264            il.Emit(OpCodes.Ldtoken, type);
 265            il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
 266        }
 267
 268        #endregion
 269
 270        #region Fields, properties and methods
 271
 272        internal static void EmitFieldAddress(this ILGenerator il, FieldInfo fi) {
 273            ContractUtils.RequiresNotNull(fi, "fi");
 274
 275            if (fi.IsStatic) {
 276                il.Emit(OpCodes.Ldsflda, fi);
 277            } else {
 278                il.Emit(OpCodes.Ldflda, fi);
 279            }
 280        }
 281
 282        internal static void EmitFieldGet(this ILGenerator il, FieldInfo fi) {
 283            ContractUtils.RequiresNotNull(fi, "fi");
 284
 285            if (fi.IsStatic) {
 286                il.Emit(OpCodes.Ldsfld, fi);
 287            } else {
 288                il.Emit(OpCodes.Ldfld, fi);
 289            }
 290        }
 291
 292        internal static void EmitFieldSet(this ILGenerator il, FieldInfo fi) {
 293            ContractUtils.RequiresNotNull(fi, "fi");
 294
 295            if (fi.IsStatic) {
 296                il.Emit(OpCodes.Stsfld, fi);
 297            } else {
 298                il.Emit(OpCodes.Stfld, fi);
 299            }
 300        }
 301
 302        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
 303        internal static void EmitNew(this ILGenerator il, ConstructorInfo ci) {
 304            ContractUtils.RequiresNotNull(ci, "ci");
 305
 306            if (ci.DeclaringType.ContainsGenericParameters) {
 307                throw Error.IllegalNewGenericParams(ci.DeclaringType);
 308            }
 309
 310            il.Emit(OpCodes.Newobj, ci);
 311        }
 312
 313        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
 314        internal static void EmitNew(this ILGenerator il, Type type, Type[] paramTypes) {
 315            ContractUtils.RequiresNotNull(type, "type");
 316            ContractUtils.RequiresNotNull(paramTypes, "paramTypes");
 317
 318            ConstructorInfo ci = type.GetConstructor(paramTypes);
 319            ContractUtils.Requires(ci != null, "type", Strings.TypeDoesNotHaveConstructorForTheSignature);
 320            il.EmitNew(ci);
 321        }
 322
 323        #endregion
 324
 325        #region Constants
 326
 327        internal static void EmitNull(this ILGenerator il) {
 328            il.Emit(OpCodes.Ldnull);
 329        }
 330
 331        internal static void EmitString(this ILGenerator il, string value) {
 332            ContractUtils.RequiresNotNull(value, "value");
 333            il.Emit(OpCodes.Ldstr, value);
 334        }
 335
 336        internal static void EmitBoolean(this ILGenerator il, bool value) {
 337            if (value) {
 338                il.Emit(OpCodes.Ldc_I4_1);
 339            } else {
 340                il.Emit(OpCodes.Ldc_I4_0);
 341            }
 342        }
 343
 344        internal static void EmitChar(this ILGenerator il, char value) {
 345            il.EmitInt(value);
 346            il.Emit(OpCodes.Conv_U2);
 347        }
 348
 349        internal static void EmitByte(this ILGenerator il, byte value) {
 350            il.EmitInt(value);
 351            il.Emit(OpCodes.Conv_U1);
 352        }
 353
 354        internal static void EmitSByte(this ILGenerator il, sbyte value) {
 355            il.EmitInt(value);
 356            il.Emit(OpCodes.Conv_I1);
 357        }
 358
 359        internal static void EmitShort(this ILGenerator il, short value) {
 360            il.EmitInt(value);
 361            il.Emit(OpCodes.Conv_I2);
 362        }
 363
 364        internal static void EmitUShort(this ILGenerator il, ushort value) {
 365            il.EmitInt(value);
 366            il.Emit(OpCodes.Conv_U2);
 367        }
 368
 369        internal static void EmitInt(this ILGenerator il, int value) {
 370            OpCode c;
 371            switch (value) {
 372                case -1:
 373                    c = OpCodes.Ldc_I4_M1;
 374                    break;
 375                case 0:
 376                    c = OpCodes.Ldc_I4_0;
 377                    break;
 378                case 1:
 379                    c = OpCodes.Ldc_I4_1;
 380                    break;
 381                case 2:
 382                    c = OpCodes.Ldc_I4_2;
 383                    break;
 384                case 3:
 385                    c = OpCodes.Ldc_I4_3;
 386                    break;
 387                case 4:
 388                    c = OpCodes.Ldc_I4_4;
 389                    break;
 390                case 5:
 391                    c = OpCodes.Ldc_I4_5;
 392                    break;
 393                case 6:
 394                    c = OpCodes.Ldc_I4_6;
 395                    break;
 396                case 7:
 397                    c = OpCodes.Ldc_I4_7;
 398                    break;
 399                case 8:
 400                    c = OpCodes.Ldc_I4_8;
 401                    break;
 402                default:
 403                    if (value >= -128 && value <= 127) {
 404                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
 405                    } else {
 406                        il.Emit(OpCodes.Ldc_I4, value);
 407                    }
 408                    return;
 409            }
 410            il.Emit(c);
 411        }
 412
 413        internal static void EmitUInt(this ILGenerator il, uint value) {
 414            il.EmitInt((int)value);
 415            il.Emit(OpCodes.Conv_U4);
 416        }
 417
 418        internal static void EmitLong(this ILGenerator il, long value) {
 419            il.Emit(OpCodes.Ldc_I8, value);
 420
 421            //
 422            // Now, emit convert to give the constant type information.
 423            //
 424            // Otherwise, it is treated as unsigned and overflow is not
 425            // detected if it's used in checked ops.
 426            //
 427            il.Emit(OpCodes.Conv_I8);
 428        }
 429
 430        internal static void EmitULong(this ILGenerator il, ulong value) {
 431            il.Emit(OpCodes.Ldc_I8, (long)value);
 432            il.Emit(OpCodes.Conv_U8);
 433        }
 434
 435        internal static void EmitDouble(this ILGenerator il, double value) {
 436            il.Emit(OpCodes.Ldc_R8, value);
 437        }
 438
 439        internal static void EmitSingle(this ILGenerator il, float value) {
 440            il.Emit(OpCodes.Ldc_R4, value);
 441        }
 442
 443        // matches TryEmitConstant
 444        internal static bool CanEmitConstant(object value, Type type) {
 445            if (value == null || CanEmitILConstant(type)) {
 446                return true;
 447            }
 448
 449            Type t = value as Type;
 450            if (t != null && ShouldLdtoken(t)) {
 451                return true;
 452            }
 453
 454            MethodBase mb = value as MethodBase;
 455            if (mb != null && ShouldLdtoken(mb)) {
 456                return true;
 457            }
 458
 459            return false;
 460        }
 461
 462        // matches TryEmitILConstant
 463        private static bool CanEmitILConstant(Type type) {
 464            switch (Type.GetTypeCode(type)) {
 465                case TypeCode.Boolean:
 466                case TypeCode.SByte:
 467                case TypeCode.Int16:
 468                case TypeCode.Int32:
 469                case TypeCode.Int64:
 470                case TypeCode.Single:
 471                case TypeCode.Double:
 472                case TypeCode.Char:
 473                case TypeCode.Byte:
 474                case TypeCode.UInt16:
 475                case TypeCode.UInt32:
 476                case TypeCode.UInt64:
 477                case TypeCode.Decimal:
 478                case TypeCode.String:
 479                    return true;
 480            }
 481            return false;
 482        }
 483
 484        internal static void EmitConstant(this ILGenerator il, object value) {
 485            Debug.Assert(value != null);
 486            EmitConstant(il, value, value.GetType());
 487        }
 488
 489
 490        //
 491        // Note: we support emitting more things as IL constants than
 492        // Linq does
 493        internal static void EmitConstant(this ILGenerator il, object value, Type type) {
 494            if (value == null) {
 495                // Smarter than the Linq implementation which uses the initobj
 496                // pattern for all value types (works, but requires a local and
 497                // more IL)
 498                il.EmitDefault(type);
 499                return;
 500            }
 501
 502            // Handle the easy cases
 503            if (il.TryEmitILConstant(value, type)) {
 504                return;
 505            }
 506
 507            // Check for a few more types that we support emitting as constants
 508            Type t = value as Type;
 509            if (t != null && ShouldLdtoken(t)) {
 510                il.EmitType(t);
 511                return;
 512            }
 513
 514            MethodBase mb = value as MethodBase;
 515            if (mb != null && ShouldLdtoken(mb)) {
 516                il.Emit(OpCodes.Ldtoken, mb);
 517                Type dt = mb.DeclaringType;
 518                if (dt != null && dt.IsGenericType) {
 519                    il.Emit(OpCodes.Ldtoken, dt);
 520                    il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }));
 521                } else {
 522                    il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) }));
 523                }
 524                type = TypeUtils.GetConstantType(type);
 525                if (type != typeof(MethodBase)) {
 526                    il.Emit(OpCodes.Castclass, type);
 527                }
 528                return;
 529            }
 530
 531            throw ContractUtils.Unreachable;
 532        }
 533
 534        internal static bool ShouldLdtoken(Type t) {
 535            return t is TypeBuilder || t.IsGenericParameter || t.IsVisible;
 536        }
 537
 538        internal static bool ShouldLdtoken(MethodBase mb) {
 539            // Can't ldtoken on a DynamicMethod
 540            if (mb is DynamicMethod) {
 541                return false;
 542            }
 543
 544            Type dt = mb.DeclaringType;
 545            return dt == null || ShouldLdtoken(dt);
 546        }
 547
 548
 549        private static bool TryEmitILConstant(this ILGenerator il, object value, Type type) {
 550            switch (Type.GetTypeCode(type)) {
 551                case TypeCode.Boolean:
 552                    il.EmitBoolean((bool)value);
 553                    return true;
 554                case TypeCode.SByte:
 555                    il.EmitSByte((sbyte)value);
 556                    return true;
 557                case TypeCode.Int16:
 558                    il.EmitShort((short)value);
 559                    return true;
 560                case TypeCode.Int32:
 561                    il.EmitInt((int)value);
 562                    return true;
 563                case TypeCode.Int64:
 564                    il.EmitLong((long)value);
 565                    return true;
 566                case TypeCode.Single:
 567                    il.EmitSingle((float)value);
 568                    return true;
 569                case TypeCode.Double:
 570                    il.EmitDouble((double)value);
 571                    return true;
 572                case TypeCode.Char:
 573                    il.EmitChar((char)value);
 574                    return true;
 575                case TypeCode.Byte:
 576                    il.EmitByte((byte)value);
 577                    return true;
 578                case TypeCode.UInt16:
 579                    il.EmitUShort((ushort)value);
 580                    return true;
 581                case TypeCode.UInt32:
 582                    il.EmitUInt((uint)value);
 583                    return true;
 584                case TypeCode.UInt64:
 585                    il.EmitULong((ulong)value);
 586                    return true;
 587                case TypeCode.Decimal:
 588                    il.EmitDecimal((decimal)value);
 589                    return true;
 590                case TypeCode.String:
 591                    il.EmitString((string)value);
 592                    return true;
 593                default:
 594                    return false;
 595            }
 596        }
 597
 598        #endregion
 599
 600        #region Linq Conversions
 601
 602        internal static void EmitConvertToType(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 603            if (typeFrom == typeTo) {
 604                return;
 605            }
 606
 607            if (typeFrom == typeof(void) || typeTo == typeof(void)) {
 608                throw ContractUtils.Unreachable;
 609            }
 610
 611            bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom);
 612            bool isTypeToNullable = TypeUtils.IsNullableType(typeTo);
 613
 614            Type nnExprType = TypeUtils.GetNonNullableType(typeFrom);
 615            Type nnType = TypeUtils.GetNonNullableType(typeTo);
 616
 617            if (typeFrom.IsInterface || // interface cast
 618               typeTo.IsInterface ||
 619               typeFrom == typeof(object) || // boxing cast
 620               typeTo == typeof(object)) {
 621                il.EmitCastToType(typeFrom, typeTo);
 622            } else if (isTypeFromNullable || isTypeToNullable) {
 623                il.EmitNullableConversion(typeFrom, typeTo, isChecked);
 624            } else if (!(TypeUtils.IsConvertible(typeFrom) && TypeUtils.IsConvertible(typeTo)) // primitive runtime conversion
 625                       &&
 626                       (nnExprType.IsAssignableFrom(nnType) || // down cast
 627                       nnType.IsAssignableFrom(nnExprType))) // up cast
 628            {
 629                il.EmitCastToType(typeFrom, typeTo);
 630            } else if (typeFrom.IsArray && typeTo.IsArray) {
 631                // See DevDiv Bugs #94657.
 632                il.EmitCastToType(typeFrom, typeTo);
 633            } else {
 634                il.EmitNumericConversion(typeFrom, typeTo, isChecked);
 635            }
 636        }
 637
 638
 639        private static void EmitCastToType(this ILGenerator il, Type typeFrom, Type typeTo) {
 640            if (!typeFrom.IsValueType && typeTo.IsValueType) {
 641                il.Emit(OpCodes.Unbox_Any, typeTo);
 642            } else if (typeFrom.IsValueType && !typeTo.IsValueType) {
 643                il.Emit(OpCodes.Box, typeFrom);
 644                if (typeTo != typeof(object)) {
 645                    il.Emit(OpCodes.Castclass, typeTo);
 646                }
 647            } else if (!typeFrom.IsValueType && !typeTo.IsValueType) {
 648                il.Emit(OpCodes.Castclass, typeTo);
 649            } else {
 650                throw Error.InvalidCast(typeFrom, typeTo);
 651            }
 652        }
 653
 654
 655        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
 656        private static void EmitNumericConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 657            bool isFromUnsigned = TypeUtils.IsUnsigned(typeFrom);
 658            bool isFromFloatingPoint = TypeUtils.IsFloatingPoint(typeFrom);
 659            if (typeTo == typeof(Single)) {
 660                if (isFromUnsigned)
 661                    il.Emit(OpCodes.Conv_R_Un);
 662                il.Emit(OpCodes.Conv_R4);
 663            } else if (typeTo == typeof(Double)) {
 664                if (isFromUnsigned)
 665                    il.Emit(OpCodes.Conv_R_Un);
 666                il.Emit(OpCodes.Conv_R8);
 667            } else {
 668                TypeCode tc = Type.GetTypeCode(typeTo);
 669                if (isChecked) {
 670                    if (isFromUnsigned) {
 671                        switch (tc) {
 672                            case TypeCode.SByte:
 673                                il.Emit(OpCodes.Conv_Ovf_I1_Un);
 674                                break;
 675                            case TypeCode.Int16:
 676                                il.Emit(OpCodes.Conv_Ovf_I2_Un);
 677                                break;
 678                            case TypeCode.Int32:
 679                                il.Emit(OpCodes.Conv_Ovf_I4_Un);
 680                                break;
 681                            case TypeCode.Int64:
 682                                il.Emit(OpCodes.Conv_Ovf_I8_Un);
 683                                break;
 684                            case TypeCode.Byte:
 685                                il.Emit(OpCodes.Conv_Ovf_U1_Un);
 686                                break;
 687                            case TypeCode.UInt16:
 688                            case TypeCode.Char:
 689                                il.Emit(OpCodes.Conv_Ovf_U2_Un);
 690                                break;
 691                            case TypeCode.UInt32:
 692                                il.Emit(OpCodes.Conv_Ovf_U4_Un);
 693                                break;
 694                            case TypeCode.UInt64:
 695                                il.Emit(OpCodes.Conv_Ovf_U8_Un);
 696                                break;
 697                            default:
 698                                throw Error.UnhandledConvert(typeTo);
 699                        }
 700                    } else {
 701                        switch (tc) {
 702                            case TypeCode.SByte:
 703                                il.Emit(OpCodes.Conv_Ovf_I1);
 704                                break;
 705                            case TypeCode.Int16:
 706                                il.Emit(OpCodes.Conv_Ovf_I2);
 707                                break;
 708                            case TypeCode.Int32:
 709                                il.Emit(OpCodes.Conv_Ovf_I4);
 710                                break;
 711                            case TypeCode.Int64:
 712                                il.Emit(OpCodes.Conv_Ovf_I8);
 713                                break;
 714                            case TypeCode.Byte:
 715                                il.Emit(OpCodes.Conv_Ovf_U1);
 716                                break;
 717                            case TypeCode.UInt16:
 718                            case TypeCode.Char:
 719                                il.Emit(OpCodes.Conv_Ovf_U2);
 720                                break;
 721                            case TypeCode.UInt32:
 722                                il.Emit(OpCodes.Conv_Ovf_U4);
 723                                break;
 724                            case TypeCode.UInt64:
 725                                il.Emit(OpCodes.Conv_Ovf_U8);
 726                                break;
 727                            default:
 728                                throw Error.UnhandledConvert(typeTo);
 729                        }
 730                    }
 731                } else {
 732                    if (isFromUnsigned) {
 733                        switch (tc) {
 734                            case TypeCode.SByte:
 735                            case TypeCode.Byte:
 736                                il.Emit(OpCodes.Conv_U1);
 737                                break;
 738                            case TypeCode.Int16:
 739                            case TypeCode.UInt16:
 740                            case TypeCode.Char:
 741                                il.Emit(OpCodes.Conv_U2);
 742                                break;
 743                            case TypeCode.Int32:
 744                            case TypeCode.UInt32:
 745                                il.Emit(OpCodes.Conv_U4);
 746                                break;
 747                            case TypeCode.Int64:
 748                            case TypeCode.UInt64:
 749                                il.Emit(OpCodes.Conv_U8);
 750                                break;
 751                            default:
 752                                throw Error.UnhandledConvert(typeTo);
 753                        }
 754                    } else {
 755                        switch (tc) {
 756                            case TypeCode.SByte:
 757                            case TypeCode.Byte:
 758                                il.Emit(OpCodes.Conv_I1);
 759                                break;
 760                            case TypeCode.Int16:
 761                            case TypeCode.UInt16:
 762                            case TypeCode.Char:
 763                                il.Emit(OpCodes.Conv_I2);
 764                                break;
 765                            case TypeCode.Int32:
 766                            case TypeCode.UInt32:
 767                                il.Emit(OpCodes.Conv_I4);
 768                                break;
 769                            case TypeCode.Int64:
 770                            case TypeCode.UInt64:
 771                                il.Emit(OpCodes.Conv_I8);
 772                                break;
 773                            default:
 774                                throw Error.UnhandledConvert(typeTo);
 775                        }
 776                    }
 777                }
 778            }
 779        }
 780
 781
 782        private static void EmitNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 783            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
 784            Debug.Assert(TypeUtils.IsNullableType(typeTo));
 785            Label labIfNull = default(Label);
 786            Label labEnd = default(Label);
 787            LocalBuilder locFrom = null;
 788            LocalBuilder locTo = null;
 789            locFrom = il.DeclareLocal(typeFrom);
 790            il.Emit(OpCodes.Stloc, locFrom);
 791            locTo = il.DeclareLocal(typeTo);
 792            // test for null
 793            il.Emit(OpCodes.Ldloca, locFrom);
 794            il.EmitHasValue(typeFrom);
 795            labIfNull = il.DefineLabel();
 796            il.Emit(OpCodes.Brfalse_S, labIfNull);
 797            il.Emit(OpCodes.Ldloca, locFrom);
 798            il.EmitGetValueOrDefault(typeFrom);
 799            Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
 800            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
 801            il.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked);
 802            // construct result type
 803            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
 804            il.Emit(OpCodes.Newobj, ci);
 805            il.Emit(OpCodes.Stloc, locTo);
 806            labEnd = il.DefineLabel();
 807            il.Emit(OpCodes.Br_S, labEnd);
 808            // if null then create a default one
 809            il.MarkLabel(labIfNull);
 810            il.Emit(OpCodes.Ldloca, locTo);
 811            il.Emit(OpCodes.Initobj, typeTo);
 812            il.MarkLabel(labEnd);
 813            il.Emit(OpCodes.Ldloc, locTo);
 814        }
 815
 816
 817        private static void EmitNonNullableToNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 818            Debug.Assert(!TypeUtils.IsNullableType(typeFrom));
 819            Debug.Assert(TypeUtils.IsNullableType(typeTo));
 820            LocalBuilder locTo = null;
 821            locTo = il.DeclareLocal(typeTo);
 822            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
 823            il.EmitConvertToType(typeFrom, nnTypeTo, isChecked);
 824            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
 825            il.Emit(OpCodes.Newobj, ci);
 826            il.Emit(OpCodes.Stloc, locTo);
 827            il.Emit(OpCodes.Ldloc, locTo);
 828        }
 829
 830
 831        private static void EmitNullableToNonNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 832            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
 833            Debug.Assert(!TypeUtils.IsNullableType(typeTo));
 834            if (typeTo.IsValueType)
 835                il.EmitNullableToNonNullableStructConversion(typeFrom, typeTo, isChecked);
 836            else
 837                il.EmitNullableToReferenceConversion(typeFrom);
 838        }
 839
 840
 841        private static void EmitNullableToNonNullableStructConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 842            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
 843            Debug.Assert(!TypeUtils.IsNullableType(typeTo));
 844            Debug.Assert(typeTo.IsValueType);
 845            LocalBuilder locFrom = null;
 846            locFrom = il.DeclareLocal(typeFrom);
 847            il.Emit(OpCodes.Stloc, locFrom);
 848            il.Emit(OpCodes.Ldloca, locFrom);
 849            il.EmitGetValue(typeFrom);
 850            Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
 851            il.EmitConvertToType(nnTypeFrom, typeTo, isChecked);
 852        }
 853
 854
 855        private static void EmitNullableToReferenceConversion(this ILGenerator il, Type typeFrom) {
 856            Debug.Assert(TypeUtils.IsNullableType(typeFrom));
 857            // We've got a conversion from nullable to Object, ValueType, Enum, etc.  Just box it so that
 858            // we get the nullable semantics.  
 859            il.Emit(OpCodes.Box, typeFrom);
 860        }
 861
 862
 863        private static void EmitNullableConversion(this ILGenerator il, Type typeFrom, Type typeTo, bool isChecked) {
 864            bool isTypeFromNullable = TypeUtils.IsNullableType(typeFrom);
 865            bool isTypeToNullable = TypeUtils.IsNullableType(typeTo);
 866            Debug.Assert(isTypeFromNullable || isTypeToNullable);
 867            if (isTypeFromNullable && isTypeToNullable)
 868                il.EmitNullableToNullableConversion(typeFrom, typeTo, isChecked);
 869            else if (isTypeFromNullable)
 870                il.EmitNullableToNonNullableConversion(typeFrom, typeTo, isChecked);
 871            else
 872                il.EmitNonNullableToNullableConversion(typeFrom, typeTo, isChecked);
 873        }
 874
 875
 876        internal static void EmitHasValue(this ILGenerator il, Type nullableType) {
 877            MethodInfo mi = nullableType.GetMethod("get_HasValue", BindingFlags.Instance | BindingFlags.Public);
 878            Debug.Assert(nullableType.IsValueType);
 879            il.Emit(OpCodes.Call, mi);
 880        }
 881
 882
 883        internal static void EmitGetValue(this ILGenerator il, Type nullableType) {
 884            MethodInfo mi = nullableType.GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public);
 885            Debug.Assert(nullableType.IsValueType);
 886            il.Emit(OpCodes.Call, mi);
 887        }
 888
 889
 890        internal static void EmitGetValueOrDefault(this ILGenerator il, Type nullableType) {
 891            MethodInfo mi = nullableType.GetMethod("GetValueOrDefault", System.Type.EmptyTypes);
 892            Debug.Assert(nullableType.IsValueType);
 893            il.Emit(OpCodes.Call, mi);
 894        }
 895
 896        #endregion
 897
 898        #region Arrays
 899
 900        /// <summary>
 901        /// Emits an array of constant values provided in the given list.
 902        /// The array is strongly typed.
 903        /// </summary>
 904        internal static void EmitArray<T>(this ILGenerator il, IList<T> items) {
 905            ContractUtils.RequiresNotNull(items, "items");
 906
 907            il.EmitInt(items.Count);
 908            il.Emit(OpCodes.Newarr, typeof(T));
 909            for (int i = 0; i < items.Count; i++) {
 910                il.Emit(OpCodes.Dup);
 911                il.EmitInt(i);
 912                il.EmitConstant(items[i], typeof(T));
 913                il.EmitStoreElement(typeof(T));
 914            }
 915        }
 916
 917        /// <summary>
 918        /// Emits an array of values of count size.  The items are emitted via the callback
 919        /// which is provided with the current item index to emit.
 920        /// </summary>
 921        internal static void EmitArray(this ILGenerator il, Type elementType, int count, Action<int> emit) {
 922            ContractUtils.RequiresNotNull(elementType, "elementType");
 923            ContractUtils.RequiresNotNull(emit, "emit");
 924            ContractUtils.Requires(count >= 0, "count", Strings.CountCannotBeNegative);
 925
 926            il.EmitInt(count);
 927            il.Emit(OpCodes.Newarr, elementType);
 928            for (int i = 0; i < count; i++) {
 929                il.Emit(OpCodes.Dup);
 930                il.EmitInt(i);
 931
 932                emit(i);
 933
 934                il.EmitStoreElement(elementType);
 935            }
 936        }
 937
 938        /// <summary>
 939        /// Emits an array construction code.  
 940        /// The code assumes that bounds for all dimensions
 941        /// are already emitted.
 942        /// </summary>
 943        internal static void EmitArray(this ILGenerator il, Type arrayType) {
 944            ContractUtils.RequiresNotNull(arrayType, "arrayType");
 945            ContractUtils.Requires(arrayType.IsArray, "arrayType", Strings.ArrayTypeMustBeArray);
 946
 947            int rank = arrayType.GetArrayRank();
 948            if (rank == 1) {
 949                il.Emit(OpCodes.Newarr, arrayType.GetElementType());
 950            } else {
 951                Type[] types = new Type[rank];
 952                for (int i = 0; i < rank; i++) {
 953                    types[i] = typeof(int);
 954                }
 955                il. EmitNew(arrayType, types);
 956            }
 957        }
 958
 959        #endregion
 960
 961        #region Support for emitting constants
 962
 963        internal static void EmitDecimal(this ILGenerator il, decimal value) {
 964            if (Decimal.Truncate(value) == value) {
 965                if (Int32.MinValue <= value && value <= Int32.MaxValue) {
 966                    int intValue = Decimal.ToInt32(value);
 967                    il.EmitInt(intValue);
 968                    il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(int) }));
 969                } else if (Int64.MinValue <= value && value <= Int64.MaxValue) {
 970                    long longValue = Decimal.ToInt64(value);
 971                    il.EmitLong(longValue);
 972                    il.EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(long) }));
 973                } else {
 974                    il.EmitDecimalBits(value);
 975                }
 976            } else {
 977                il.EmitDecimalBits(value);
 978            }
 979        }
 980
 981        private static void EmitDecimalBits(this ILGenerator il, decimal value) {
 982            int[] bits = Decimal.GetBits(value);
 983            il.EmitInt(bits[0]);
 984            il.EmitInt(bits[1]);
 985            il.EmitInt(bits[2]);
 986            il.EmitBoolean((bits[3] & 0x80000000) != 0);
 987            il.EmitByte((byte)(bits[3] >> 16));
 988            il.EmitNew(typeof(decimal).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte) }));
 989        }
 990
 991        /// <summary>
 992        /// Emits default(T)
 993        /// Semantics match C# compiler behavior
 994        /// </summary>
 995        internal static void EmitDefault(this ILGenerator il, Type type) {
 996            switch (Type.GetTypeCode(type)) {
 997                case TypeCode.Object:
 998                case TypeCode.DateTime:
 999                    if (type.IsValueType) {
1000                        // Type.GetTypeCode on an enum returns the underlying
1001                        // integer TypeCode, so we won't get here.
1002                        Debug.Assert(!type.IsEnum);
1003
1004                        // This is the IL for default(T) if T is a generic type
1005                        // parameter, so it should work for any type. It's also
1006                        // the standard pattern for structs.
1007                        LocalBuilder lb = il.DeclareLocal(type);
1008                        il.Emit(OpCodes.Ldloca, lb);
1009                        il.Emit(OpCodes.Initobj, type);
1010                        il.Emit(OpCodes.Ldloc, lb);
1011                    } else {
1012                        il.Emit(OpCodes.Ldnull);
1013                    }
1014                    break;
1015
1016                case TypeCode.Empty:
1017                case TypeCode.String:
1018                case TypeCode.DBNull:
1019                    il.Emit(OpCodes.Ldnull);
1020                    break;
1021
1022                case TypeCode.Boolean:
1023                case TypeCode.Char:
1024                case TypeCode.SByte:
1025                case TypeCode.Byte:
1026                case TypeCode.Int16:
1027                case TypeCode.UInt16:
1028                case TypeCode.Int32:
1029                case TypeCode.UInt32:
1030                    il.Emit(OpCodes.Ldc_I4_0);
1031                    break;
1032
1033                case TypeCode.Int64:
1034                case TypeCode.UInt64:
1035                    il.Emit(OpCodes.Ldc_I4_0);
1036                    il.Emit(OpCodes.Conv_I8);
1037                    break;
1038
1039                case TypeCode.Single:
1040                    il.Emit(OpCodes.Ldc_R4, default(Single));
1041                    break;
1042
1043                case TypeCode.Double:
1044                    il.Emit(OpCodes.Ldc_R8, default(Double));
1045                    break;
1046
1047                case TypeCode.Decimal:
1048                    il.Emit(OpCodes.Ldc_I4_0);
1049                    il.Emit(OpCodes.Newobj, typeof(Decimal).GetConstructor(new Type[] { typeof(int) }));
1050                    break;
1051
1052                default:
1053                    throw ContractUtils.Unreachable;
1054            }
1055        }
1056
1057        #endregion
1058    }
1059}