ILGen.cs :  » Script » IronPython » Microsoft » Scripting » Generation » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Script » IronPython 
IronPython » Microsoft » Scripting » Generation » 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.
 *
 *
 * ***************************************************************************/

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;

namespace Microsoft.Scripting.Generation{

    public delegate void EmitArrayHelper(int index);

    // TODO: change to extension methods for ILGenerator
    public class ILGen {
        private readonly ILGenerator _ilg;
        private readonly KeyedQueue<Type, LocalBuilder> _freeLocals = new KeyedQueue<Type, LocalBuilder>();

        // TODO: remove Python dependency
        public ILGen(ILGenerator ilg) {
            ContractUtils.RequiresNotNull(ilg, "ilg");

            _ilg = ilg;
        }

        #region ILGenerator Methods

        /// <summary>
        /// Begins a catch block.
        /// </summary>
        public virtual void BeginCatchBlock(Type exceptionType) {
            _ilg.BeginCatchBlock(exceptionType);
        }

        /// <summary>
        /// Begins an exception block for a filtered exception.
        /// </summary>
        public virtual void BeginExceptFilterBlock() {
            _ilg.BeginExceptFilterBlock();
        }

        /// <summary>
        /// Begins an exception block for a non-filtered exception.
        /// </summary>
        /// <returns></returns>
        public virtual Label BeginExceptionBlock() {
            return _ilg.BeginExceptionBlock();
        }

        /// <summary>
        /// Begins an exception fault block
        /// </summary>
        public virtual void BeginFaultBlock() {
            _ilg.BeginFaultBlock();
        }

        /// <summary>
        /// Begins a finally block
        /// </summary>
        public virtual void BeginFinallyBlock() {
            _ilg.BeginFinallyBlock();
        }

        /// <summary>
        /// Ends an exception block.
        /// </summary>
        public virtual void EndExceptionBlock() {
            _ilg.EndExceptionBlock();
        }

        /// <summary>
        /// Begins a lexical scope.
        /// </summary>
        public virtual void BeginScope() {
            _ilg.BeginScope();
        }

        /// <summary>
        /// Ends a lexical scope.
        /// </summary>
        public virtual void EndScope() {
            _ilg.EndScope();
        }

        /// <summary>
        /// Declares a local variable of the specified type.
        /// </summary>
        public virtual LocalBuilder DeclareLocal(Type localType) {
            return _ilg.DeclareLocal(localType);
        }

        /// <summary>
        /// Declares a local variable of the specified type, optionally
        /// pinning the object referred to by the variable.
        /// </summary>
        public virtual LocalBuilder DeclareLocal(Type localType, bool pinned) {
            return _ilg.DeclareLocal(localType, pinned);
        }

        /// <summary>
        /// Declares a new label.
        /// </summary>
        public virtual Label DefineLabel() {
            return _ilg.DefineLabel();
        }

        /// <summary>
        /// Marks the label at the current position.
        /// </summary>
        public virtual void MarkLabel(Label loc) {
            _ilg.MarkLabel(loc);
        }

        /// <summary>
        /// Emits an instruction.
        /// </summary>
        public virtual void Emit(OpCode opcode) {
            _ilg.Emit(opcode);
        }

        /// <summary>
        /// Emits an instruction with a byte argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, byte arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with the metadata token for the specified contructor.
        /// </summary>
        public virtual void Emit(OpCode opcode, ConstructorInfo con) {
            _ilg.Emit(opcode, con);
        }

        /// <summary>
        /// Emits an instruction with a double argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, double arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with the metadata token for the specified field.
        /// </summary>
        public virtual void Emit(OpCode opcode, FieldInfo field) {
            _ilg.Emit(opcode, field);
        }

        /// <summary>
        /// Emits an instruction with a float argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, float arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with an int argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, int arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with a label argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, Label label) {
            _ilg.Emit(opcode, label);
        }

        /// <summary>
        /// Emits an instruction with multiple target labels (switch).
        /// </summary>
        public virtual void Emit(OpCode opcode, Label[] labels) {
            _ilg.Emit(opcode, labels);
        }

        /// <summary>
        /// Emits an instruction with a reference to a local variable.
        /// </summary>
        public virtual void Emit(OpCode opcode, LocalBuilder local) {
            _ilg.Emit(opcode, local);
        }

        /// <summary>
        /// Emits an instruction with a long argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, long arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with the metadata token for a specified method.
        /// </summary>
        public virtual void Emit(OpCode opcode, MethodInfo meth) {
            _ilg.Emit(opcode, meth);
        }

        /// <summary>
        /// Emits an instruction with a signed byte argument.
        /// </summary>
        [CLSCompliant(false)]
        public virtual void Emit(OpCode opcode, sbyte arg) {
            _ilg.Emit(opcode, arg);
        }

        /// <summary>
        /// Emits an instruction with a short argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, short arg) {
            _ilg.Emit(opcode, arg);
        }

