We need you! We're working hard on the next version of Developer Fusion - Let us know what you think we should be up to!

The Labs \ Source Viewer \ SSCLI \ System.Reflection.Emit \ __FixupData

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Reflection.Emit
  16. {
  17.     using System;
  18.     using TextWriter = System.IO.TextWriter;
  19.     using System.Diagnostics.SymbolStore;
  20.     using System.Runtime.InteropServices;
  21.     using System.Reflection;
  22.     using System.Security.Permissions;
  23.     using System.Globalization;
  24.    
  25.     [ClassInterface(ClassInterfaceType.None)]
  26.     [ComDefaultInterface(typeof(_ILGenerator))]
  27.     [System.Runtime.InteropServices.ComVisible(true)]
  28.     public class ILGenerator : _ILGenerator
  29.     {
  30.         #region Const Members
  31.         internal const byte PrefixInstruction = (byte)255;
  32.         internal const int defaultSize = 16;
  33.         internal const int DefaultFixupArraySize = 64;
  34.         internal const int DefaultLabelArraySize = 16;
  35.         internal const int DefaultExceptionArraySize = 8;
  36.         #endregion
  37.        
  38.         #region Internal Statics
  39.         static internal int[] EnlargeArray(int[] incoming)
  40.         {
  41.             int[] temp = new int[incoming.Length * 2];
  42.             Array.Copy(incoming, temp, incoming.Length);
  43.             return temp;
  44.         }
  45.        
  46.         static internal byte[] EnlargeArray(byte[] incoming)
  47.         {
  48.             byte[] temp = new byte[incoming.Length * 2];
  49.             Array.Copy(incoming, temp, incoming.Length);
  50.             return temp;
  51.         }
  52.        
  53.         static internal byte[] EnlargeArray(byte[] incoming, int requiredSize)
  54.         {
  55.             byte[] temp = new byte[requiredSize];
  56.             Array.Copy(incoming, temp, incoming.Length);
  57.             return temp;
  58.         }
  59.        
  60.         static internal __FixupData[] EnlargeArray(__FixupData[] incoming)
  61.         {
  62.             __FixupData[] temp = new __FixupData[incoming.Length * 2];
  63.             //Does arraycopy work for value classes?
  64.             Array.Copy(incoming, temp, incoming.Length);
  65.             return temp;
  66.         }
  67.        
  68.         static internal Type[] EnlargeArray(Type[] incoming)
  69.         {
  70.             Type[] temp = new Type[incoming.Length * 2];
  71.             Array.Copy(incoming, temp, incoming.Length);
  72.             return temp;
  73.         }
  74.        
  75.         static internal __ExceptionInfo[] EnlargeArray(__ExceptionInfo[] incoming)
  76.         {
  77.             __ExceptionInfo[] temp = new __ExceptionInfo[incoming.Length * 2];
  78.             Array.Copy(incoming, temp, incoming.Length);
  79.             return temp;
  80.         }
  81.        
  82.         static internal int CalculateNumberOfExceptions(__ExceptionInfo[] excp)
  83.         {
  84.             int num = 0;
  85.             if (excp == null)
  86.                 return 0;
  87.             for (int i = 0; i < excp.Length; i++)
  88.                 num += excp[i].GetNumberOfCatches();
  89.             return num;
  90.         }
  91.        
  92.         #endregion
  93.        
  94.         #region Internal Data Members
  95.         internal int m_length;
  96.         internal byte[] m_ILStream;
  97.        
  98.         internal int[] m_labelList;
  99.         internal int m_labelCount;
  100.        
  101.         internal __FixupData[] m_fixupData;
  102.         //internal Label[] m_fixupLabel;
  103.         //internal int[] m_fixupPos;
  104.        
  105.        
  106.        
  107.        
  108.         internal int m_fixupCount;
  109.        
  110.         internal int[] m_RVAFixupList;
  111.         internal int m_RVAFixupCount;
  112.        
  113.         internal int[] m_RelocFixupList;
  114.         internal int m_RelocFixupCount;
  115.        
  116.         internal int m_exceptionCount;
  117.         internal int m_currExcStackCount;
  118.         internal __ExceptionInfo[] m_exceptions;
  119.         //This is the list of all of the exceptions in this ILStream.
  120.         internal __ExceptionInfo[] m_currExcStack;
  121.         //This is the stack of exceptions which we're currently in.
  122.         internal ScopeTree m_ScopeTree;
  123.         // this variable tracks all debugging scope information
  124.         internal LineNumberInfo m_LineNumberInfo;
  125.         // this variable tracks all line number information
  126.         internal MethodInfo m_methodBuilder;
  127.         internal int m_localCount;
  128.         internal SignatureHelper m_localSignature;
  129.        
  130.         internal int m_maxStackSize = 0;
  131.         // Maximum stack size not counting the exceptions.
  132.         internal int m_maxMidStack = 0;
  133.         // Maximum stack size for a given basic block.
  134.         internal int m_maxMidStackCur = 0;
  135.         // Running count of the maximum stack size for the current basic block.
  136.         #endregion
  137.         #region Constructor
  138.         // package private constructor. This code path is used when client create
  139.         // ILGenerator through MethodBuilder.
  140.         internal ILGenerator(MethodInfo methodBuilder) : this(methodBuilder, 64)
  141.         {
  142.         }
  143.        
  144.         internal ILGenerator(MethodInfo methodBuilder, int size)
  145.         {
  146.             if (size < defaultSize) {
  147.                 m_ILStream = new byte[defaultSize];
  148.             }
  149.             else {
  150.                 m_ILStream = new byte[size];
  151.             }
  152.            
  153.             m_length = 0;
  154.            
  155.             m_labelCount = 0;
  156.             m_fixupCount = 0;
  157.             m_labelList = null;
  158.            
  159.             m_fixupData = null;
  160.            
  161.             m_exceptions = null;
  162.             m_exceptionCount = 0;
  163.             m_currExcStack = null;
  164.             m_currExcStackCount = 0;
  165.            
  166.             m_RelocFixupList = new int[DefaultFixupArraySize];
  167.             m_RelocFixupCount = 0;
  168.             m_RVAFixupList = new int[DefaultFixupArraySize];
  169.             m_RVAFixupCount = 0;
  170.            
  171.             // initialize the scope tree
  172.             m_ScopeTree = new ScopeTree();
  173.             m_LineNumberInfo = new LineNumberInfo();
  174.             m_methodBuilder = methodBuilder;
  175.            
  176.             // initialize local signature
  177.             m_localCount = 0;
  178.             MethodBuilder mb = m_methodBuilder as MethodBuilder;
  179.             if (mb == null)
  180.                 m_localSignature = SignatureHelper.GetLocalVarSigHelper(null);
  181.             else
  182.                 m_localSignature = SignatureHelper.GetLocalVarSigHelper(mb.GetTypeBuilder().Module);
  183.         }
  184.        
  185.         internal ILGenerator(int size)
  186.         {
  187.             if (size < defaultSize)
  188.                 m_ILStream = new byte[defaultSize];
  189.             else
  190.                 m_ILStream = new byte[size];
  191.             m_length = 0;
  192.            
  193.             m_labelCount = 0;
  194.             m_fixupCount = 0;
  195.             m_labelList = null;
  196.            
  197.             m_fixupData = null;
  198.            
  199.             m_exceptions = null;
  200.             m_exceptionCount = 0;
  201.             m_currExcStack = null;
  202.             m_currExcStackCount = 0;
  203.            
  204.             m_RelocFixupList = new int[DefaultFixupArraySize];
  205.             m_RelocFixupCount = 0;
  206.             m_RVAFixupList = new int[DefaultFixupArraySize];
  207.             m_RVAFixupCount = 0;
  208.            
  209.             // initialize the scope tree
  210.             m_ScopeTree = new ScopeTree();
  211.             m_LineNumberInfo = new LineNumberInfo();
  212.             m_methodBuilder = null;
  213.            
  214.             // initialize local signature
  215.             m_localCount = 0;
  216.             m_localSignature = SignatureHelper.GetLocalVarSigHelper(null);
  217.         }
  218.        
  219.         #endregion
  220.        
  221.         #region Private Members
  222.         private void RecordTokenFixup()
  223.         {
  224.             if (m_RelocFixupCount >= m_RelocFixupList.Length)
  225.                 m_RelocFixupList = EnlargeArray(m_RelocFixupList);
  226.            
  227.             m_RelocFixupList[m_RelocFixupCount++] = m_length;
  228.         }
  229.        
  230.         #endregion
  231.        
  232.         #region Internal Members
  233.         internal void InternalEmit(OpCode opcode)
  234.         {
  235.             if (opcode.m_size == 1) {
  236.                 m_ILStream[m_length++] = opcode.m_s2;
  237.             }
  238.             else {
  239.                 m_ILStream[m_length++] = opcode.m_s1;
  240.                 m_ILStream[m_length++] = opcode.m_s2;
  241.             }
  242.            
  243.             UpdateStackSize(opcode, opcode.StackChange());
  244.            
  245.         }
  246.        
  247.         internal void UpdateStackSize(OpCode opcode, int stackchange)
  248.         {
  249.             // Updates internal variables for keeping track of the stack size
  250.             // requirements for the function. stackchange specifies the amount
  251.             // by which the stacksize needs to be updated.
  252.            
  253.             // Special case for the Return. Returns pops 1 if there is a
  254.             // non-void return value.
  255.            
  256.            
  257.            
  258.            
  259.            
  260.            
  261.            
  262.            
  263.            
  264.             // Update the running stacksize. m_maxMidStack specifies the maximum
  265.             // amount of stack required for the current basic block irrespective of
  266.             // where you enter the block.
  267.             m_maxMidStackCur += stackchange;
  268.             if (m_maxMidStackCur > m_maxMidStack)
  269.                 m_maxMidStack = m_maxMidStackCur;
  270.             else if (m_maxMidStackCur < 0)
  271.                 m_maxMidStackCur = 0;
  272.            
  273.             // If the current instruction signifies end of a basic, which basically
  274.             // means an unconditional branch, add m_maxMidStack to m_maxStackSize.
  275.             // m_maxStackSize will eventually be the sum of the stack requirements for
  276.             // each basic block.
  277.             if (opcode.EndsUncondJmpBlk()) {
  278.                 m_maxStackSize += m_maxMidStack;
  279.                 m_maxMidStack = 0;
  280.                 m_maxMidStackCur = 0;
  281.             }
  282.         }
  283.        
  284.         internal virtual int GetMethodToken(MethodBase method, Type[] optionalParameterTypes)
  285.         {
  286.             int tk = 0;
  287.             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
  288.            
  289.             if (method.IsGenericMethod) {
  290.                 // Given M<Bar> unbind to M<S>
  291.                 MethodInfo methodInfoUnbound = method as MethodInfo;
  292.                
  293.                 if (!method.IsGenericMethodDefinition && method is MethodInfo)
  294.                     methodInfoUnbound = ((MethodInfo)method).GetGenericMethodDefinition();
  295.                
  296.                 if (methodInfoUnbound.Module != m_methodBuilder.Module || (methodInfoUnbound.DeclaringType != null && methodInfoUnbound.DeclaringType.IsGenericType))
  297.                     tk = GetMemberRefToken(methodInfoUnbound, null);
  298.                 else
  299.                     tk = modBuilder.GetMethodToken(methodInfoUnbound).Token;
  300.                
  301.                 // Create signature of method instantiation M<Bar>
  302.                 int sigLength;
  303.                 byte[] sigBytes = SignatureHelper.GetMethodSpecSigHelper(modBuilder, method.GetGenericArguments()).InternalGetSignature(out sigLength);
  304.                
  305.                 // Create MethodSepc M<Bar> with parent G?.M<S>
  306.                 tk = TypeBuilder.InternalDefineMethodSpec(tk, sigBytes, sigLength, modBuilder);
  307.             }
  308.             else {
  309.                 if (((method.CallingConvention & CallingConventions.VarArgs) == 0) && (method.DeclaringType == null || !method.DeclaringType.IsGenericType)) {
  310.                     if (method is MethodInfo)
  311.                         tk = modBuilder.GetMethodToken(method as MethodInfo).Token;
  312.                     else
  313.                         tk = modBuilder.GetConstructorToken(method as ConstructorInfo).Token;
  314.                 }
  315.                 else {
  316.                     tk = GetMemberRefToken(method, optionalParameterTypes);
  317.                 }
  318.             }
  319.            
  320.             return tk;
  321.         }
  322.        
  323.         internal virtual int GetMemberRefToken(MethodBase method, Type[] optionalParameterTypes)
  324.         {
  325.             Type[] parameterTypes;
  326.             Type returnType;
  327.             int tkParent;
  328.             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
  329.             int cGenericParameters = 0;
  330.            
  331.             if (method.IsGenericMethod) {
  332.                 if (!method.IsGenericMethodDefinition)
  333.                     throw new InvalidOperationException();
  334.                
  335.                 cGenericParameters = method.GetGenericArguments().Length;
  336.             }
  337.            
  338.             if (optionalParameterTypes != null) {
  339.                 if ((method.CallingConvention & CallingConventions.VarArgs) == 0) {
  340.                     // Client should not supply optional parameter in default calling convention
  341.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention"));
  342.                 }
  343.             }
  344.            
  345.             if (method.DeclaringType.IsGenericType) {
  346.                 MethodBase methDef = null;
  347.                 // methodInfo = G<Foo>.M<Bar> ==> methDef = G<T>.M<S>
  348.                 if (method is MethodOnTypeBuilderInstantiation) {
  349.                     methDef = (method as MethodOnTypeBuilderInstantiation).m_method;
  350.                 }
  351.                 else if (method is ConstructorOnTypeBuilderInstantiation) {
  352.                     methDef = (method as ConstructorOnTypeBuilderInstantiation).m_ctor;
  353.                 }
  354.                 else if (method is MethodBuilder || method is ConstructorBuilder) {
  355.                     // methodInfo must be GenericMethodDefinition; trying to emit G<?>.M<S>
  356.                     methDef = method;
  357.                 }
  358.                 else if (method.IsGenericMethod) {
  359.                     methDef = ((MethodInfo)method).GetGenericMethodDefinition();
  360.                     methDef = methDef.Module.ResolveMethod(methDef.MetadataTokenInternal, methDef.GetGenericArguments(), methDef.DeclaringType != null ? methDef.DeclaringType.GetGenericArguments() : null) as MethodBase;
  361.                 }
  362.                 else {
  363.                     methDef = method;
  364.                     methDef = method.Module.ResolveMethod(method.MetadataTokenInternal, null, methDef.DeclaringType != null ? methDef.DeclaringType.GetGenericArguments() : null) as MethodBase;
  365.                 }
  366.                
  367.                 parameterTypes = methDef.GetParameterTypes();
  368.                 returnType = methDef.GetReturnType();
  369.             }
  370.             else {
  371.                 parameterTypes = method.GetParameterTypes();
  372.                 returnType = method.GetReturnType();
  373.             }
  374.            
  375.             if (method.DeclaringType.IsGenericType) {
  376.                 int length;
  377.                 byte[] sig = SignatureHelper.GetTypeSigToken(modBuilder, method.DeclaringType).InternalGetSignature(out length);
  378.                 tkParent = modBuilder.InternalGetTypeSpecTokenWithBytes(sig, length);
  379.             }
  380.             else if (method.Module != modBuilder) {
  381.                 // Use typeRef as parent because the method's declaringType lives in a different assembly
  382.                 tkParent = modBuilder.GetTypeToken(method.DeclaringType).Token;
  383.             }
  384.             else {
  385.                 // Use methodDef as parent because the method lives in this assembly and its declaringType has no generic arguments
  386.                 if (method is MethodInfo)
  387.                     tkParent = modBuilder.GetMethodToken(method as MethodInfo).Token;
  388.                 else
  389.                     tkParent = modBuilder.GetConstructorToken(method as ConstructorInfo).Token;
  390.             }
  391.            
  392.             int sigLength;
  393.             byte[] sigBytes = GetMemberRefSignature(method.CallingConvention, returnType, parameterTypes, optionalParameterTypes, cGenericParameters).InternalGetSignature(out sigLength);
  394.            
  395.             return modBuilder.InternalGetMemberRefFromSignature(tkParent, method.Name, sigBytes, sigLength);
  396.         }
  397.        
  398.         internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
  399.         {
  400.             return GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, 0);
  401.         }
  402.        
  403.         internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes, int cGenericParameters)
  404.         {
  405.             int cParams;
  406.             int i;
  407.             SignatureHelper sig;
  408.            
  409.             if (parameterTypes == null) {
  410.                 cParams = 0;
  411.             }
  412.             else {
  413.                 cParams = parameterTypes.Length;
  414.             }
  415.            
  416.             sig = SignatureHelper.GetMethodSigHelper(m_methodBuilder.Module, call, returnType, cGenericParameters);
  417.            
  418.             for (i = 0; i < cParams; i++)
  419.                 sig.AddArgument(parameterTypes[i]);
  420.            
  421.             if (optionalParameterTypes != null && optionalParameterTypes.Length != 0) {
  422.                 // add the sentinel
  423.                 sig.AddSentinel();
  424.                
  425.                 for (i = 0; i < optionalParameterTypes.Length; i++)
  426.                     sig.AddArgument(optionalParameterTypes[i]);
  427.             }
  428.            
  429.             return sig;
  430.         }
  431.        
  432.         internal virtual byte[] BakeByteArray()
  433.         {
  434.             // BakeByteArray is a package private function designed to be called by MethodDefinition to do
  435.             // all of the fixups and return a new byte array representing the byte stream with labels resolved, etc.
  436.             //
  437.            
  438.            
  439.             int newSize;
  440.             int updateAddr;
  441.             byte[] newBytes;
  442.            
  443.             if (m_currExcStackCount != 0) {
  444.                 throw new ArgumentException(Environment.GetResourceString("Argument_UnclosedExceptionBlock"));
  445.             }
  446.             if (m_length == 0)
  447.                 return null;
  448.            
  449.             //Calculate the size of the new array.
  450.             newSize = m_length;
  451.            
  452.             //Allocate space for the new array.
  453.             newBytes = new byte[newSize];
  454.            
  455.             //Copy the data from the old array
  456.             Array.Copy(m_ILStream, newBytes, newSize);
  457.            
  458.             //Do the fixups.
  459.             //This involves iterating over all of the labels and
  460.             //replacing them with their proper values.
  461.             for (int i = 0; i < m_fixupCount; i++) {
  462.                 updateAddr = GetLabelPos(m_fixupData[i].m_fixupLabel) - (m_fixupData[i].m_fixupPos + m_fixupData[i].m_fixupInstSize);
  463.                
  464.                 //Handle single byte instructions
  465.                 //Throw an exception if they're trying to store a jump in a single byte instruction that doesn't fit.
  466.                 if (m_fixupData[i].m_fixupInstSize == 1) {
  467.                    
  468.                     //Verify that our one-byte arg will fit into a Signed Byte.
  469.                     if (updateAddr < SByte.MinValue || updateAddr > SByte.MaxValue) {
  470.                        
  471.                         throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_IllegalOneByteBranch"), m_fixupData[i].m_fixupPos, updateAddr));
  472.                     }
  473.                    
  474.                     //Place the one-byte arg
  475.                     if (updateAddr < 0) {
  476.                        
  477.                         newBytes[m_fixupData[i].m_fixupPos] = (byte)(256 + updateAddr);
  478.                     }
  479.                     else {
  480.                         newBytes[m_fixupData[i].m_fixupPos] = (byte)updateAddr;
  481.                     }
  482.                 }
  483.                 else {
  484.                     //Place the four-byte arg
  485.                     PutInteger4(updateAddr, m_fixupData[i].m_fixupPos, newBytes);
  486.                 }
  487.             }
  488.             return newBytes;
  489.         }
  490.        
  491.         internal virtual __ExceptionInfo[] GetExceptions()
  492.         {
  493.             __ExceptionInfo[] temp;
  494.             if (m_currExcStackCount != 0) {
  495.                 throw new NotSupportedException(Environment.GetResourceString(ResId.Argument_UnclosedExceptionBlock));
  496.             }
  497.            
  498.             if (m_exceptionCount == 0) {
  499.                 return null;
  500.             }
  501.            
  502.             temp = new __ExceptionInfo[m_exceptionCount];
  503.             Array.Copy(m_exceptions, temp, m_exceptionCount);
  504.             SortExceptions(temp);
  505.             return temp;
  506.         }
  507.        
  508.         internal virtual void EnsureCapacity(int size)
  509.         {
  510.             // Guarantees an array capable of holding at least size elements.
  511.             if (m_length + size >= m_ILStream.Length) {
  512.                 if (m_length + size >= 2 * m_ILStream.Length) {
  513.                     m_ILStream = EnlargeArray(m_ILStream, m_length + size);
  514.                 }
  515.                 else {
  516.                     m_ILStream = EnlargeArray(m_ILStream);
  517.                 }
  518.             }
  519.         }
  520.        
  521.         internal virtual int PutInteger4(int value, int startPos, byte[] array)
  522.         {
  523.             // Puts an Int32 onto the stream. This is an internal routine, so it does not do any error checking.
  524.            
  525.             array[startPos++] = (byte)value;
  526.             array[startPos++] = (byte)(value >> 8);
  527.             array[startPos++] = (byte)(value >> 16);
  528.             array[startPos++] = (byte)(value >> 24);
  529.             return startPos;
  530.         }
  531.        
  532.         internal virtual int GetLabelPos(Label lbl)
  533.         {
  534.             // Gets the position in the stream of a particular label.
  535.             // Verifies that the label exists and that it has been given a value.
  536.            
  537.             int index = lbl.GetLabelValue();
  538.            
  539.             if (index < 0 || index >= m_labelCount)
  540.                 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabel"));
  541.            
  542.             if (m_labelList[index] < 0)
  543.                 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabelContent"));
  544.            
  545.             return m_labelList[index];
  546.         }
  547.        
  548.         internal virtual void AddFixup(Label lbl, int pos, int instSize)
  549.         {
  550.             // Notes the label, position, and instruction size of a new fixup. Expands
  551.             // all of the fixup arrays as appropriate.
  552.            
  553.             if (m_fixupData == null) {
  554.                 m_fixupData = new __FixupData[DefaultFixupArraySize];
  555.             }
  556.            
  557.             if (m_fixupCount >= m_fixupData.Length) {
  558.                 m_fixupData = EnlargeArray(m_fixupData);
  559.             }
  560.            
  561.             m_fixupData[m_fixupCount].m_fixupPos = pos;
  562.             m_fixupData[m_fixupCount].m_fixupLabel = lbl;
  563.             m_fixupData[m_fixupCount].m_fixupInstSize = instSize;
  564.             m_fixupCount++;
  565.         }
  566.        
  567.         internal virtual int GetMaxStackSize()
  568.         {
  569.             MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
  570.             if (methodBuilder == null)
  571.                 throw new NotSupportedException();
  572.             return m_maxStackSize + methodBuilder.GetNumberOfExceptions();
  573.         }
  574.        
  575.         internal virtual void SortExceptions(__ExceptionInfo[] exceptions)
  576.         {
  577.            
  578.             int least;
  579.             __ExceptionInfo temp;
  580.             int length = exceptions.Length;
  581.             for (int i = 0; i < length; i++) {
  582.                 least = i;
  583.                 for (int j = i + 1; j < length; j++) {
  584.                     if (exceptions[least].IsInner(exceptions[j])) {
  585.                         least = j;
  586.                     }
  587.                 }
  588.                 temp = exceptions[i];
  589.                 exceptions[i] = exceptions[least];
  590.                 exceptions[least] = temp;
  591.             }
  592.         }
  593.        
  594.         internal virtual int[] GetTokenFixups()
  595.         {
  596.            
  597.             int[] narrowTokens = new int[m_RelocFixupCount];
  598.             Array.Copy(m_RelocFixupList, narrowTokens, m_RelocFixupCount);
  599.             return narrowTokens;
  600.         }
  601.        
  602.         internal virtual int[] GetRVAFixups()
  603.         {
  604.            
  605.             int[] narrowRVAs = new int[m_RVAFixupCount];
  606.             Array.Copy(m_RVAFixupList, narrowRVAs, m_RVAFixupCount);
  607.             return narrowRVAs;
  608.         }
  609.         #endregion
  610.        
  611.         #region Public Members
  612.        
  613.         #region Emit
  614.         public virtual void Emit(OpCode opcode)
  615.         {
  616.             EnsureCapacity(3);
  617.             InternalEmit(opcode);
  618.            
  619.         }
  620.        
  621.         public virtual void Emit(OpCode opcode, byte arg)
  622.         {
  623.             EnsureCapacity(4);
  624.             InternalEmit(opcode);
  625.             m_ILStream[m_length++] = arg;
  626.         }
  627.        
  628.         [CLSCompliant(false)]
  629.         public void Emit(OpCode opcode, sbyte arg)
  630.         {
  631.             // Puts opcode onto the stream of instructions followed by arg
  632.            
  633.             EnsureCapacity(4);
  634.             InternalEmit(opcode);
  635.             if (arg < 0) {
  636.                 m_ILStream[m_length++] = (byte)(256 + arg);
  637.             }
  638.             else {
  639.                 m_ILStream[m_length++] = (byte)arg;
  640.             }
  641.         }
  642.        
  643.         public virtual void Emit(OpCode opcode, short arg)
  644.         {
  645.             // Puts opcode onto the stream of instructions followed by arg
  646.             EnsureCapacity(5);
  647.             InternalEmit(opcode);
  648.             m_ILStream[m_length++] = (byte)arg;
  649.             m_ILStream[m_length++] = (byte)(arg >> 8);
  650.         }
  651.        
  652.         public virtual void Emit(OpCode opcode, int arg)
  653.         {
  654.             // Puts opcode onto the stream of instructions followed by arg
  655.             EnsureCapacity(7);
  656.             InternalEmit(opcode);
  657.             m_length = PutInteger4(arg, m_length, m_ILStream);
  658.         }
  659.        
  660.         public virtual void Emit(OpCode opcode, MethodInfo meth)
  661.         {
  662.             if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)) {
  663.                 EmitCall(opcode, meth, null);
  664.             }
  665.             else {
  666.                 int stackchange = 0;
  667.                
  668.                 if (meth == null)
  669.                     throw new ArgumentNullException("meth");
  670.                
  671.                 int tk = GetMethodToken(meth, null);
  672.                
  673.                 EnsureCapacity(7);
  674.                 InternalEmit(opcode);
  675.                
  676.                 UpdateStackSize(opcode, stackchange);
  677.                 RecordTokenFixup();
  678.                 m_length = PutInteger4(tk, m_length, m_ILStream);
  679.             }
  680.         }
  681.        
  682.        
  683.         public virtual void EmitCalli(OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
  684.         {
  685.             int stackchange = 0;
  686.             SignatureHelper sig;
  687.             if (optionalParameterTypes != null) {
  688.                 if ((callingConvention & CallingConventions.VarArgs) == 0) {
  689.                     // Client should not supply optional parameter in default calling convention
  690.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention"));
  691.                 }
  692.             }
  693.            
  694.             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
  695.             sig = GetMemberRefSignature(callingConvention, returnType, parameterTypes, optionalParameterTypes);
  696.            
  697.             EnsureCapacity(7);
  698.             Emit(OpCodes.Calli);
  699.            
  700.             // The opcode passed in must be the calli instruction.
  701.             BCLDebug.Assert(opcode.Equals(OpCodes.Calli), "Unexpected opcode passed to EmitCalli.");
  702.             // If there is a non-void return type, push one.
  703.             if (returnType != typeof(void))
  704.                 stackchange++;
  705.             // Pop off arguments if any.
  706.             if (parameterTypes != null)
  707.                 stackchange -= parameterTypes.Length;
  708.             // Pop off vararg arguments.
  709.             if (optionalParameterTypes != null)
  710.                 stackchange -= optionalParameterTypes.Length;
  711.             // Pop the this parameter if the method has a this parameter.
  712.             if ((callingConvention & CallingConventions.HasThis) == CallingConventions.HasThis)
  713.                 stackchange--;
  714.             // Pop the native function pointer.
  715.             stackchange--;
  716.             UpdateStackSize(opcode, stackchange);
  717.            
  718.             RecordTokenFixup();
  719.             m_length = PutInteger4(modBuilder.GetSignatureToken(sig).Token, m_length, m_ILStream);
  720.         }
  721.        
  722.         public virtual void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
  723.         {
  724.             int stackchange = 0;
  725.             int cParams = 0;
  726.             int i;
  727.             SignatureHelper sig;
  728.            
  729.             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
  730.            
  731.             // The opcode passed in must be the calli instruction.
  732.             BCLDebug.Assert(opcode.Equals(OpCodes.Calli), "Unexpected opcode passed to EmitCalli.");
  733.             if (parameterTypes != null) {
  734.                 cParams = parameterTypes.Length;
  735.             }
  736.            
  737.             sig = SignatureHelper.GetMethodSigHelper(modBuilder, unmanagedCallConv, returnType);
  738.            
  739.             if (parameterTypes != null) {
  740.                 for (i = 0; i < cParams; i++) {
  741.                     sig.AddArgument(parameterTypes[i]);
  742.                 }
  743.             }
  744.            
  745.             // If there is a non-void return type, push one.
  746.             if (returnType != typeof(void))
  747.                 stackchange++;
  748.            
  749.             // Pop off arguments if any.
  750.             if (parameterTypes != null)
  751.                 stackchange -= cParams;
  752.            
  753.             // Pop the native function pointer.
  754.             stackchange--;
  755.             UpdateStackSize(opcode, stackchange);
  756.            
  757.             EnsureCapacity(7);
  758.             Emit(OpCodes.Calli);
  759.             RecordTokenFixup();
  760.             m_length = PutInteger4(modBuilder.GetSignatureToken(sig).Token, m_length, m_ILStream);
  761.         }
  762.        
  763.         public virtual void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
  764.         {
  765.             int stackchange = 0;
  766.            
  767.             if (methodInfo == null)
  768.                 throw new ArgumentNullException("methodInfo");
  769.            
  770.             int tk = GetMethodToken(methodInfo, optionalParameterTypes);
  771.            
  772.             EnsureCapacity(7);
  773.             InternalEmit(opcode);
  774.            
  775.             // The opcode must be one of call, callvirt, or newobj.
  776.             BCLDebug.Assert(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj), "Unexpected opcode passed to EmitCall.");
  777.             // Push the return value if there is one.
  778.             if (methodInfo.GetReturnType() != typeof(void))
  779.                 stackchange++;
  780.             // Pop the parameters.
  781.             if (methodInfo.GetParameterTypes() != null)
  782.                 stackchange -= methodInfo.GetParameterTypes().Length;
  783.            
  784.             // Pop the this parameter if the method is non-static and the
  785.             // instruction is not newobj.
  786.             if (!(methodInfo is SymbolMethod) && methodInfo.IsStatic == false && !(opcode.Equals(OpCodes.Newobj)))
  787.                 stackchange--;
  788.             // Pop the optional parameters off the stack.
  789.             if (optionalParameterTypes != null)
  790.                 stackchange -= optionalParameterTypes.Length;
  791.             UpdateStackSize(opcode, stackchange);
  792.            
  793.             RecordTokenFixup();
  794.             m_length = PutInteger4(tk, m_length, m_ILStream);
  795.         }
  796.        
  797.         public virtual void Emit(OpCode opcode, SignatureHelper signature)
  798.         {
  799.             int stackchange = 0;
  800.             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
  801.             if (signature == null)
  802.                 throw new ArgumentNullException("signature");
  803.            
  804.             SignatureToken sig = modBuilder.GetSignatureToken(signature);
  805.            
  806.             int tempVal = sig.Token;
  807.            
  808.             EnsureCapacity(7);
  809.             InternalEmit(opcode);
  810.            
  811.             // The only IL instruction that has VarPop behaviour, that takes a
  812.             // Signature token as a parameter is calli. Pop the parameters and
  813.             // the native function pointer. To be conservative, do not pop the
  814.             // this pointer since this information is not easily derived from
  815.             // SignatureHelper.
  816.             if (opcode.m_pop == StackBehaviour.Varpop) {
  817.                 BCLDebug.Assert(opcode.Equals(OpCodes.Calli), "Unexpected opcode encountered for StackBehaviour VarPop.");
  818.                 // Pop the arguments..
  819.                 stackchange -= signature.ArgumentCount;
  820.                 // Pop native function pointer off the stack.
  821.                 stackchange--;
  822.                 UpdateStackSize(opcode, stackchange);
  823.             }
  824.            
  825.             RecordTokenFixup();
  826.             m_length = PutInteger4(tempVal, m_length, m_ILStream);
  827.         }
  828.        
  829.         [System.Runtime.InteropServices.ComVisible(true)]
  830.         public virtual void Emit(OpCode opcode, ConstructorInfo con)
  831.         {
  832.             int stackchange = 0;
  833.            
  834.             int tk = GetMethodToken(con, null);
  835.            
  836.             EnsureCapacity(7);
  837.             InternalEmit(opcode);
  838.            
  839.             // Make a conservative estimate by assuming a return type and no
  840.             // this parameter.
  841.             if (opcode.m_push == StackBehaviour.Varpush) {
  842.                 // Instruction must be one of call or callvirt.
  843.                 BCLDebug.Assert(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt), "Unexpected opcode encountered for StackBehaviour of VarPush.");
  844.                 stackchange++;
  845.             }
  846.             if (opcode.m_pop == StackBehaviour.Varpop) {
  847.                 // Instruction must be one of call, callvirt or newobj.
  848.                 BCLDebug.Assert(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj), "Unex