File: system\reflection\emit\ilgenerator.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
// 
 
namespace System.Reflection.Emit 
{
    using System;
    using TextWriter = System.IO.TextWriter;
    using System.Diagnostics.SymbolStore;
    using System.Runtime.InteropServices;
    using System.Reflection;
    using System.Security.Permissions;
    using System.Globalization;
    using System.Diagnostics.Contracts;
    
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(_ILGenerator))]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class ILGenerator : _ILGenerator
    {
        #region Const Members
        private const int defaultSize = 16;
        private const int DefaultFixupArraySize = 8;
        private const int DefaultLabelArraySize = 4;
        private const int DefaultExceptionArraySize = 2;
        #endregion
 
        #region Internal Statics
        internal static int[] EnlargeArray(int[] incoming)
        {
            Contract.Requires(incoming != null);
            Contract.Ensures(Contract.Result<int[]>() != null);
            Contract.Ensures(Contract.Result<int[]>().Length > incoming.Length);
            int[] temp = new int [incoming.Length*2];
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }
 
        private static byte[] EnlargeArray(byte[] incoming)
        {
            byte [] temp = new byte [incoming.Length*2];
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }
 
        private static byte[] EnlargeArray(byte[] incoming, int requiredSize)
        {
            byte [] temp = new byte [requiredSize];
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }
 
        private static __FixupData[] EnlargeArray(__FixupData[] incoming)
        {
            __FixupData [] temp = new __FixupData[incoming.Length*2];
            //Does arraycopy work for value classes?
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }
 
        private static __ExceptionInfo[] EnlargeArray(__ExceptionInfo[] incoming)
        {
            __ExceptionInfo[] temp = new __ExceptionInfo[incoming.Length*2];
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }        
        #endregion
 
        #region Internal Data Members
        private  int                m_length;
        private  byte[]             m_ILStream;
 
        private  int[]              m_labelList;
        private  int                m_labelCount;
 
        private  __FixupData[]      m_fixupData;         
         
        private  int                m_fixupCount;
 
        private  int[]              m_RelocFixupList;
        private  int                m_RelocFixupCount;
 
        private  int                m_exceptionCount;
        private  int                m_currExcStackCount;
        private  __ExceptionInfo[]  m_exceptions;           //This is the list of all of the exceptions in this ILStream.
        private  __ExceptionInfo[]  m_currExcStack;         //This is the stack of exceptions which we're currently in.
 
        internal ScopeTree          m_ScopeTree;            // this variable tracks all debugging scope information
        internal LineNumberInfo     m_LineNumberInfo;       // this variable tracks all line number information
 
        internal MethodInfo         m_methodBuilder;
        internal int                m_localCount;
        internal SignatureHelper    m_localSignature;
 
        private  int                m_maxStackSize = 0;     // Maximum stack size not counting the exceptions.
 
        private  int                m_maxMidStack = 0;      // Maximum stack size for a given basic block.
        private  int                m_maxMidStackCur = 0;   // Running count of the maximum stack size for the current basic block.
 
        internal int CurrExcStackCount
        {
            get { return m_currExcStackCount; }
        }
 
        internal __ExceptionInfo[] CurrExcStack
        {
            get { return m_currExcStack; }
        }
        #endregion
 
        #region Constructor
        // package private constructor. This code path is used when client create
        // ILGenerator through MethodBuilder.
        internal ILGenerator(MethodInfo methodBuilder) : this(methodBuilder, 64)
        {
        }
 
        internal ILGenerator(MethodInfo methodBuilder, int size)
        {
            Contract.Requires(methodBuilder != null);
            Contract.Requires(methodBuilder is MethodBuilder || methodBuilder is DynamicMethod);
 
            if (size < defaultSize)
            {
                m_ILStream = new byte[defaultSize];
            }
            else
            {
                m_ILStream = new byte[size];
            }
 
            m_length = 0;
 
            m_labelCount = 0;
            m_fixupCount = 0;
            m_labelList = null;
 
            m_fixupData = null;
 
            m_exceptions = null; 
            m_exceptionCount = 0;
            m_currExcStack = null; 
            m_currExcStackCount = 0;
 
            m_RelocFixupList = null;
            m_RelocFixupCount = 0;
 
            // initialize the scope tree
            m_ScopeTree = new ScopeTree();
            m_LineNumberInfo = new LineNumberInfo();
            m_methodBuilder = methodBuilder;
 
            // initialize local signature
            m_localCount = 0;
            MethodBuilder mb = m_methodBuilder as MethodBuilder;
            if (mb == null) 
                m_localSignature = SignatureHelper.GetLocalVarSigHelper(null);
            else
                m_localSignature = SignatureHelper.GetLocalVarSigHelper(mb.GetTypeBuilder().Module);
        }
 
        #endregion
 
        #region Internal Members
        internal virtual void RecordTokenFixup()
        {
            if (m_RelocFixupList == null)
                m_RelocFixupList = new int[DefaultFixupArraySize];
            else if (m_RelocFixupList.Length <= m_RelocFixupCount)
                m_RelocFixupList = EnlargeArray(m_RelocFixupList);
 
            m_RelocFixupList[m_RelocFixupCount++] = m_length;
        }
 
        internal void InternalEmit(OpCode opcode)
        {
            if (opcode.Size != 1)
            {
                m_ILStream[m_length++] = (byte)(opcode.Value >> 8);
            }
 
            m_ILStream[m_length++] = (byte)opcode.Value;
 
            UpdateStackSize(opcode, opcode.StackChange());
 
        }
 
        internal void UpdateStackSize(OpCode opcode, int stackchange)
        {
            // Updates internal variables for keeping track of the stack size
            // requirements for the function.  stackchange specifies the amount
            // by which the stacksize needs to be updated.
 
            // Special case for the Return.  Returns pops 1 if there is a
            // non-void return value.
 
            // Update the running stacksize.  m_maxMidStack specifies the maximum
            // amount of stack required for the current basic block irrespective of
            // where you enter the block.
            m_maxMidStackCur += stackchange;
            if (m_maxMidStackCur > m_maxMidStack)
                m_maxMidStack = m_maxMidStackCur;
            else if (m_maxMidStackCur < 0)
                m_maxMidStackCur = 0;
 
            // If the current instruction signifies end of a basic, which basically
            // means an unconditional branch, add m_maxMidStack to m_maxStackSize.
            // m_maxStackSize will eventually be the sum of the stack requirements for
            // each basic block.
            if (opcode.EndsUncondJmpBlk())
            {
                m_maxStackSize += m_maxMidStack;
                m_maxMidStack = 0;
                m_maxMidStackCur = 0;
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private int GetMethodToken(MethodBase method, Type[] optionalParameterTypes, bool useMethodDef)
        {
            return ((ModuleBuilder)m_methodBuilder.Module).GetMethodTokenInternal(method, optionalParameterTypes, useMethodDef);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, 
            Type[] parameterTypes, Type[] optionalParameterTypes)
        {
            return GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, 0);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        private SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, 
            Type[] parameterTypes, Type[] optionalParameterTypes, int cGenericParameters)
        {
            return ((ModuleBuilder)m_methodBuilder.Module).GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, cGenericParameters);
        }
 
        internal byte[] BakeByteArray()
        {
            // BakeByteArray is an internal function designed to be called by MethodBuilder to do
            // all of the fixups and return a new byte array representing the byte stream with labels resolved, etc.
 
            int newSize;
            int updateAddr;
            byte []newBytes;
 
            if (m_currExcStackCount != 0)
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_UnclosedExceptionBlock"));
            }
            if (m_length == 0)
                return null;
 
            //Calculate the size of the new array.
            newSize = m_length;
 
            //Allocate space for the new array.
            newBytes = new byte[newSize];
 
            //Copy the data from the old array
            Array.Copy(m_ILStream, newBytes, newSize);
 
            //Do the fixups.
            //This involves iterating over all of the labels and
            //replacing them with their proper values.
            for (int i =0; i < m_fixupCount; i++)
            {
                updateAddr = GetLabelPos(m_fixupData[i].m_fixupLabel) - (m_fixupData[i].m_fixupPos + m_fixupData[i].m_fixupInstSize);
 
                //Handle single byte instructions
                //Throw an exception if they're trying to store a jump in a single byte instruction that doesn't fit.
                if (m_fixupData[i].m_fixupInstSize == 1)
                {
 
                    //Verify that our one-byte arg will fit into a Signed Byte.
                    if (updateAddr < SByte.MinValue || updateAddr > SByte.MaxValue)
                    {
                        throw new NotSupportedException(Environment.GetResourceString("NotSupported_IllegalOneByteBranch",m_fixupData[i].m_fixupPos, updateAddr));
                    }
 
                    //Place the one-byte arg
                    if (updateAddr < 0)
                    {
                        newBytes[m_fixupData[i].m_fixupPos] = (byte)(256 + updateAddr);
                    }
                    else
                    {
                        newBytes[m_fixupData[i].m_fixupPos] = (byte)updateAddr;
                    }
                }
                else
                {
                    //Place the four-byte arg
                    PutInteger4InArray(updateAddr, m_fixupData[i].m_fixupPos, newBytes);
                }
            }
            return newBytes;
        }
 
        internal __ExceptionInfo[] GetExceptions()
        {
            __ExceptionInfo []temp;
            if (m_currExcStackCount != 0)
            {
                throw new NotSupportedException(Environment.GetResourceString(ResId.Argument_UnclosedExceptionBlock));
            }
            
            if (m_exceptionCount == 0)
            {
                return null;
            }
            
            temp = new __ExceptionInfo[m_exceptionCount];
            Array.Copy(m_exceptions, temp, m_exceptionCount);
            SortExceptions(temp);
            return temp;
        }
 
        internal void EnsureCapacity(int size)
        {
            // Guarantees an array capable of holding at least size elements.
            if (m_length + size >= m_ILStream.Length)
            {
                if (m_length + size >= 2 * m_ILStream.Length)
                {
                    m_ILStream = EnlargeArray(m_ILStream, m_length + size);
                }
                else
                {
                    m_ILStream = EnlargeArray(m_ILStream);
                }
            }
        }
 
        internal void PutInteger4(int value)
        {
            m_length = PutInteger4InArray(value, m_length, m_ILStream);
        }
 
        private static int PutInteger4InArray(int value, int startPos, byte []array)
        {
            // Puts an Int32 onto the stream. This is an internal routine, so it does not do any error checking.
 
            array[startPos++] = (byte)value;
            array[startPos++] = (byte)(value >>8);
            array[startPos++] = (byte)(value >>16);
            array[startPos++] = (byte)(value >>24);
            return startPos;
        }
 
        private int GetLabelPos(Label lbl)
        {
            // Gets the position in the stream of a particular label.
            // Verifies that the label exists and that it has been given a value.
 
            int index = lbl.GetLabelValue();
            
            if (index < 0 || index >= m_labelCount)
                throw new ArgumentException(Environment.GetResourceString("Argument_BadLabel"));
 
            if (m_labelList[index] < 0)
                throw new ArgumentException(Environment.GetResourceString("Argument_BadLabelContent"));
 
            return m_labelList[index];
        }
 
        private void AddFixup(Label lbl, int pos, int instSize)
        {
            // Notes the label, position, and instruction size of a new fixup.  Expands
            // all of the fixup arrays as appropriate.
 
            if (m_fixupData == null)
            {
                m_fixupData = new __FixupData[DefaultFixupArraySize];
            }
            else if (m_fixupData.Length <= m_fixupCount)
            {
                m_fixupData = EnlargeArray(m_fixupData);
            }
 
            m_fixupData[m_fixupCount].m_fixupPos = pos;
            m_fixupData[m_fixupCount].m_fixupLabel = lbl;
            m_fixupData[m_fixupCount].m_fixupInstSize = instSize;
 
            m_fixupCount++;
        }
 
        internal int GetMaxStackSize()
        {
            return m_maxStackSize;
        }
 
        private static void SortExceptions(__ExceptionInfo []exceptions)
        {
            // In order to call exceptions properly we have to sort them in ascending order by their end position.
            // Just a cheap insertion sort.  We don't expect many exceptions (<10), where InsertionSort beats QuickSort.
            // If we have more exceptions than this in real life, we should consider moving to a QuickSort.
 
            int least;
            __ExceptionInfo temp;
            int length = exceptions.Length;
            for (int i =0; i < length; i++)
            {
                least = i;
                for (int j =i + 1; j < length; j++)
                {
                    if (exceptions[least].IsInner(exceptions[j]))
                    {
                        least = j;
                    }
                }
                temp = exceptions[i];
                exceptions[i] = exceptions[least];
                exceptions[least] = temp;
            }
        }
 
        internal int[] GetTokenFixups()
        {
            if (m_RelocFixupCount == 0)
            {
                Contract.Assert(m_RelocFixupList == null);
                return null;
            }
 
            int[] narrowTokens = new int[m_RelocFixupCount];
            Array.Copy(m_RelocFixupList, narrowTokens, m_RelocFixupCount);
            return narrowTokens;
        }
        #endregion
 
        #region Public Members
 
        #region Emit
        public virtual void Emit(OpCode opcode)
        {
            EnsureCapacity(3);
            InternalEmit(opcode);
 
        }
 
        public virtual void Emit(OpCode opcode, byte arg) 
        {
            EnsureCapacity(4);
            InternalEmit(opcode);
            m_ILStream[m_length++]=arg;
        }
 
        [CLSCompliant(false)]
        public void Emit(OpCode opcode, sbyte arg) 
        {
            // Puts opcode onto the stream of instructions followed by arg
 
            EnsureCapacity(4);
            InternalEmit(opcode);
            // <
            if (arg<0) {
                m_ILStream[m_length++]=(byte)(256+arg);
            } else {
                m_ILStream[m_length++]=(byte) arg;
            }
        }
 
        public virtual void Emit(OpCode opcode, short arg) 
        {
            // Puts opcode onto the stream of instructions followed by arg
            EnsureCapacity(5);
            InternalEmit(opcode);
            m_ILStream[m_length++]=(byte) arg;
            m_ILStream[m_length++]=(byte) (arg>>8);
        }
 
        public virtual void Emit(OpCode opcode, int arg) 
        {
            // Puts opcode onto the stream of instructions followed by arg
            EnsureCapacity(7);
            InternalEmit(opcode);
            PutInteger4(arg);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        public virtual void Emit(OpCode opcode, MethodInfo meth)
        {
            if (meth == null)
                throw new ArgumentNullException("meth");
            Contract.EndContractBlock();
 
            if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))
            {
                EmitCall(opcode, meth, null);
            }
            else
            {
                int stackchange = 0;
 
                // Reflection doesn't distinguish between these two concepts:
                //   1. A generic method definition: Foo`1
                //   2. A generic method definition instantiated over its own generic arguments: Foo`1<!!0>
                // In RefEmit, we always want 1 for Ld* opcodes and 2 for Call* and Newobj.
                bool useMethodDef = opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn) || opcode.Equals(OpCodes.Ldvirtftn);
                int tk = GetMethodToken(meth, null, useMethodDef);
 
                EnsureCapacity(7);
                InternalEmit(opcode);
 
                UpdateStackSize(opcode, stackchange);
                RecordTokenFixup();
                PutInteger4(tk);        
            }
        }
 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        public virtual void EmitCalli(OpCode opcode, CallingConventions callingConvention, 
            Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
        {
            int stackchange = 0;
            SignatureHelper     sig;
            if (optionalParameterTypes != null)
            {
                if ((callingConvention & CallingConventions.VarArgs) == 0)
                {
                    // Client should not supply optional parameter in default calling convention
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention"));
                }
            }
 
            ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
            sig = GetMemberRefSignature(callingConvention,
                                        returnType,
                                        parameterTypes,
                                        optionalParameterTypes);
 
            EnsureCapacity(7);
            Emit(OpCodes.Calli);
 
            // If there is a non-void return type, push one.
            if (returnType != typeof(void))
                stackchange++;
            // Pop off arguments if any.
            if (parameterTypes != null)
                stackchange -= parameterTypes.Length;
            // Pop off vararg arguments.
            if (optionalParameterTypes != null)
                stackchange -= optionalParameterTypes.Length;
            // Pop the this parameter if the method has a this parameter.
            if ((callingConvention & CallingConventions.HasThis) == CallingConventions.HasThis)
                stackchange--;
            // Pop the native function pointer.
            stackchange--;
            UpdateStackSize(OpCodes.Calli, stackchange);
 
            RecordTokenFixup();
            PutInteger4(modBuilder.GetSignatureToken(sig).Token);
        }
 
        public virtual void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
        {
            int             stackchange = 0;
            int             cParams = 0;
            int             i;
            SignatureHelper sig;
            
            ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
 
            if (parameterTypes != null)
            {
                cParams = parameterTypes.Length;
            }
            
            sig = SignatureHelper.GetMethodSigHelper(
                modBuilder, 
                unmanagedCallConv, 
                returnType);
                            
            if (parameterTypes != null)
            {
                for (i = 0; i < cParams; i++) 
                {
                    sig.AddArgument(parameterTypes[i]);
                }
            }
                                  
            // If there is a non-void return type, push one.
            if (returnType != typeof(void))
                stackchange++;
                
            // Pop off arguments if any.
            if (parameterTypes != null)
                stackchange -= cParams;
                
            // Pop the native function pointer.
            stackchange--;
            UpdateStackSize(OpCodes.Calli, stackchange);
 
            EnsureCapacity(7);
            Emit(OpCodes.Calli);
            RecordTokenFixup();
            PutInteger4(modBuilder.GetSignatureToken(sig).Token);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        public virtual void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
        {
            if (methodInfo == null)
                throw new ArgumentNullException("methodInfo");
 
            if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)))
                throw new ArgumentException(Environment.GetResourceString("Argument_NotMethodCallOpcode"), "opcode");
 
            Contract.EndContractBlock();
 
            int stackchange = 0;
            int tk = GetMethodToken(methodInfo, optionalParameterTypes, false);
 
            EnsureCapacity(7);
            InternalEmit(opcode);
 
            // Push the return value if there is one.
            if (methodInfo.ReturnType != typeof(void))
                stackchange++;
            // Pop the parameters.
            Type[] parameters = methodInfo.GetParameterTypes();
            if (parameters != null)
                stackchange -= parameters.Length;
 
            // Pop the this parameter if the method is non-static and the
            // instruction is not newobj.
            if (!(methodInfo is SymbolMethod) && methodInfo.IsStatic == false && !(opcode.Equals(OpCodes.Newobj)))
                stackchange--;
            // Pop the optional parameters off the stack.
            if (optionalParameterTypes != null)
                stackchange -= optionalParameterTypes.Length;
            UpdateStackSize(opcode, stackchange);
 
            RecordTokenFixup();
            PutInteger4(tk);
        }
 
        public virtual void Emit(OpCode opcode, SignatureHelper signature)
        {
            if (signature == null)
                throw new ArgumentNullException("signature");
            Contract.EndContractBlock();
 
            int stackchange = 0;
            ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
            SignatureToken sig = modBuilder.GetSignatureToken(signature);
 
            int tempVal = sig.Token;
 
            EnsureCapacity(7);
            InternalEmit(opcode);
 
            // The only IL instruction that has VarPop behaviour, that takes a
            // Signature token as a parameter is calli.  Pop the parameters and
            // the native function pointer.  To be conservative, do not pop the
            // this pointer since this information is not easily derived from
            // SignatureHelper.
            if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
            {
                Contract.Assert(opcode.Equals(OpCodes.Calli),
                                "Unexpected opcode encountered for StackBehaviour VarPop.");
                // Pop the arguments..
                stackchange -= signature.ArgumentCount;
                // Pop native function pointer off the stack.
                stackchange--;
                UpdateStackSize(opcode, stackchange);
            }
 
            RecordTokenFixup();
            PutInteger4(tempVal);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [System.Runtime.InteropServices.ComVisible(true)]
        public virtual void Emit(OpCode opcode, ConstructorInfo con)
        {
            if (con == null)
                throw new ArgumentNullException("con");
            Contract.EndContractBlock();
 
            int stackchange = 0;
 
            // Constructors cannot be generic so the value of UseMethodDef doesn't matter.
            int tk = GetMethodToken(con, null, true);
 
            EnsureCapacity(7);
            InternalEmit(opcode);
 
            // Make a conservative estimate by assuming a return type and no
            // this parameter.
            if (opcode.StackBehaviourPush == StackBehaviour.Varpush)
            {
                // Instruction must be one of call or callvirt.
                Contract.Assert(opcode.Equals(OpCodes.Call) ||
                                opcode.Equals(OpCodes.Callvirt),
                                "Unexpected opcode encountered for StackBehaviour of VarPush.");
                stackchange++;
            }
            if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
            {
                // Instruction must be one of call, callvirt or newobj.
                Contract.Assert(opcode.Equals(OpCodes.Call) ||
                                opcode.Equals(OpCodes.Callvirt) ||
                                opcode.Equals(OpCodes.Newobj),
                                "Unexpected opcode encountered for StackBehaviour of VarPop.");
 
                Type[] parameters = con.GetParameterTypes();
                if (parameters != null)
                    stackchange -= parameters.Length;
            }
            UpdateStackSize(opcode, stackchange);
 
            RecordTokenFixup();
            PutInteger4(tk);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        public virtual void Emit(OpCode opcode, Type cls)
        {
            // Puts opcode onto the stream and then the metadata token represented
            // by cls.  The location of cls is recorded so that the token can be
            // patched if necessary when persisting the module to a PE.
 
            int tempVal = 0;
            ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
            if (opcode == OpCodes.Ldtoken && cls != null && cls.IsGenericTypeDefinition)
            {
                // This gets the token for the generic type definition if cls is one.
                tempVal = modBuilder.GetTypeToken( cls ).Token;
            }
            else
            {
                // This gets the token for the generic type instantiated on the formal parameters
                // if cls is a generic type definition.
                tempVal = modBuilder.GetTypeTokenInternal(cls).Token;
            }
 
            EnsureCapacity(7);
            InternalEmit(opcode);
            RecordTokenFixup();
            PutInteger4(tempVal);
        }
 
        public virtual void Emit(OpCode opcode, long arg) {
            EnsureCapacity(11);
            InternalEmit(opcode);
            m_ILStream[m_length++] = (byte) arg;
            m_ILStream[m_length++] = (byte) (arg>>8);
            m_ILStream[m_length++] = (byte) (arg>>16);
            m_ILStream[m_length++] = (byte) (arg>>24);
            m_ILStream[m_length++] = (byte) (arg>>32);
            m_ILStream[m_length++] = (byte) (arg>>40);
            m_ILStream[m_length++] = (byte) (arg>>48);
            m_ILStream[m_length++] = (byte) (arg>>56);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        unsafe public virtual void Emit(OpCode opcode, float arg) {
            EnsureCapacity(7);
            InternalEmit(opcode);
            uint tempVal = *(uint*)&arg;
            m_ILStream[m_length++] = (byte) tempVal;
            m_ILStream[m_length++] = (byte) (tempVal>>8);
            m_ILStream[m_length++] = (byte) (tempVal>>16);
            m_ILStream[m_length++] = (byte) (tempVal>>24);
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        unsafe public virtual void Emit(OpCode opcode, double arg) {
            EnsureCapacity(11);
            InternalEmit(opcode);
            ulong tempVal = *(ulong*)&arg;           
            m_ILStream[m_length++] = (byte) tempVal;
            m_ILStream[m_length++] = (byte) (tempVal>>8);
            m_ILStream[m_length++] = (byte) (tempVal>>16);
            m_ILStream[m_length++] = (byte) (tempVal>>24);
            m_ILStream[m_length++] = (byte) (tempVal>>32);
            m_ILStream[m_length++] = (byte) (tempVal>>40);
            m_ILStream[m_length++] = (byte) (tempVal>>48);
            m_ILStream[m_length++] = (byte) (tempVal>>56);
        }
 
        public virtual void Emit(OpCode opcode, Label label) 
        {
            // Puts opcode onto the stream and leaves space to include label
            // when fixups are done.  Labels are created using ILGenerator.DefineLabel and
            // their location within the stream is fixed by using ILGenerator.MarkLabel.
            // If a single-byte instruction (designated by the _S suffix in OpCodes.cs) is used,
            // the label can represent a jump of at most 127 bytes along the stream.
            //
            // opcode must represent a branch instruction (although we don't explicitly
            // verify this).  Since branches are relative instructions, label will be replaced with the
            // correct offset to branch during the fixup process.
            
            int tempVal = label.GetLabelValue();
            EnsureCapacity(7);
 
             
            InternalEmit(opcode);
            if (OpCodes.TakesSingleByteArgument(opcode)) {
                AddFixup(label, m_length, 1);
                m_length++;
            } else {
                AddFixup(label, m_length, 4);
                m_length+=4;
            }
        }
 
        public virtual void Emit(OpCode opcode, Label[] labels)
        {
            if (labels == null)
                throw new ArgumentNullException("labels");
            Contract.EndContractBlock();
 
            // Emitting a switch table
 
            int i;
            int remaining;                  // number of bytes remaining for this switch instruction to be substracted
            // for computing the offset
 
            int count = labels.Length;
 
            EnsureCapacity( count * 4 + 7 );
            InternalEmit(opcode);
            PutInteger4(count);
            for ( remaining = count * 4, i = 0; remaining > 0; remaining -= 4, i++ ) {
                AddFixup( labels[i], m_length, remaining );
                m_length += 4;
            }
        }
 
        public virtual void Emit(OpCode opcode, FieldInfo field)
        {
            ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
            int tempVal = modBuilder.GetFieldToken( field ).Token;
            EnsureCapacity(7);
            InternalEmit(opcode);
            RecordTokenFixup();
            PutInteger4(tempVal);
        }
 
        public virtual void Emit(OpCode opcode, String str) 
        {
            // Puts the opcode onto the IL stream followed by the metadata token
            // represented by str.  The location of str is recorded for future
            // fixups if the module is persisted to a PE.
 
            ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
            int tempVal = modBuilder.GetStringConstant(str).Token;
            EnsureCapacity(7);
            InternalEmit(opcode);
            PutInteger4(tempVal);
        }
 
        public virtual void Emit(OpCode opcode, LocalBuilder local)
        {
            // Puts the opcode onto the IL stream followed by the information for local variable local.
 
            if (local == null)
            {
                throw new ArgumentNullException("local");
            }
            Contract.EndContractBlock();
            int tempVal = local.GetLocalIndex();
            if (local.GetMethodBuilder() != m_methodBuilder)
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchedMethodForLocal"), "local");
            }
            // If the instruction is a ldloc, ldloca a stloc, morph it to the optimal form.
            if (opcode.Equals(OpCodes.Ldloc))
            {
                switch(tempVal)
                {
                    case 0:
                        opcode = OpCodes.Ldloc_0;
                        break;
                    case 1:
                        opcode = OpCodes.Ldloc_1;
                        break;
                    case 2:
                        opcode = OpCodes.Ldloc_2;
                        break;
                    case 3:
                        opcode = OpCodes.Ldloc_3;
                        break;
                    default:
                        if (tempVal <= 255)
                            opcode = OpCodes.Ldloc_S;
                        break;
                }
            }
            else if (opcode.Equals(OpCodes.Stloc))
            {
                switch(tempVal)
                {
                    case 0:
                        opcode = OpCodes.Stloc_0;
                        break;
                    case 1:
                        opcode = OpCodes.Stloc_1;
                        break;
                    case 2:
                        opcode = OpCodes.Stloc_2;
                        break;
                    case 3:
                        opcode = OpCodes.Stloc_3;
                        break;
                    default:
                        if (tempVal <= 255)
                            opcode = OpCodes.Stloc_S;
                        break;
                }
            }
            else if (opcode.Equals(OpCodes.Ldloca))
            {
                if (tempVal <= 255)
                    opcode = OpCodes.Ldloca_S;
            }
 
            EnsureCapacity(7);
            InternalEmit(opcode);
             
            if (opcode.OperandType == OperandType.InlineNone)
                return;
            else if (!OpCodes.TakesSingleByteArgument(opcode))
            {
                m_ILStream[m_length++]=(byte) tempVal;
                m_ILStream[m_length++]=(byte) (tempVal>>8);
            }
            else
            {
                //Handle stloc_1, ldloc_1
                if (tempVal > Byte.MaxValue)
                {
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadInstructionOrIndexOutOfBound"));
                }
                m_ILStream[m_length++]=(byte)tempVal;
            }
        }
        #endregion
 
        #region Exceptions
        public virtual Label BeginExceptionBlock() 
        {
            // Begin an Exception block.  Creating an Exception block records some information,
            // but does not actually emit any IL onto the stream.  Exceptions should be created and
            // marked in the following form:
            //
            // Emit Some IL
            // BeginExceptionBlock
            // Emit the IL which should appear within the "try" block
            // BeginCatchBlock
            // Emit the IL which should appear within the "catch" block
            // Optional: BeginCatchBlock (this can be repeated an arbitrary number of times
            // EndExceptionBlock
 
            // Delay init
            if (m_exceptions == null)
            {
                m_exceptions = new __ExceptionInfo[DefaultExceptionArraySize];
            }
 
            if (m_currExcStack == null)
            {
                m_currExcStack = new __ExceptionInfo[DefaultExceptionArraySize];
            }
 
            if (m_exceptionCount>=m_exceptions.Length) {
                m_exceptions=EnlargeArray(m_exceptions);
            }
 
            if (m_currExcStackCount>=m_currExcStack.Length) {
                m_currExcStack = EnlargeArray(m_currExcStack);
            }
 
            Label endLabel = DefineLabel();
            __ExceptionInfo exceptionInfo = new __ExceptionInfo(m_length, endLabel);
 
            // add the exception to the tracking list
            m_exceptions[m_exceptionCount++] = exceptionInfo;
 
            // Make this exception the current active exception
            m_currExcStack[m_currExcStackCount++] = exceptionInfo;
            return endLabel;
        }
 
        public virtual void EndExceptionBlock() {
            if (m_currExcStackCount==0) {
                throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
            }
 
           // Pop the current exception block
            __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
            m_currExcStack[m_currExcStackCount-1] = null;
            m_currExcStackCount--;
 
            Label endLabel = current.GetEndLabel();
            int state = current.GetCurrentState();
 
            if (state == __ExceptionInfo.State_Filter ||
                state == __ExceptionInfo.State_Try)
            {
                 
                 
                throw new InvalidOperationException(Environment.GetResourceString("Argument_BadExceptionCodeGen"));
            }
 
            if (state == __ExceptionInfo.State_Catch) {
                this.Emit(OpCodes.Leave, endLabel);
            } else if (state == __ExceptionInfo.State_Finally || state == __ExceptionInfo.State_Fault) {
                this.Emit(OpCodes.Endfinally);
            }
 
            //Check if we've alredy set this label.
            //The only reason why we might have set this is if we have a finally block.
            if (m_labelList[endLabel.GetLabelValue()]==-1) {
                MarkLabel(endLabel);
            } else {
                MarkLabel(current.GetFinallyEndLabel());
            }
 
            current.Done(m_length);
        }
 
        public virtual void BeginExceptFilterBlock() 
        {
            // Begins a eception filter block.  Emits a branch instruction to the end of the current exception block.
 
            if (m_currExcStackCount == 0)
                throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
 
            __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
 
            Label endLabel = current.GetEndLabel();
            this.Emit(OpCodes.Leave, endLabel);
 
            current.MarkFilterAddr(m_length);
        }
 
        public virtual void BeginCatchBlock(Type exceptionType) 
        {
            // Begins a catch block.  Emits a branch instruction to the end of the current exception block.
 
            if (m_currExcStackCount==0) {
                throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
            }
            __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
 
            if (current.GetCurrentState() == __ExceptionInfo.State_Filter) {
                if (exceptionType != null) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_ShouldNotSpecifyExceptionType"));
                }
 
                this.Emit(OpCodes.Endfilter);
            } else {
                // execute this branch if previous clause is Catch or Fault
                if (exceptionType==null) {
                    throw new ArgumentNullException("exceptionType");
                }
 
                Label endLabel = current.GetEndLabel();
                this.Emit(OpCodes.Leave, endLabel);
 
            }
 
            current.MarkCatchAddr(m_length, exceptionType);
        }
 
        public virtual void BeginFaultBlock()
        {
            if (m_currExcStackCount==0) {
                throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
            }
            __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
 
            // emit the leave for the clause before this one.
            Label endLabel = current.GetEndLabel();
            this.Emit(OpCodes.Leave, endLabel);
 
            current.MarkFaultAddr(m_length);
        }
 
        public virtual void BeginFinallyBlock() 
        {
            if (m_currExcStackCount==0) {
                throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
            }
            __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
            int         state = current.GetCurrentState();
            Label       endLabel = current.GetEndLabel();
            int         catchEndAddr = 0;
            if (state != __ExceptionInfo.State_Try)
            {
                // generate leave for any preceeding catch clause
                this.Emit(OpCodes.Leave, endLabel);                
                catchEndAddr = m_length;
            }
            
            MarkLabel(endLabel);
 
 
            Label finallyEndLabel = this.DefineLabel();
            current.SetFinallyEndLabel(finallyEndLabel);
            
            // generate leave for try clause                                                  
            this.Emit(OpCodes.Leave, finallyEndLabel);
            if (catchEndAddr == 0)
                catchEndAddr = m_length;
            current.MarkFinallyAddr(m_length, catchEndAddr);
        }
 
        #endregion
 
        #region Labels
        public virtual Label DefineLabel() 
        {
            // Declares a new Label.  This is just a token and does not yet represent any particular location
            // within the stream.  In order to set the position of the label within the stream, you must call
            // Mark Label.
 
            // Delay init the lable array in case we dont use it
            if (m_labelList == null){
                m_labelList = new int[DefaultLabelArraySize];
            }
 
            if (m_labelCount>=m_labelList.Length) {
                m_labelList = EnlargeArray(m_labelList);
            }
            m_labelList[m_labelCount]=-1;
            return new Label(m_labelCount++);
        }
 
        public virtual void MarkLabel(Label loc) 
        {
            // Defines a label by setting the position where that label is found within the stream.
            // Does not allow a label to be defined more than once.
 
            int labelIndex = loc.GetLabelValue();
 
            //This should never happen.
            if (labelIndex<0 || labelIndex>=m_labelList.Length) {
                throw new ArgumentException (Environment.GetResourceString("Argument_InvalidLabel"));
            }
 
            if (m_labelList[labelIndex]!=-1) {
                throw new ArgumentException (Environment.GetResourceString("Argument_RedefinedLabel"));
            }
 
            m_labelList[labelIndex]=m_length;
        }
 
        #endregion
 
        #region IL Macros
        public virtual void ThrowException(Type excType)
        {
            // Emits the il to throw an exception
 
            if (excType==null) {
                throw new ArgumentNullException("excType");
            }
 
            if (!excType.IsSubclassOf(typeof(Exception)) && excType!=typeof(Exception)) {
                throw new ArgumentException(Environment.GetResourceString("Argument_NotExceptionType"));
            }
            Contract.EndContractBlock();
            ConstructorInfo con = excType.GetConstructor(Type.EmptyTypes);
            if (con==null) {
                throw new ArgumentException(Environment.GetResourceString("Argument_MissingDefaultConstructor"));
            }
            this.Emit(OpCodes.Newobj, con);
            this.Emit(OpCodes.Throw);
        }
 
        public virtual void EmitWriteLine(String value)
        {
            // Emits the IL to call Console.WriteLine with a string.
 
            Emit(OpCodes.Ldstr, value);
            Type[] parameterTypes = new Type[1];
            parameterTypes[0] = typeof(String);
            MethodInfo mi = typeof(Console).GetMethod("WriteLine", parameterTypes);
            Emit(OpCodes.Call, mi);
        }
 
        public virtual void EmitWriteLine(LocalBuilder localBuilder) 
        {
            // Emits the IL necessary to call WriteLine with lcl.  It is
            // an error to call EmitWriteLine with a lcl which is not of
            // one of the types for which Console.WriteLine implements overloads. (e.g.
            // we do *not* call ToString on the locals.
 
            Object          cls;
            if (m_methodBuilder==null)
            {
                throw new ArgumentException(Environment.GetResourceString("InvalidOperation_BadILGeneratorUsage"));
            }
 
            MethodInfo prop = typeof(Console).GetMethod("get_Out");
            Emit(OpCodes.Call, prop);
            Emit(OpCodes.Ldloc, localBuilder);
            Type[] parameterTypes = new Type[1];
            cls = localBuilder.LocalType;
            if (cls is TypeBuilder || cls is EnumBuilder) {
                throw new ArgumentException(Environment.GetResourceString("NotSupported_OutputStreamUsingTypeBuilder"));
            }
            parameterTypes[0] = (Type)cls;
            MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
             if (mi==null) {
                throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "localBuilder");
            }
 
            Emit(OpCodes.Callvirt, mi);
        }
 
        public virtual void EmitWriteLine(FieldInfo fld)
        {
            // Emits the IL necessary to call WriteLine with fld.  It is
            // an error to call EmitWriteLine with a fld which is not of
            // one of the types for which Console.WriteLine implements overloads. (e.g.
            // we do *not* call ToString on the fields.
 
            Object cls;
 
            if (fld == null)
            {
                throw new ArgumentNullException("fld");
            }
            Contract.EndContractBlock();
            
            MethodInfo prop = typeof(Console).GetMethod("get_Out");
            Emit(OpCodes.Call, prop);
 
            if ((fld.Attributes & FieldAttributes.Static)!=0) {
                Emit(OpCodes.Ldsfld, fld);
            } else {
                Emit(OpCodes.Ldarg, (short)0); //Load the this ref.
                Emit(OpCodes.Ldfld, fld);
            }
            Type[] parameterTypes = new Type[1];
            cls = fld.FieldType;
            if (cls is TypeBuilder || cls is EnumBuilder) {
                throw new NotSupportedException(Environment.GetResourceString("NotSupported_OutputStreamUsingTypeBuilder"));
            }
            parameterTypes[0] = (Type)cls;
            MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
            if (mi==null) {
                throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "fld");
            }
            Emit(OpCodes.Callvirt, mi);
        }
 
        #endregion
 
        #region Debug API
        public virtual LocalBuilder DeclareLocal(Type localType)
        {
            return DeclareLocal(localType, false);
        }
 
        public virtual LocalBuilder DeclareLocal(Type localType, bool pinned)
        {
            // Declare a local of type "local". The current active lexical scope
            // will be the scope that local will live.
 
            LocalBuilder    localBuilder;
 
            MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
            if (methodBuilder == null) 
                throw new NotSupportedException();
 
            if (methodBuilder.IsTypeCreated())
            {
                // cannot change method after its containing type has been created
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TypeHasBeenCreated"));
            }
 
            if (localType==null) {
                throw new ArgumentNullException("localType");
            }
 
            if (methodBuilder.m_bIsBaked) {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBaked"));
            }
 
            // add the localType to local signature
            m_localSignature.AddArgument(localType, pinned);
 
            localBuilder = new LocalBuilder(m_localCount, localType, methodBuilder, pinned);
            m_localCount++;
            return localBuilder;
        }
 
        public virtual void UsingNamespace(String usingNamespace)
        {
            // Specifying the namespace to be used in evaluating locals and watches
            // for the current active lexical scope.
 
            if (usingNamespace == null)
                throw new ArgumentNullException("usingNamespace");
 
            if (usingNamespace.Length == 0)
                throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "usingNamespace");
            Contract.EndContractBlock();
 
            int index;
            MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
            if (methodBuilder == null) 
                throw new NotSupportedException();
 
            index = methodBuilder.GetILGenerator().m_ScopeTree.GetCurrentActiveScopeIndex();
            if (index == -1)
            {
                methodBuilder.m_localSymInfo.AddUsingNamespace(usingNamespace);
            }
            else
            {
                m_ScopeTree.AddUsingNamespaceToCurrentScope(usingNamespace);
            }
        }
 
        public virtual void MarkSequencePoint(
            ISymbolDocumentWriter document,
            int startLine,       // line number is 1 based
            int startColumn,     // column is 0 based
            int endLine,         // line number is 1 based
            int endColumn)       // column is 0 based
        {
            if (startLine == 0 || startLine < 0 || endLine == 0 || endLine < 0)
            {
                throw new ArgumentOutOfRangeException("startLine");
            }
            Contract.EndContractBlock();
            m_LineNumberInfo.AddLineNumberInfo(document, m_length, startLine, startColumn, endLine, endColumn);
        }
 
        public virtual void BeginScope()
        {
            m_ScopeTree.AddScopeInfo(ScopeAction.Open, m_length);
        }
 
        public virtual void EndScope()
        {
            m_ScopeTree.AddScopeInfo(ScopeAction.Close, m_length);
        }
 
        public virtual int ILOffset
        {
            get
            {
                return m_length;
            }
        }
 
        #endregion
 
        #endregion
 