#if !SILVERLIGHT
        /// <summary>
        /// Emits an instruction with a signature token.
        /// </summary>
        public virtual void Emit(OpCode opcode, SignatureHelper signature) {
            _ilg.Emit(opcode, signature);
        }
#endif

        /// <summary>
        /// Emits an instruction with a string argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, string str) {
            _ilg.Emit(opcode, str);
        }

        /// <summary>
        /// Emits an instruction with the metadata token for a specified type argument.
        /// </summary>
        public virtual void Emit(OpCode opcode, Type cls) {
            _ilg.Emit(opcode, cls);
        }

        /// <summary>
        /// Emits a call or a virtual call to the varargs method.
        /// </summary>
        public virtual void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes) {
            _ilg.EmitCall(opcode, methodInfo, optionalParameterTypes);
        }

#if !SILVERLIGHT
        /// <summary>
        /// Emits an unmanaged indirect call instruction.
        /// </summary>
        public virtual void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes) {
            _ilg.EmitCalli(opcode, unmanagedCallConv, returnType, parameterTypes);
        }

        /// <summary>
        /// Emits a managed indirect call instruction.
        /// </summary>
        public virtual void EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes) {
            _ilg.EmitCalli(opcode, callingConvention, returnType, parameterTypes, optionalParameterTypes);
        }