#if !FEATURE_CORECLR
        void _ILGenerator.GetTypeInfoCount(out uint pcTInfo)
        {
            throw new NotImplementedException();
        }
 
        void _ILGenerator.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
        {
            throw new NotImplementedException();
        }
 
        void _ILGenerator.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
        {
            throw new NotImplementedException();
        }
 
        void _ILGenerator.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
        {
            throw new NotImplementedException();
        }
#endif
    }
 
    internal struct __FixupData
    {
        internal Label m_fixupLabel;
        internal int m_fixupPos;
         
        internal int m_fixupInstSize;
    }
 
    internal sealed class __ExceptionInfo {
 
        internal const int None             = 0x0000;  //COR_ILEXCEPTION_CLAUSE_NONE
        internal const int Filter           = 0x0001;  //COR_ILEXCEPTION_CLAUSE_FILTER
        internal const int Finally          = 0x0002;  //COR_ILEXCEPTION_CLAUSE_FINALLY
        internal const int Fault            = 0x0004;  //COR_ILEXCEPTION_CLAUSE_FAULT
        internal const int PreserveStack    = 0x0004;  //COR_ILEXCEPTION_CLAUSE_PRESERVESTACK
 
        internal const int State_Try = 0;
        internal const int State_Filter =1;
        internal const int State_Catch = 2;
        internal const int State_Finally = 3;
        internal const int State_Fault = 4;
        internal const int State_Done = 5;
 
        internal int m_startAddr;
        internal int []m_filterAddr;
        internal int []m_catchAddr;
        internal int []m_catchEndAddr;
        internal int []m_type;
        internal Type []m_catchClass;
        internal Label m_endLabel;
        internal Label m_finallyEndLabel;
        internal int m_endAddr;
        internal int m_endFinally;
        internal int m_currentCatch;
 
        int m_currentState;
 
 
        //This will never get called.  The values exist merely to keep the
        //compiler happy.
        private __ExceptionInfo() {
            m_startAddr = 0;
            m_filterAddr = null;
            m_catchAddr = null;
            m_catchEndAddr = null;
            m_endAddr = 0;
            m_currentCatch = 0;
            m_type = null;
            m_endFinally = -1;
            m_currentState = State_Try;
        }
 
        internal __ExceptionInfo(int startAddr, Label endLabel) {
            m_startAddr=startAddr;
            m_endAddr=-1;
            m_filterAddr=new int[4];
            m_catchAddr=new int[4];
            m_catchEndAddr=new int[4];
            m_catchClass=new Type[4];
            m_currentCatch=0;
            m_endLabel=endLabel;
            m_type=new int[4];
            m_endFinally=-1;
            m_currentState = State_Try;
        }
 
        private static Type[] EnlargeArray(Type[] incoming)
        {
            Type[] temp = new Type[incoming.Length * 2];
            Array.Copy(incoming, temp, incoming.Length);
            return temp;
        }
 
        private void MarkHelper(
            int         catchorfilterAddr,      // the starting address of a clause
            int         catchEndAddr,           // the end address of a previous catch clause. Only use when finally is following a catch
            Type        catchClass,             // catch exception type
            int         type)                   // kind of clause
        {
            if (m_currentCatch>=m_catchAddr.Length) {
                m_filterAddr=ILGenerator.EnlargeArray(m_filterAddr);
                m_catchAddr=ILGenerator.EnlargeArray(m_catchAddr);
                m_catchEndAddr=ILGenerator.EnlargeArray(m_catchEndAddr);
                m_catchClass=__ExceptionInfo.EnlargeArray(m_catchClass);
                m_type = ILGenerator.EnlargeArray(m_type);
            }
            if (type == Filter)
            {
                m_type[m_currentCatch]=type;
                m_filterAddr[m_currentCatch] = catchorfilterAddr;
                m_catchAddr[m_currentCatch] = -1;
                if (m_currentCatch > 0)
                {
                    Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
                    m_catchEndAddr[m_currentCatch-1] = catchorfilterAddr;
                }
            }
            else
            {
                // catch or Fault clause
                m_catchClass[m_currentCatch]=catchClass;
                if (m_type[m_currentCatch] != Filter)
                {
                    m_type[m_currentCatch]=type;
                }
                m_catchAddr[m_currentCatch]=catchorfilterAddr;
                if (m_currentCatch > 0)
                {
                        if (m_type[m_currentCatch] != Filter)
                        {
                            Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
                            m_catchEndAddr[m_currentCatch-1] = catchEndAddr;
                        }
                }
                m_catchEndAddr[m_currentCatch]=-1;  
                m_currentCatch++;
            }
 
            if (m_endAddr==-1)
            {
                m_endAddr=catchorfilterAddr;
            }
        }
 
        internal void MarkFilterAddr(int filterAddr)
        {
            m_currentState = State_Filter;
            MarkHelper(filterAddr, filterAddr, null, Filter);
        }
 
        internal void MarkFaultAddr(int faultAddr)
        {
            m_currentState = State_Fault;
            MarkHelper(faultAddr, faultAddr, null, Fault);
        }
 
        internal void MarkCatchAddr(int catchAddr, Type catchException) {
            m_currentState = State_Catch;
            MarkHelper(catchAddr, catchAddr, catchException, None);
        }
 
        internal void MarkFinallyAddr(int finallyAddr, int endCatchAddr) {
            if (m_endFinally!=-1) {
                throw new ArgumentException(Environment.GetResourceString("Argument_TooManyFinallyClause"));
            } else {
                m_currentState = State_Finally;
                m_endFinally=finallyAddr;
            }
            MarkHelper(finallyAddr, endCatchAddr, null, Finally);
        }
 
        internal void Done(int endAddr) {
            Contract.Assert(m_currentCatch > 0,"m_currentCatch > 0");
            Contract.Assert(m_catchAddr[m_currentCatch-1] > 0,"m_catchAddr[m_currentCatch-1] > 0");
            Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
            m_catchEndAddr[m_currentCatch-1] = endAddr;
            m_currentState = State_Done;
        }
 
        internal int GetStartAddress() {
            return m_startAddr;
        }
 
        internal int GetEndAddress() {
            return m_endAddr;
        }
 
        internal int GetFinallyEndAddress() {
            return m_endFinally;
        }
 
        internal Label GetEndLabel() {
            return m_endLabel;
        }
 
        internal int [] GetFilterAddresses() {
            return m_filterAddr;
        }
 
        internal int [] GetCatchAddresses() {
            return m_catchAddr;
        }
 
        internal int [] GetCatchEndAddresses() {
            return m_catchEndAddr;
        }
 
        internal Type [] GetCatchClass() {
            return m_catchClass;
        }
 
        internal int GetNumberOfCatches() {
            return m_currentCatch;
        }
 
        internal int[] GetExceptionTypes() {
            return m_type;
        }
 
        internal void SetFinallyEndLabel(Label lbl) {
            m_finallyEndLabel=lbl;
        }
 
        internal Label GetFinallyEndLabel() {
            return m_finallyEndLabel;
        }
 
        // Specifies whether exc is an inner exception for "this".  The way
        // its determined is by comparing the end address for the last catch
        // clause for both exceptions.  If they're the same, the start address
        // for the exception is compared.
        // WARNING: This is not a generic function to determine the innerness
        // of an exception.  This is somewhat of a mis-nomer.  This gives a
        // random result for cases where the two exceptions being compared do
        // not having a nesting relation. 
        internal bool IsInner(__ExceptionInfo exc) {
            Contract.Requires(exc != null);
            Contract.Assert(m_currentCatch > 0,"m_currentCatch > 0");
            Contract.Assert(exc.m_currentCatch > 0,"exc.m_currentCatch > 0");
 
            int exclast = exc.m_currentCatch - 1;
            int last = m_currentCatch - 1;
 
            if (exc.m_catchEndAddr[exclast]  < m_catchEndAddr[last])
                return true;
            else if (exc.m_catchEndAddr[exclast] == m_catchEndAddr[last])
            {
                Contract.Assert(exc.GetEndAddress() != GetEndAddress(),
                                "exc.GetEndAddress() != GetEndAddress()");
                if (exc.GetEndAddress() > GetEndAddress())
                    return true;
            }
            return false;
        }
 
        // 0 indicates in a try block
        // 1 indicates in a filter block
        // 2 indicates in a catch block
        // 3 indicates in a finally block
        // 4 indicates Done
        internal int GetCurrentState() {
            return m_currentState;
        }
    }
 
 
    /***************************
    *
    * Scope Tree is a class that track the scope structure within a method body
    * It keeps track two parallel array. m_ScopeAction keeps track the action. It can be
    * OpenScope or CloseScope. m_iOffset records the offset where the action
    * takes place.
    *
    ***************************/
    [Serializable]
    enum ScopeAction
    {
        Open        = 0x0,
        Close       = 0x1,
    }
 
    internal sealed class ScopeTree
    {
        internal ScopeTree()
        {
            // initialize data variables
            m_iOpenScopeCount = 0;
            m_iCount = 0;
        }
 
        /***************************
        *
        * Find the current active lexcial scope. For example, if we have
        * "Open Open Open Close",
        * we will return 1 as the second BeginScope is currently active.
        *
        ***************************/
        internal int GetCurrentActiveScopeIndex()
        {
            int         cClose = 0;
            int         i = m_iCount - 1;
 
            if (m_iCount == 0)
            {
                return -1;
            }
            for (; cClose > 0 || m_ScopeActions[i] == ScopeAction.Close; i--)
            {
                if (m_ScopeActions[i] == ScopeAction.Open)
                {
                    cClose--;
                }
                else
                    cClose++;
            }
 
            return i;
        }
 
        internal void AddLocalSymInfoToCurrentScope(
            String          strName,
            byte[]          signature,
            int             slot,
            int             startOffset,
            int             endOffset)
        {
            int         i = GetCurrentActiveScopeIndex();
            if (m_localSymInfos[i] == null)
            {
                m_localSymInfos[i] = new LocalSymInfo();
            }
            m_localSymInfos[i].AddLocalSymInfo(strName, signature, slot, startOffset, endOffset);
        }
 
        internal void AddUsingNamespaceToCurrentScope(
            String          strNamespace)
        {
            int         i = GetCurrentActiveScopeIndex();
            if (m_localSymInfos[i] == null)
            {
                m_localSymInfos[i] = new LocalSymInfo();
            }
            m_localSymInfos[i].AddUsingNamespace(strNamespace);
        }
 
        internal void AddScopeInfo(ScopeAction sa, int iOffset)
        {
            if (sa == ScopeAction.Close && m_iOpenScopeCount <=0)
            {
                throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchingSymScope"));
            }
            Contract.EndContractBlock();
 
            // make sure that arrays are large enough to hold addition info
            EnsureCapacity();             
             
             
            m_ScopeActions[m_iCount] = sa;
            m_iOffsets[m_iCount] = iOffset;
            m_localSymInfos[m_iCount] = null;
            checked { m_iCount++; }
            if (sa == ScopeAction.Open)
            {
                m_iOpenScopeCount++;
            }
            else
                m_iOpenScopeCount--;
 
        }
 
        /**************************
        *
        * Helper to ensure arrays are large enough
        *
        **************************/
        internal void EnsureCapacity()
        {
            if (m_iCount == 0)
            {
                // First time. Allocate the arrays.
                m_iOffsets = new int[InitialSize];
                m_ScopeActions = new ScopeAction[InitialSize];
                m_localSymInfos = new LocalSymInfo[InitialSize];
            }
            else if (m_iCount == m_iOffsets.Length)
            {
                // the arrays are full. Enlarge the arrays
                // It would probably be simpler to just use Lists here.
                int newSize = checked(m_iCount * 2);
                int[] temp = new int[newSize];
                Array.Copy(m_iOffsets, temp, m_iCount);
                m_iOffsets = temp;
 
                ScopeAction[] tempSA = new ScopeAction[newSize];
                Array.Copy(m_ScopeActions, tempSA, m_iCount);
                m_ScopeActions = tempSA;
 
                LocalSymInfo[] tempLSI = new LocalSymInfo[newSize];
                Array.Copy(m_localSymInfos, tempLSI, m_iCount);
                m_localSymInfos = tempLSI;
            }
        }
 
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        internal void EmitScopeTree(ISymbolWriter symWriter)
        {
            int         i;
            for (i = 0; i < m_iCount; i++)
            {
                if (m_ScopeActions[i] == ScopeAction.Open)
                {
                    symWriter.OpenScope(m_iOffsets[i]);
                }
                else
                {
                    symWriter.CloseScope(m_iOffsets[i]);
                }
                if (m_localSymInfos[i] != null)
                {
                    m_localSymInfos[i].EmitLocalSymInfo(symWriter);
                }
            }
        }
 
        internal int[]          m_iOffsets;                 // array of offsets
        internal ScopeAction[]  m_ScopeActions;             // array of scope actions
        internal int            m_iCount;                   // how many entries in the arrays are occupied
        internal int            m_iOpenScopeCount;          // keep track how many scopes are open
        internal const int      InitialSize = 16;
        internal LocalSymInfo[] m_localSymInfos;            // keep track debugging local information
    }
 
 
    /***************************
    *
    * This class tracks the line number info
    *
    ***************************/
    internal sealed class LineNumberInfo
    {
        internal LineNumberInfo()
        {
            // initialize data variables
            m_DocumentCount = 0;
            m_iLastFound = 0;
        }
 
        internal void AddLineNumberInfo(
            ISymbolDocumentWriter document,
            int             iOffset,
            int             iStartLine,
            int             iStartColumn,
            int             iEndLine,
            int             iEndColumn)
        {
            int         i;
            
            // make sure that arrays are large enough to hold addition info
            i = FindDocument(document);
            
            Contract.Assert(i < m_DocumentCount, "Bad document look up!");
            m_Documents[i].AddLineNumberInfo(document, iOffset, iStartLine, iStartColumn, iEndLine, iEndColumn);
        }
        
        // Find a REDocument representing document. If we cannot find one, we will add a new entry into
        // the REDocument array.
        private int FindDocument(ISymbolDocumentWriter document)
        {
            int         i;
            
            // This is an optimization. The chance that the previous line is coming from the same
            // document is very high.
            if (m_iLastFound < m_DocumentCount && m_Documents[m_iLastFound].m_document == document)
                return m_iLastFound;
                
            for (i = 0; i < m_DocumentCount; i++)
            {
                if (m_Documents[i].m_document == document)
                {
                    m_iLastFound = i;
                    return m_iLastFound;
                }
            }
            
            // cannot find an existing document so add one to the array                                       
            EnsureCapacity();
            m_iLastFound = m_DocumentCount;
            m_Documents[m_iLastFound] = new REDocument(document);
            checked { m_DocumentCount++; }
            return m_iLastFound;
        }
 
        /**************************
        *
        * Helper to ensure arrays are large enough
        *
        **************************/
        private void EnsureCapacity()
        {
            if (m_DocumentCount == 0)
            {
                // First time. Allocate the arrays.
                m_Documents = new REDocument[InitialSize];
            }
            else if (m_DocumentCount == m_Documents.Length)
            {
                // the arrays are full. Enlarge the arrays
                REDocument[] temp = new REDocument [m_DocumentCount * 2];
                Array.Copy(m_Documents, temp, m_DocumentCount);
                m_Documents = temp;
            }
        }
 
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        internal void EmitLineNumberInfo(ISymbolWriter symWriter)
        {
            for (int i = 0; i < m_DocumentCount; i++)
                m_Documents[i].EmitLineNumberInfo(symWriter);
        }
 
        private int          m_DocumentCount;         // how many documents that we have right now
        private REDocument[] m_Documents;             // array of documents
        private const int    InitialSize = 16;
        private int          m_iLastFound;
    }
 
 
    /***************************
    *
    * This class tracks the line number info
    *
    ***************************/
    internal sealed class REDocument
    {
        internal REDocument(ISymbolDocumentWriter document)
        {
            // initialize data variables
            m_iLineNumberCount = 0;
            m_document = document;
        }
 
        internal void AddLineNumberInfo(
            ISymbolDocumentWriter document,
            int             iOffset,
            int             iStartLine,
            int             iStartColumn,
            int             iEndLine,
            int             iEndColumn)
        {
            Contract.Assert(document == m_document, "Bad document look up!");
            
            // make sure that arrays are large enough to hold addition info
            EnsureCapacity();
            
            m_iOffsets[m_iLineNumberCount] = iOffset;
            m_iLines[m_iLineNumberCount] = iStartLine;
            m_iColumns[m_iLineNumberCount] = iStartColumn;
            m_iEndLines[m_iLineNumberCount] = iEndLine;
            m_iEndColumns[m_iLineNumberCount] = iEndColumn;
            checked { m_iLineNumberCount++; }
        }
 
        /**************************
        *
        * Helper to ensure arrays are large enough
        *
        **************************/
        private void EnsureCapacity()
        {
            if (m_iLineNumberCount == 0)
            {
                // First time. Allocate the arrays.
                m_iOffsets = new int[InitialSize];
                m_iLines = new int[InitialSize];
                m_iColumns = new int[InitialSize];
                m_iEndLines = new int[InitialSize];
                m_iEndColumns = new int[InitialSize];
            }
            else if (m_iLineNumberCount == m_iOffsets.Length)
            {            
                // the arrays are full. Enlarge the arrays
                // It would probably be simpler to just use Lists here
                int newSize = checked(m_iLineNumberCount * 2);
                int[] temp = new int [newSize];
                Array.Copy(m_iOffsets, temp, m_iLineNumberCount);
                m_iOffsets = temp;
 
                temp = new int [newSize];
                Array.Copy(m_iLines, temp, m_iLineNumberCount);
                m_iLines = temp;
 
                temp = new int [newSize];
                Array.Copy(m_iColumns, temp, m_iLineNumberCount);
                m_iColumns = temp;
 
                temp = new int [newSize];
                Array.Copy(m_iEndLines, temp, m_iLineNumberCount);
                m_iEndLines = temp;
 
                temp = new int [newSize];
                Array.Copy(m_iEndColumns, temp, m_iLineNumberCount);
                m_iEndColumns = temp;
            }
        }
 
        #if FEATURE_CORECLR
        [System.Security.SecurityCritical] // auto-generated
        #endif
        internal void EmitLineNumberInfo(ISymbolWriter symWriter)
        {
            int[]       iOffsetsTemp;
            int[]       iLinesTemp;
            int[]       iColumnsTemp;
            int[]       iEndLinesTemp;
            int[]       iEndColumnsTemp;
 
            if (m_iLineNumberCount == 0)
                return;
            // reduce the array size to be exact
            iOffsetsTemp = new int [m_iLineNumberCount];
            Array.Copy(m_iOffsets, iOffsetsTemp, m_iLineNumberCount);
 
            iLinesTemp = new int [m_iLineNumberCount];
            Array.Copy(m_iLines, iLinesTemp, m_iLineNumberCount);
 
            iColumnsTemp = new int [m_iLineNumberCount];
            Array.Copy(m_iColumns, iColumnsTemp, m_iLineNumberCount);
 
            iEndLinesTemp = new int [m_iLineNumberCount];
            Array.Copy(m_iEndLines, iEndLinesTemp, m_iLineNumberCount);
 
            iEndColumnsTemp = new int [m_iLineNumberCount];
            Array.Copy(m_iEndColumns, iEndColumnsTemp, m_iLineNumberCount);
 
            symWriter.DefineSequencePoints(m_document, iOffsetsTemp, iLinesTemp, iColumnsTemp, iEndLinesTemp, iEndColumnsTemp); 
        }
 
        private  int[]       m_iOffsets;                 // array of offsets
        private  int[]       m_iLines;                   // array of offsets
        private  int[]       m_iColumns;                 // array of offsets
        private  int[]       m_iEndLines;                // array of offsets
        private  int[]       m_iEndColumns;              // array of offsets
        internal ISymbolDocumentWriter m_document;       // The ISymbolDocumentWriter that this REDocument is tracking.
        private  int         m_iLineNumberCount;         // how many entries in the arrays are occupied
        private  const int   InitialSize = 16;
    }       // end of REDocument
}