#endif

        /// <summary>
        /// Marks a sequence point.
        /// </summary>
        public virtual void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn) {
            _ilg.MarkSequencePoint(document, startLine, startColumn, endLine, endColumn);
        }

        /// <summary>
        /// Specifies the namespace to be used in evaluating locals and watches for the
        ///     current active lexical scope.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames")] // TODO: fix
        public virtual void UsingNamespace(string usingNamespace) {
            _ilg.UsingNamespace(usingNamespace);
        }

        #endregion

        #region Simple helpers

        [Conditional("DEBUG")]
        internal void EmitDebugWriteLine(string message) {
            EmitString(message);
            EmitCall(typeof(Debug), "WriteLine", new Type[] { typeof(string) });
        }

        internal void Emit(OpCode opcode, MethodBase methodBase) {
            Debug.Assert(methodBase is MethodInfo || methodBase is ConstructorInfo);

            if (methodBase.MemberType == MemberTypes.Constructor) {
                Emit(opcode, (ConstructorInfo)methodBase);
            } else {
                Emit(opcode, (MethodInfo)methodBase);
            }
        }

        #endregion

        #region Instruction helpers

        public void EmitLoadArg(int index) {
            ContractUtils.Requires(index >= 0, "index");

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

        public void EmitLoadArgAddress(int index) {
            ContractUtils.Requires(index >= 0, "index");

            if (index <= Byte.MaxValue) {
                Emit(OpCodes.Ldarga_S, (byte)index);
            } else {
                Emit(OpCodes.Ldarga, index);
            }
        }

        public void EmitStoreArg(int index) {
            ContractUtils.Requires(index >= 0, "index");

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

        /// <summary>
        /// Emits a Ldind* instruction for the appropriate type
        /// </summary>
        public void EmitLoadValueIndirect(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            if (type.IsValueType) {
                if (type == typeof(int)) {
                    Emit(OpCodes.Ldind_I4);
                } else if (type == typeof(uint)) {
                    Emit(OpCodes.Ldind_U4);
                } else if (type == typeof(short)) {
                    Emit(OpCodes.Ldind_I2);
                } else if (type == typeof(ushort)) {
                    Emit(OpCodes.Ldind_U2);
                } else if (type == typeof(long) || type == typeof(ulong)) {
                    Emit(OpCodes.Ldind_I8);
                } else if (type == typeof(char)) {
                    Emit(OpCodes.Ldind_I2);
                } else if (type == typeof(bool)) {
                    Emit(OpCodes.Ldind_I1);
                } else if (type == typeof(float)) {
                    Emit(OpCodes.Ldind_R4);
                } else if (type == typeof(double)) {
                    Emit(OpCodes.Ldind_R8);
                } else {
                    Emit(OpCodes.Ldobj, type);
                }
            } else if (type.IsGenericParameter) {
                Emit(OpCodes.Ldobj, type);
            } else {
                Emit(OpCodes.Ldind_Ref);
            }
        }


        /// <summary>
        /// Emits a Stind* instruction for the appropriate type.
        /// </summary>
        public void EmitStoreValueIndirect(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

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

        // Emits the Ldelem* instruction for the appropriate type
        //CONFORMING
        public void EmitLoadElement(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            if (!type.IsValueType) {
                Emit(OpCodes.Ldelem_Ref);
            } else if (type.IsEnum) {
                Emit(OpCodes.Ldelem, type);
            } else {
                switch (Type.GetTypeCode(type)) {
                    case TypeCode.Boolean:
                    case TypeCode.SByte:
                        Emit(OpCodes.Ldelem_I1);
                        break;
                    case TypeCode.Byte:
                        Emit(OpCodes.Ldelem_U1);
                        break;
                    case TypeCode.Int16:
                        Emit(OpCodes.Ldelem_I2);
                        break;
                    case TypeCode.Char:
                    case TypeCode.UInt16:
                        Emit(OpCodes.Ldelem_U2);
                        break;
                    case TypeCode.Int32:
                        Emit(OpCodes.Ldelem_I4);
                        break;
                    case TypeCode.UInt32:
                        Emit(OpCodes.Ldelem_U4);
                        break;
                    case TypeCode.Int64:
                    case TypeCode.UInt64:
                        Emit(OpCodes.Ldelem_I8);
                        break;
                    case TypeCode.Single:
                        Emit(OpCodes.Ldelem_R4);
                        break;
                    case TypeCode.Double:
                        Emit(OpCodes.Ldelem_R8);
                        break;
                    default:
                        Emit(OpCodes.Ldelem, type);
                        break;
                }
            }
        }

        /// <summary>
        /// Emits a Stelem* instruction for the appropriate type.
        /// </summary>
        public void EmitStoreElement(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            if (type.IsEnum) {
                Emit(OpCodes.Stelem, type);
                return;
            }
            switch (Type.GetTypeCode(type)) {
                case TypeCode.Boolean:
                case TypeCode.SByte:
                case TypeCode.Byte:
                    Emit(OpCodes.Stelem_I1);
                    break;
                case TypeCode.Char:
                case TypeCode.Int16:
                case TypeCode.UInt16:
                    Emit(OpCodes.Stelem_I2);
                    break;
                case TypeCode.Int32:
                case TypeCode.UInt32:
                    Emit(OpCodes.Stelem_I4);
                    break;
                case TypeCode.Int64:
                case TypeCode.UInt64:
                    Emit(OpCodes.Stelem_I8);
                    break;
                case TypeCode.Single:
                    Emit(OpCodes.Stelem_R4);
                    break;
                case TypeCode.Double:
                    Emit(OpCodes.Stelem_R8);
                    break;
                default:
                    if (type.IsValueType) {
                        Emit(OpCodes.Stelem, type);
                    } else {
                        Emit(OpCodes.Stelem_Ref);
                    }
                    break;
            }
        }

        public void EmitType(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            Emit(OpCodes.Ldtoken, type);
            EmitCall(typeof(Type), "GetTypeFromHandle");
        }

        public void EmitUnbox(Type type) {
            ContractUtils.RequiresNotNull(type, "type");
            Emit(OpCodes.Unbox_Any, type);
        }

        #endregion

        #region Fields, properties and methods

        public void EmitPropertyGet(Type type, string name) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");

            PropertyInfo pi = type.GetProperty(name);
            ContractUtils.Requires(pi != null, "name", Strings.PropertyDoesNotExist);

            EmitPropertyGet(pi);
        }

        public void EmitPropertyGet(PropertyInfo pi) {
            ContractUtils.RequiresNotNull(pi, "pi");

            if (!pi.CanRead) {
                throw Error.CantReadProperty();
            }

            EmitCall(pi.GetGetMethod());
        }

        public void EmitPropertySet(Type type, string name) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");

            PropertyInfo pi = type.GetProperty(name);
            ContractUtils.Requires(pi != null, "name", Strings.PropertyDoesNotExist);

            EmitPropertySet(pi);
        }

        public void EmitPropertySet(PropertyInfo pi) {
            ContractUtils.RequiresNotNull(pi, "pi");

            if (!pi.CanWrite) {
                throw Error.CantWriteProperty();
            }

            EmitCall(pi.GetSetMethod());
        }

        public void EmitFieldAddress(FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                Emit(OpCodes.Ldsflda, fi);
            } else {
                Emit(OpCodes.Ldflda, fi);
            }
        }

        public void EmitFieldGet(Type type, String name) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");

            FieldInfo fi = type.GetField(name);
            ContractUtils.Requires(fi != null, "name", Strings.FieldDoesNotExist);
            EmitFieldGet(fi);
        }

        public void EmitFieldSet(Type type, String name) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");

            FieldInfo fi = type.GetField(name);
            ContractUtils.Requires(fi != null, "name", Strings.FieldDoesNotExist);
            EmitFieldSet(fi);
        }

        public void EmitFieldGet(FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

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

        public void EmitFieldSet(FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                Emit(OpCodes.Stsfld, fi);
            } else {
                Emit(OpCodes.Stfld, fi);
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
        public void EmitNew(ConstructorInfo ci) {
            ContractUtils.RequiresNotNull(ci, "ci");

            if (ci.DeclaringType.ContainsGenericParameters) {
                throw Error.IllegalNew_GenericParams(ci.DeclaringType);
            }

            Emit(OpCodes.Newobj, ci);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
        public void EmitNew(Type type, Type[] paramTypes) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(paramTypes, "paramTypes");

            ConstructorInfo ci = type.GetConstructor(paramTypes);
            ContractUtils.Requires(ci != null, "type", Strings.TypeDoesNotHaveConstructorForTheSignature);
            EmitNew(ci);
        }

        public void EmitCall(MethodInfo mi) {
            ContractUtils.RequiresNotNull(mi, "mi");

            if (mi.IsVirtual && !mi.DeclaringType.IsValueType) {
                Emit(OpCodes.Callvirt, mi);
            } else {
                Emit(OpCodes.Call, mi);
            }
        }

        public void EmitCall(Type type, String name) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");

            MethodInfo mi = type.GetMethod(name);
            ContractUtils.Requires(mi != null, "type", Strings.TypeDoesNotHaveMethodForName);

            EmitCall(mi);
        }

        public void EmitCall(Type type, String name, Type[] paramTypes) {
            ContractUtils.RequiresNotNull(type, "type");
            ContractUtils.RequiresNotNull(name, "name");
            ContractUtils.RequiresNotNull(paramTypes, "paramTypes");

            MethodInfo mi = type.GetMethod(name, paramTypes);
            ContractUtils.Requires(mi != null, "type", Strings.TypeDoesNotHaveMethodForNameSignature);

            EmitCall(mi);
        }

        #endregion

        #region Constants

        public void EmitNull() {
            Emit(OpCodes.Ldnull);
        }

        public void EmitString(string value) {
            ContractUtils.RequiresNotNull(value, "value");
            Emit(OpCodes.Ldstr, value);
        }

        public void EmitBoolean(bool value) {
            if (value) {
                Emit(OpCodes.Ldc_I4_1);
            } else {
                Emit(OpCodes.Ldc_I4_0);
            }
        }

        public void EmitChar(char value) {
            EmitInt(value);
            Emit(OpCodes.Conv_U2);
        }

        public void EmitByte(byte value) {
            EmitInt(value);
            Emit(OpCodes.Conv_U1);
        }

        [CLSCompliant(false)]
        public void EmitSByte(sbyte value) {
            EmitInt(value);
            Emit(OpCodes.Conv_I1);
        }

        public void EmitShort(short value) {
            EmitInt(value);
            Emit(OpCodes.Conv_I2);
        }

        [CLSCompliant(false)]
        public void EmitUShort(ushort value) {
            EmitInt(value);
            Emit(OpCodes.Conv_U2);
        }

        public void EmitInt(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) {
                        Emit(OpCodes.Ldc_I4_S, (sbyte)value);
                    } else {
                        Emit(OpCodes.Ldc_I4, value);
                    }
                    return;
            }
            Emit(c);
        }

        [CLSCompliant(false)]
        public void EmitUInt(uint value) {
            EmitInt((int)value);
            Emit(OpCodes.Conv_U4);
        }

        public void EmitLong(long value) {
            Emit(OpCodes.Ldc_I8, value);
        }

        [CLSCompliant(false)]
        public void EmitULong(ulong value) {
            Emit(OpCodes.Ldc_I8, (long)value);
            Emit(OpCodes.Conv_U8);
        }

        public void EmitDouble(double value) {
            Emit(OpCodes.Ldc_R8, value);
        }

        public void EmitSingle(float value) {
            Emit(OpCodes.Ldc_R4, value);
        }

        private void EmitSimpleConstant(object value) {
            if (!TryEmitConstant(value, value == null ? typeof(object) : value.GetType())) {
                throw Error.CanotEmitConstant(value, value.GetType());
            }
        }

        //CONFORMING
        //
        // Note: we support emitting a lot more things as IL constants than
        // Linq does
        internal bool TryEmitConstant(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)
                EmitDefault(type);
                return true;
            }

            // Handle the easy cases
            if (TryEmitILConstant(value, type)) {
                return true;
            }

            // Check for a few more types that we support emitting as constants
            Type t = value as Type;
            if (t != null && ShouldLdtoken(t)) {
                EmitType(t);
                return true;
            }

            MethodBase mb = value as MethodBase;
            if (mb != null && ShouldLdtoken(mb)) {
                Emit(OpCodes.Ldtoken, mb);
                Type dt = mb.DeclaringType;
                if (dt != null && dt.IsGenericType) {
                    Emit(OpCodes.Ldtoken, dt);
                    EmitCall(typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }));
                } else {
                    EmitCall(typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) }));
                }
                type = TypeUtils.GetConstantType(type);
                if (type != typeof(MethodBase)) {
                    Emit(OpCodes.Castclass, type);
                }
                return true;
            }

            return false;
        }

        // TODO: Can we always ldtoken and let restrictedSkipVisibility sort things out?
        public static bool ShouldLdtoken(Type t) {
            return t is TypeBuilder || t.IsGenericParameter || t.IsVisible;
        }

        public 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);
        }

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

        #endregion

        // TODO: deprecate in favor of the Linq versions
        #region Conversions

        public void EmitImplicitCast(Type from, Type to) {
            if (!TryEmitCast(from, to, true)) {
                throw Error.NoImplicitCast(from, to);
            }
        }

        public void EmitExplicitCast(Type from, Type to) {
            if (!TryEmitCast(from, to, false)) {
                throw Error.NoExplicitCast(from, to);
            }
        }

        public bool TryEmitImplicitCast(Type from, Type to) {
            return TryEmitCast(from, to, true);
        }

        public bool TryEmitExplicitCast(Type from, Type to) {
            return TryEmitCast(from, to, false);
        }

        private bool TryEmitCast(Type from, Type to, bool implicitOnly) {
            ContractUtils.RequiresNotNull(from, "from");
            ContractUtils.RequiresNotNull(to, "to");

            // No cast necessary if identical types
            if (from == to) {
                return true;
            }

            if (to.IsAssignableFrom(from)) {
                // T -> Nullable<T>
                if (TypeUtils.IsNullableType(to)) {
                    Type nonNullableTo = TypeUtils.GetNonNullableType(to);
                    if (TryEmitCast(from, nonNullableTo, true)) {
                        EmitNew(to.GetConstructor(new Type[] { nonNullableTo }));
                    } else {
                        return false;
                    }
                }

                if (from.IsValueType) {
                    if (to == typeof(object)) {
                        EmitBoxing(from);
                        return true;
                    }
                }

                if (to.IsInterface) {
                    Emit(OpCodes.Box, from);
                    return true;
                }

                if (from.IsEnum && to == typeof(Enum)) {
                    Emit(OpCodes.Box, from);
                    return true;
                }

                // They are assignable and reference types.
                return true;
            }

            if (to == typeof(void)) {
                Emit(OpCodes.Pop);
                return true;
            }

            if (to.IsValueType && from == typeof(object)) {
                if (implicitOnly) {
                    return false;
                }
                Emit(OpCodes.Unbox_Any, to);
                return true;
            }

            if (to.IsValueType != from.IsValueType) {
                return false;
            }

            if (!to.IsValueType) {
                if (implicitOnly) {
                    return false;
                }
                Emit(OpCodes.Castclass, to);
                return true;
            }

            if (to.IsEnum) {
                to = Enum.GetUnderlyingType(to);
            }
            if (from.IsEnum) {
                from = Enum.GetUnderlyingType(from);
            }

            if (to == from) {
                return true;
            }

            if (EmitNumericCast(from, to, implicitOnly)) {
                return true;
            }

            return false;
        }

        public bool EmitNumericCast(Type from, Type to, bool implicitOnly) {
            TypeCode fc = Type.GetTypeCode(from);
            TypeCode tc = Type.GetTypeCode(to);
            int fromx, fromy, tox, toy;

            if (!TypeUtils.GetNumericConversionOrder(fc, out fromx, out fromy) ||
                !TypeUtils.GetNumericConversionOrder(tc, out tox, out toy)) {
                // numeric <-> non-numeric
                return false;
            }

            bool isImplicit = TypeUtils.IsImplicitlyConvertible(fromx, fromy, tox, toy);

            if (implicitOnly && !isImplicit) {
                return false;
            }

            // IL conversion instruction also needed for floating point -> integer:
            if (!isImplicit || toy == 2 || tox == 2) {
                switch (tc) {
                    case TypeCode.SByte:
                        Emit(OpCodes.Conv_I1);
                        break;
                    case TypeCode.Int16:
                        Emit(OpCodes.Conv_I2);
                        break;
                    case TypeCode.Int32:
                        Emit(OpCodes.Conv_I4);
                        break;
                    case TypeCode.Int64:
                        Emit(OpCodes.Conv_I8);
                        break;
                    case TypeCode.Byte:
                        Emit(OpCodes.Conv_U1);
                        break;
                    case TypeCode.UInt16:
                        Emit(OpCodes.Conv_U1);
                        break;
                    case TypeCode.UInt32:
                        Emit(OpCodes.Conv_U2);
                        break;
                    case TypeCode.UInt64:
                        Emit(OpCodes.Conv_U4);
                        break;
                    case TypeCode.Single:
                        Emit(OpCodes.Conv_R4);
                        break;
                    case TypeCode.Double:
                        Emit(OpCodes.Conv_R8);
                        break;
                    default:
                        throw Assert.Unreachable;
                }
            }

            return true;
        }

        // TODO: we should try to remove this. It caused a 4x degrade in a
        // conversion intense lambda. And also seems like a bad idea to mess
        // with CLR boxing semantics.
        /// <summary>
        /// Boxes the value of the stack. No-op for reference types. Void is
        /// converted to a null reference. For almost all value types this
        /// method will box them in the standard way. Int32 and Boolean are
        /// handled with optimized conversions that reuse the same object for
        /// small values. For Int32 this is purely a performance optimization.
        /// For Boolean this is use to ensure that True and False are always
        /// the same objects.
        /// </summary>
        public void EmitBoxing(Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            if (type.IsValueType) {
                if (type == typeof(void)) {
                    Emit(OpCodes.Ldnull);
                } else if (type == typeof(int)) {
                    EmitCall(typeof(ScriptingRuntimeHelpers), "Int32ToObject");
                } else if (type == typeof(bool)) {
                    var label = DefineLabel();
                    var end = DefineLabel();
                    Emit(OpCodes.Brtrue_S, label);
                    Emit(OpCodes.Ldsfld, typeof(ScriptingRuntimeHelpers).GetField("False"));
                    Emit(OpCodes.Br_S, end);
                    MarkLabel(label);
                    Emit(OpCodes.Ldsfld, typeof(ScriptingRuntimeHelpers).GetField("True"));
                    MarkLabel(end);
                } else {
                    Emit(OpCodes.Box, type);
                }
            } else if (type.IsGenericParameter) {
                EmitCall(typeof(GeneratorOps).GetMethod("BoxGeneric").MakeGenericMethod(type));
            }
        }

        #endregion

        #region Linq Conversions

        //CONFORMING
        // (plus support for None, Void conversions)
        internal void EmitConvertToType(Type typeFrom, Type typeTo, bool isChecked) {
            if (typeFrom == typeof(DynamicNull)) {
                typeFrom = typeof(object);
            }

            if (typeFrom == typeTo) {
                return;
            }

            // void -> non-void: default(T)
            if (typeFrom == typeof(void)) {
                EmitDefault(typeTo);
                return;
            }

            // non-void -> void: pop
            if (typeTo == typeof(void)) {
                Emit(OpCodes.Pop);
                return;
            }

            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)) {
                EmitCastToType(typeFrom, typeTo);
            } else if (isTypeFromNullable || isTypeToNullable) {
                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
            {
                EmitCastToType(typeFrom, typeTo);
            } else if (typeFrom.IsArray && typeTo.IsArray) {
                // See DevDiv Bugs #94657.
                EmitCastToType(typeFrom, typeTo);
            } else {
                EmitNumericConversion(typeFrom, typeTo, isChecked);
            }
        }

        //CONFORMING
        private void EmitCastToType(Type typeFrom, Type typeTo) {
            if (!typeFrom.IsValueType && typeTo.IsValueType) {
                Emit(OpCodes.Unbox_Any, typeTo);
            } else if (typeFrom.IsValueType && !typeTo.IsValueType) {
                EmitBoxing(typeFrom);
                if (typeTo != typeof(object)) {
                    Emit(OpCodes.Castclass, typeTo);
                }
            } else if (!typeFrom.IsValueType && !typeTo.IsValueType) {
                Emit(OpCodes.Castclass, typeTo);
            } else {
                throw Error.InvalidCast(typeFrom, typeTo);
            }
        }

        //CONFORMING
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private void EmitNumericConversion(Type typeFrom, Type typeTo, bool isChecked) {
            bool isFromUnsigned = TypeUtils.IsUnsignedInt(typeFrom);
            bool isFromFloatingPoint = TypeUtils.IsFloatingPoint(typeFrom);
            if (typeTo == typeof(Single)) {
                if (isFromUnsigned)
                    Emit(OpCodes.Conv_R_Un);
                Emit(OpCodes.Conv_R4);
            } else if (typeTo == typeof(Double)) {
                if (isFromUnsigned)
                    Emit(OpCodes.Conv_R_Un);
                Emit(OpCodes.Conv_R8);
            } else {
                TypeCode tc = Type.GetTypeCode(typeTo);
                if (isChecked) {
                    if (isFromUnsigned) {
                        switch (tc) {
                            case TypeCode.SByte:
                                Emit(OpCodes.Conv_Ovf_I1_Un);
                                break;
                            case TypeCode.Int16:
                                Emit(OpCodes.Conv_Ovf_I2_Un);
                                break;
                            case TypeCode.Int32:
                                Emit(OpCodes.Conv_Ovf_I4_Un);
                                break;
                            case TypeCode.Int64:
                                Emit(OpCodes.Conv_Ovf_I8_Un);
                                break;
                            case TypeCode.Byte:
                                Emit(OpCodes.Conv_Ovf_U1_Un);
                                break;
                            case TypeCode.UInt16:
                            case TypeCode.Char:
                                Emit(OpCodes.Conv_Ovf_U2_Un);
                                break;
                            case TypeCode.UInt32:
                                Emit(OpCodes.Conv_Ovf_U4_Un);
                                break;
                            case TypeCode.UInt64:
                                Emit(OpCodes.Conv_Ovf_U8_Un);
                                break;
                            default:
                                throw Error.UnhandledConvert(typeTo);
                        }
                    } else {
                        switch (tc) {
                            case TypeCode.SByte:
                                Emit(OpCodes.Conv_Ovf_I1);
                                break;
                            case TypeCode.Int16:
                                Emit(OpCodes.Conv_Ovf_I2);
                                break;
                            case TypeCode.Int32:
                                Emit(OpCodes.Conv_Ovf_I4);
                                break;
                            case TypeCode.Int64:
                                Emit(OpCodes.Conv_Ovf_I8);
                                break;
                            case TypeCode.Byte:
                                Emit(OpCodes.Conv_Ovf_U1);
                                break;
                            case TypeCode.UInt16:
                            case TypeCode.Char:
                                Emit(OpCodes.Conv_Ovf_U2);
                                break;
                            case TypeCode.UInt32:
                                Emit(OpCodes.Conv_Ovf_U4);
                                break;
                            case TypeCode.UInt64:
                                Emit(OpCodes.Conv_Ovf_U8);
                                break;
                            default:
                                throw Error.UnhandledConvert(typeTo);
                        }
                    }
                } else {
                    if (isFromUnsigned) {
                        switch (tc) {
                            case TypeCode.SByte:
                            case TypeCode.Byte:
                                Emit(OpCodes.Conv_U1);
                                break;
                            case TypeCode.Int16:
                            case TypeCode.UInt16:
                            case TypeCode.Char:
                                Emit(OpCodes.Conv_U2);
                                break;
                            case TypeCode.Int32:
                            case TypeCode.UInt32:
                                Emit(OpCodes.Conv_U4);
                                break;
                            case TypeCode.Int64:
                            case TypeCode.UInt64:
                                Emit(OpCodes.Conv_U8);
                                break;
                            default:
                                throw Error.UnhandledConvert(typeTo);
                        }
                    } else {
                        switch (tc) {
                            case TypeCode.SByte:
                            case TypeCode.Byte:
                                Emit(OpCodes.Conv_I1);
                                break;
                            case TypeCode.Int16:
                            case TypeCode.UInt16:
                            case TypeCode.Char:
                                Emit(OpCodes.Conv_I2);
                                break;
                            case TypeCode.Int32:
                            case TypeCode.UInt32:
                                Emit(OpCodes.Conv_I4);
                                break;
                            case TypeCode.Int64:
                            case TypeCode.UInt64:
                                Emit(OpCodes.Conv_I8);
                                break;
                            default:
                                throw Error.UnhandledConvert(typeTo);
                        }
                    }
                }
            }
        }

        //CONFORMING
        private void EmitNullableToNullableConversion(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 = DeclareLocal(typeFrom);
            Emit(OpCodes.Stloc, locFrom);
            locTo = DeclareLocal(typeTo);
            // test for null
            Emit(OpCodes.Ldloca, locFrom);
            EmitHasValue(typeFrom);
            labIfNull = DefineLabel();
            Emit(OpCodes.Brfalse_S, labIfNull);
            Emit(OpCodes.Ldloca, locFrom);
            EmitGetValueOrDefault(typeFrom);
            Type nnTypeFrom = TypeUtils.GetNonNullableType(typeFrom);
            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
            EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked);
            // construct result type
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
            Emit(OpCodes.Newobj, ci);
            Emit(OpCodes.Stloc, locTo);
            labEnd = DefineLabel();
            Emit(OpCodes.Br_S, labEnd);
            // if null then create a default one
            MarkLabel(labIfNull);
            Emit(OpCodes.Ldloca, locTo);
            Emit(OpCodes.Initobj, typeTo);
            MarkLabel(labEnd);
            Emit(OpCodes.Ldloc, locTo);
        }

        //CONFORMING
        private void EmitNonNullableToNullableConversion(Type typeFrom, Type typeTo, bool isChecked) {
            Debug.Assert(!TypeUtils.IsNullableType(typeFrom));
            Debug.Assert(TypeUtils.IsNullableType(typeTo));
            LocalBuilder locTo = null;
            locTo = DeclareLocal(typeTo);
            Type nnTypeTo = TypeUtils.GetNonNullableType(typeTo);
            EmitConvertToType(typeFrom, nnTypeTo, isChecked);
            ConstructorInfo ci = typeTo.GetConstructor(new Type[] { nnTypeTo });
            Emit(OpCodes.Newobj, ci);
            Emit(OpCodes.Stloc, locTo);
            Emit(OpCodes.Ldloc, locTo);
        }

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

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

        //CONFORMING
        private void EmitNullableToReferenceConversion(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.  
            Emit(OpCodes.Box, typeFrom);
        }

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

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

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

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

        #endregion

        #region Arrays

        /// <summary>
        /// Emits an array of constant values provided in the given list.
        /// The array is strongly typed.
        /// </summary>
        public void EmitArray<T>(IList<T> items) {
            ContractUtils.RequiresNotNull(items, "items");

            EmitInt(items.Count);
            Emit(OpCodes.Newarr, typeof(T));
            for (int i = 0; i < items.Count; i++) {
                Emit(OpCodes.Dup);
                EmitInt(i);
                EmitSimpleConstant(items[i]);
                EmitStoreElement(typeof(T));
            }
        }

        /// <summary>
        /// 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.
        /// </summary>
        public void EmitArray(Type elementType, int count, EmitArrayHelper emit) {
            ContractUtils.RequiresNotNull(elementType, "elementType");
            ContractUtils.RequiresNotNull(emit, "emit");
            ContractUtils.Requires(count >= 0, "count", Strings.CountCannotBeNegative);

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

                emit(i);

                EmitStoreElement(elementType);
            }
        }

        /// <summary>
        /// Emits an array construction code.  
        /// The code assumes that bounds for all dimensions
        /// are already emitted.
        /// </summary>
        public void EmitArray(Type arrayType) {
            ContractUtils.RequiresNotNull(arrayType, "arrayType");
            ContractUtils.Requires(arrayType.IsArray, "arrayType", Strings.ArrayTypeMustBeArray);

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

        #endregion

        #region Support for emitting constants

        public void EmitDecimal(decimal value) {
            if (Decimal.Truncate(value) == value) {
                if (Int32.MinValue <= value && value <= Int32.MaxValue) {
                    int intValue = Decimal.ToInt32(value);
                    EmitInt(intValue);
                    EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(int) }));
                } else if (Int64.MinValue <= value && value <= Int64.MaxValue) {
                    long longValue = Decimal.ToInt64(value);
                    EmitLong(longValue);
                    EmitNew(typeof(Decimal).GetConstructor(new Type[] { typeof(long) }));
                } else {
                    EmitDecimalBits(value);
                }
            } else {
                EmitDecimalBits(value);
            }
        }

        private void EmitDecimalBits(decimal value) {
            int[] bits = Decimal.GetBits(value);
            EmitInt(bits[0]);
            EmitInt(bits[1]);
            EmitInt(bits[2]);
            EmitBoolean((bits[3] & 0x80000000) != 0);
            EmitByte((byte)(bits[3] >> 16));
            EmitNew(typeof(decimal).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte) }));
        }

        /// <summary>
        /// Emits default(T)
        /// Semantics match C# compiler behavior
        /// </summary>
        internal void EmitDefault(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 = GetLocal(type);
                        Emit(OpCodes.Ldloca, lb);
                        Emit(OpCodes.Initobj, type);
                        Emit(OpCodes.Ldloc, lb);
                        FreeLocal(lb);
                    } else {
                        Emit(OpCodes.Ldnull);
                    }
                    break;

                case TypeCode.Empty:
                case TypeCode.String:
                case TypeCode.DBNull:
                    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:
                    Emit(OpCodes.Ldc_I4_0);
                    break;

                case TypeCode.Int64:
                case TypeCode.UInt64:
                    Emit(OpCodes.Ldc_I4_0);
                    Emit(OpCodes.Conv_I8);
                    break;

                case TypeCode.Single:
                    Emit(OpCodes.Ldc_R4, default(Single));
                    break;

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

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

                default:
                    throw Assert.Unreachable;
            }
        }

        public void EmitMissingValue(Type type) {
            LocalBuilder lb;

            switch (Type.GetTypeCode(type)) {
                default:
                case TypeCode.Object:
                    if (type == typeof(object)) {
                        // parameter of type object receives the actual Missing value
                        Emit(OpCodes.Ldsfld, typeof(Missing).GetField("Value"));
                    } else if (!type.IsValueType) {
                        // reference type
                        EmitNull();
                    } else if (type.IsSealed && !type.IsEnum) {
                        lb = DeclareLocal(type);
                        Emit(OpCodes.Ldloca, lb);
                        Emit(OpCodes.Initobj, type);
                        Emit(OpCodes.Ldloc, lb);
                    } else {
                        throw Error.NoDefaultValue();
                    }
                    break;

                case TypeCode.Empty:
                case TypeCode.DBNull:
                    EmitNull();
                    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:
                    EmitInt(0);
                    break;

                case TypeCode.Int64:
                case TypeCode.UInt64:
                    EmitLong(0);
                    break;

                case TypeCode.Single:
                    EmitSingle(default(Single));
                    break;

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

                case TypeCode.Decimal:
                    EmitFieldGet(typeof(Decimal).GetField("Zero"));
                    break;

                case TypeCode.DateTime:
                    lb = DeclareLocal(typeof(DateTime));
                    Emit(OpCodes.Ldloca, lb);
                    Emit(OpCodes.Initobj, typeof(DateTime));
                    Emit(OpCodes.Ldloc, lb);
                    break;

                case TypeCode.String:
                    EmitNull();
                    break;
            }
        }

        #endregion

        #region LocalTemps

        internal LocalBuilder GetLocal(Type type) {
            Debug.Assert(type != null);

            LocalBuilder local;
            if (_freeLocals.TryDequeue(type, out local)) {
                Debug.Assert(type == local.LocalType);
                return local;
            }

            return DeclareLocal(type);
        }

        // TODO: make "local" a ref param and null it out
        internal void FreeLocal(LocalBuilder local) {
            if (local != null) {
                _freeLocals.Enqueue(local.LocalType, local);
            }
        }

        #endregion
    }

    public static partial class GeneratorOps {
        public static object BoxGeneric<T>(T value) {
            // Duplicates functionality of ILGen.EmitBoxing at runtime for templated types
            Type type = typeof(T);
            if (type == typeof(int)) {
                return ScriptingRuntimeHelpers.Int32ToObject((int)(object)value);
            } else if (type == typeof(bool)) {
                bool bValue = (bool)(object)value;
                return bValue ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
            } else {
                return (object)value;
            }
        }
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.