Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / reflection / emit / ilgenerator.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 namespace System.Reflection.Emit 
10 {
11     using System;
12     using TextWriter = System.IO.TextWriter;
13     using System.Diagnostics.SymbolStore;
14     using System.Runtime.InteropServices;
15     using System.Reflection;
16     using System.Security.Permissions;
17     using System.Globalization;
18     using System.Diagnostics.Contracts;
19     
20     [ClassInterface(ClassInterfaceType.None)]
21     [ComDefaultInterface(typeof(_ILGenerator))]
22     [System.Runtime.InteropServices.ComVisible(true)]
23     public class ILGenerator : _ILGenerator
24     {
25         #region Const Members
26         private const int defaultSize = 16;
27         private const int DefaultFixupArraySize = 8;
28         private const int DefaultLabelArraySize = 4;
29         private const int DefaultExceptionArraySize = 2;
30         #endregion
31
32         #region Internal Statics
33         internal static int[] EnlargeArray(int[] incoming)
34         {
35             Contract.Requires(incoming != null);
36             Contract.Ensures(Contract.Result<int[]>() != null);
37             Contract.Ensures(Contract.Result<int[]>().Length > incoming.Length);
38             int[] temp = new int [incoming.Length*2];
39             Array.Copy(incoming, temp, incoming.Length);
40             return temp;
41         }
42
43         private static byte[] EnlargeArray(byte[] incoming)
44         {
45             byte [] temp = new byte [incoming.Length*2];
46             Array.Copy(incoming, temp, incoming.Length);
47             return temp;
48         }
49
50         private static byte[] EnlargeArray(byte[] incoming, int requiredSize)
51         {
52             byte [] temp = new byte [requiredSize];
53             Array.Copy(incoming, temp, incoming.Length);
54             return temp;
55         }
56
57         private static __FixupData[] EnlargeArray(__FixupData[] incoming)
58         {
59             __FixupData [] temp = new __FixupData[incoming.Length*2];
60             //Does arraycopy work for value classes?
61             Array.Copy(incoming, temp, incoming.Length);
62             return temp;
63         }
64
65         private static __ExceptionInfo[] EnlargeArray(__ExceptionInfo[] incoming)
66         {
67             __ExceptionInfo[] temp = new __ExceptionInfo[incoming.Length*2];
68             Array.Copy(incoming, temp, incoming.Length);
69             return temp;
70         }        
71         #endregion
72
73         #region Internal Data Members
74         private  int                m_length;
75         private  byte[]             m_ILStream;
76
77         private  int[]              m_labelList;
78         private  int                m_labelCount;
79
80         private  __FixupData[]      m_fixupData;         
81          
82         private  int                m_fixupCount;
83
84         private  int[]              m_RelocFixupList;
85         private  int                m_RelocFixupCount;
86
87         private  int                m_exceptionCount;
88         private  int                m_currExcStackCount;
89         private  __ExceptionInfo[]  m_exceptions;           //This is the list of all of the exceptions in this ILStream.
90         private  __ExceptionInfo[]  m_currExcStack;         //This is the stack of exceptions which we're currently in.
91
92         internal ScopeTree          m_ScopeTree;            // this variable tracks all debugging scope information
93         internal LineNumberInfo     m_LineNumberInfo;       // this variable tracks all line number information
94
95         internal MethodInfo         m_methodBuilder;
96         internal int                m_localCount;
97         internal SignatureHelper    m_localSignature;
98
99         private  int                m_maxStackSize = 0;     // Maximum stack size not counting the exceptions.
100
101         private  int                m_maxMidStack = 0;      // Maximum stack size for a given basic block.
102         private  int                m_maxMidStackCur = 0;   // Running count of the maximum stack size for the current basic block.
103
104         internal int CurrExcStackCount
105         {
106             get { return m_currExcStackCount; }
107         }
108
109         internal __ExceptionInfo[] CurrExcStack
110         {
111             get { return m_currExcStack; }
112         }
113         #endregion
114
115         #region Constructor
116         // package private constructor. This code path is used when client create
117         // ILGenerator through MethodBuilder.
118         internal ILGenerator(MethodInfo methodBuilder) : this(methodBuilder, 64)
119         {
120         }
121
122         internal ILGenerator(MethodInfo methodBuilder, int size)
123         {
124             Contract.Requires(methodBuilder != null);
125             Contract.Requires(methodBuilder is MethodBuilder || methodBuilder is DynamicMethod);
126
127             if (size < defaultSize)
128             {
129                 m_ILStream = new byte[defaultSize];
130             }
131             else
132             {
133                 m_ILStream = new byte[size];
134             }
135
136             m_length = 0;
137
138             m_labelCount = 0;
139             m_fixupCount = 0;
140             m_labelList = null;
141
142             m_fixupData = null;
143
144             m_exceptions = null; 
145             m_exceptionCount = 0;
146             m_currExcStack = null; 
147             m_currExcStackCount = 0;
148
149             m_RelocFixupList = null;
150             m_RelocFixupCount = 0;
151
152             // initialize the scope tree
153             m_ScopeTree = new ScopeTree();
154             m_LineNumberInfo = new LineNumberInfo();
155             m_methodBuilder = methodBuilder;
156
157             // initialize local signature
158             m_localCount = 0;
159             MethodBuilder mb = m_methodBuilder as MethodBuilder;
160             if (mb == null) 
161                 m_localSignature = SignatureHelper.GetLocalVarSigHelper(null);
162             else
163                 m_localSignature = SignatureHelper.GetLocalVarSigHelper(mb.GetTypeBuilder().Module);
164         }
165
166         #endregion
167
168         #region Internal Members
169         internal virtual void RecordTokenFixup()
170         {
171             if (m_RelocFixupList == null)
172                 m_RelocFixupList = new int[DefaultFixupArraySize];
173             else if (m_RelocFixupList.Length <= m_RelocFixupCount)
174                 m_RelocFixupList = EnlargeArray(m_RelocFixupList);
175
176             m_RelocFixupList[m_RelocFixupCount++] = m_length;
177         }
178
179         internal void InternalEmit(OpCode opcode)
180         {
181             if (opcode.Size != 1)
182             {
183                 m_ILStream[m_length++] = (byte)(opcode.Value >> 8);
184             }
185
186             m_ILStream[m_length++] = (byte)opcode.Value;
187
188             UpdateStackSize(opcode, opcode.StackChange());
189
190         }
191
192         internal void UpdateStackSize(OpCode opcode, int stackchange)
193         {
194             // Updates internal variables for keeping track of the stack size
195             // requirements for the function.  stackchange specifies the amount
196             // by which the stacksize needs to be updated.
197
198             // Special case for the Return.  Returns pops 1 if there is a
199             // non-void return value.
200
201             // Update the running stacksize.  m_maxMidStack specifies the maximum
202             // amount of stack required for the current basic block irrespective of
203             // where you enter the block.
204             m_maxMidStackCur += stackchange;
205             if (m_maxMidStackCur > m_maxMidStack)
206                 m_maxMidStack = m_maxMidStackCur;
207             else if (m_maxMidStackCur < 0)
208                 m_maxMidStackCur = 0;
209
210             // If the current instruction signifies end of a basic, which basically
211             // means an unconditional branch, add m_maxMidStack to m_maxStackSize.
212             // m_maxStackSize will eventually be the sum of the stack requirements for
213             // each basic block.
214             if (opcode.EndsUncondJmpBlk())
215             {
216                 m_maxStackSize += m_maxMidStack;
217                 m_maxMidStack = 0;
218                 m_maxMidStackCur = 0;
219             }
220         }
221
222         [System.Security.SecurityCritical]  // auto-generated
223         private int GetMethodToken(MethodBase method, Type[] optionalParameterTypes, bool useMethodDef)
224         {
225             return ((ModuleBuilder)m_methodBuilder.Module).GetMethodTokenInternal(method, optionalParameterTypes, useMethodDef);
226         }
227
228         [System.Security.SecurityCritical]  // auto-generated
229         internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, 
230             Type[] parameterTypes, Type[] optionalParameterTypes)
231         {
232             return GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, 0);
233         }
234
235         [System.Security.SecurityCritical]  // auto-generated
236         private SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType, 
237             Type[] parameterTypes, Type[] optionalParameterTypes, int cGenericParameters)
238         {
239             return ((ModuleBuilder)m_methodBuilder.Module).GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, cGenericParameters);
240         }
241
242         internal byte[] BakeByteArray()
243         {
244             // BakeByteArray is an internal function designed to be called by MethodBuilder to do
245             // all of the fixups and return a new byte array representing the byte stream with labels resolved, etc.
246
247             int newSize;
248             int updateAddr;
249             byte []newBytes;
250
251             if (m_currExcStackCount != 0)
252             {
253                 throw new ArgumentException(Environment.GetResourceString("Argument_UnclosedExceptionBlock"));
254             }
255             if (m_length == 0)
256                 return null;
257
258             //Calculate the size of the new array.
259             newSize = m_length;
260
261             //Allocate space for the new array.
262             newBytes = new byte[newSize];
263
264             //Copy the data from the old array
265             Array.Copy(m_ILStream, newBytes, newSize);
266
267             //Do the fixups.
268             //This involves iterating over all of the labels and
269             //replacing them with their proper values.
270             for (int i =0; i < m_fixupCount; i++)
271             {
272                 updateAddr = GetLabelPos(m_fixupData[i].m_fixupLabel) - (m_fixupData[i].m_fixupPos + m_fixupData[i].m_fixupInstSize);
273
274                 //Handle single byte instructions
275                 //Throw an exception if they're trying to store a jump in a single byte instruction that doesn't fit.
276                 if (m_fixupData[i].m_fixupInstSize == 1)
277                 {
278
279                     //Verify that our one-byte arg will fit into a Signed Byte.
280                     if (updateAddr < SByte.MinValue || updateAddr > SByte.MaxValue)
281                     {
282                         throw new NotSupportedException(Environment.GetResourceString("NotSupported_IllegalOneByteBranch",m_fixupData[i].m_fixupPos, updateAddr));
283                     }
284
285                     //Place the one-byte arg
286                     if (updateAddr < 0)
287                     {
288                         newBytes[m_fixupData[i].m_fixupPos] = (byte)(256 + updateAddr);
289                     }
290                     else
291                     {
292                         newBytes[m_fixupData[i].m_fixupPos] = (byte)updateAddr;
293                     }
294                 }
295                 else
296                 {
297                     //Place the four-byte arg
298                     PutInteger4InArray(updateAddr, m_fixupData[i].m_fixupPos, newBytes);
299                 }
300             }
301             return newBytes;
302         }
303
304         internal __ExceptionInfo[] GetExceptions()
305         {
306             __ExceptionInfo []temp;
307             if (m_currExcStackCount != 0)
308             {
309                 throw new NotSupportedException(Environment.GetResourceString(ResId.Argument_UnclosedExceptionBlock));
310             }
311             
312             if (m_exceptionCount == 0)
313             {
314                 return null;
315             }
316             
317             temp = new __ExceptionInfo[m_exceptionCount];
318             Array.Copy(m_exceptions, temp, m_exceptionCount);
319             SortExceptions(temp);
320             return temp;
321         }
322
323         internal void EnsureCapacity(int size)
324         {
325             // Guarantees an array capable of holding at least size elements.
326             if (m_length + size >= m_ILStream.Length)
327             {
328                 if (m_length + size >= 2 * m_ILStream.Length)
329                 {
330                     m_ILStream = EnlargeArray(m_ILStream, m_length + size);
331                 }
332                 else
333                 {
334                     m_ILStream = EnlargeArray(m_ILStream);
335                 }
336             }
337         }
338
339         internal void PutInteger4(int value)
340         {
341             m_length = PutInteger4InArray(value, m_length, m_ILStream);
342         }
343
344         private static int PutInteger4InArray(int value, int startPos, byte []array)
345         {
346             // Puts an Int32 onto the stream. This is an internal routine, so it does not do any error checking.
347
348             array[startPos++] = (byte)value;
349             array[startPos++] = (byte)(value >>8);
350             array[startPos++] = (byte)(value >>16);
351             array[startPos++] = (byte)(value >>24);
352             return startPos;
353         }
354
355         private int GetLabelPos(Label lbl)
356         {
357             // Gets the position in the stream of a particular label.
358             // Verifies that the label exists and that it has been given a value.
359
360             int index = lbl.GetLabelValue();
361             
362             if (index < 0 || index >= m_labelCount)
363                 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabel"));
364
365             if (m_labelList[index] < 0)
366                 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabelContent"));
367
368             return m_labelList[index];
369         }
370
371         private void AddFixup(Label lbl, int pos, int instSize)
372         {
373             // Notes the label, position, and instruction size of a new fixup.  Expands
374             // all of the fixup arrays as appropriate.
375
376             if (m_fixupData == null)
377             {
378                 m_fixupData = new __FixupData[DefaultFixupArraySize];
379             }
380             else if (m_fixupData.Length <= m_fixupCount)
381             {
382                 m_fixupData = EnlargeArray(m_fixupData);
383             }
384
385             m_fixupData[m_fixupCount].m_fixupPos = pos;
386             m_fixupData[m_fixupCount].m_fixupLabel = lbl;
387             m_fixupData[m_fixupCount].m_fixupInstSize = instSize;
388
389             m_fixupCount++;
390         }
391
392         internal int GetMaxStackSize()
393         {
394             return m_maxStackSize;
395         }
396
397         private static void SortExceptions(__ExceptionInfo []exceptions)
398         {
399             // In order to call exceptions properly we have to sort them in ascending order by their end position.
400             // Just a cheap insertion sort.  We don't expect many exceptions (<10), where InsertionSort beats QuickSort.
401             // If we have more exceptions than this in real life, we should consider moving to a QuickSort.
402
403             int least;
404             __ExceptionInfo temp;
405             int length = exceptions.Length;
406             for (int i =0; i < length; i++)
407             {
408                 least = i;
409                 for (int j =i + 1; j < length; j++)
410                 {
411                     if (exceptions[least].IsInner(exceptions[j]))
412                     {
413                         least = j;
414                     }
415                 }
416                 temp = exceptions[i];
417                 exceptions[i] = exceptions[least];
418                 exceptions[least] = temp;
419             }
420         }
421
422         internal int[] GetTokenFixups()
423         {
424             if (m_RelocFixupCount == 0)
425             {
426                 Contract.Assert(m_RelocFixupList == null);
427                 return null;
428             }
429
430             int[] narrowTokens = new int[m_RelocFixupCount];
431             Array.Copy(m_RelocFixupList, narrowTokens, m_RelocFixupCount);
432             return narrowTokens;
433         }
434         #endregion
435
436         #region Public Members
437
438         #region Emit
439         public virtual void Emit(OpCode opcode)
440         {
441             EnsureCapacity(3);
442             InternalEmit(opcode);
443
444         }
445
446         public virtual void Emit(OpCode opcode, byte arg) 
447         {
448             EnsureCapacity(4);
449             InternalEmit(opcode);
450             m_ILStream[m_length++]=arg;
451         }
452
453         [CLSCompliant(false)]
454         public void Emit(OpCode opcode, sbyte arg) 
455         {
456             // Puts opcode onto the stream of instructions followed by arg
457
458             EnsureCapacity(4);
459             InternalEmit(opcode);
460             // <
461             if (arg<0) {
462                 m_ILStream[m_length++]=(byte)(256+arg);
463             } else {
464                 m_ILStream[m_length++]=(byte) arg;
465             }
466         }
467
468         public virtual void Emit(OpCode opcode, short arg) 
469         {
470             // Puts opcode onto the stream of instructions followed by arg
471             EnsureCapacity(5);
472             InternalEmit(opcode);
473             m_ILStream[m_length++]=(byte) arg;
474             m_ILStream[m_length++]=(byte) (arg>>8);
475         }
476
477         public virtual void Emit(OpCode opcode, int arg) 
478         {
479             // Puts opcode onto the stream of instructions followed by arg
480             EnsureCapacity(7);
481             InternalEmit(opcode);
482             PutInteger4(arg);
483         }
484
485         [System.Security.SecuritySafeCritical]  // auto-generated
486         public virtual void Emit(OpCode opcode, MethodInfo meth)
487         {
488             if (meth == null)
489                 throw new ArgumentNullException("meth");
490             Contract.EndContractBlock();
491
492             if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))
493             {
494                 EmitCall(opcode, meth, null);
495             }
496             else
497             {
498                 int stackchange = 0;
499
500                 // Reflection doesn't distinguish between these two concepts:
501                 //   1. A generic method definition: Foo`1
502                 //   2. A generic method definition instantiated over its own generic arguments: Foo`1<!!0>
503                 // In RefEmit, we always want 1 for Ld* opcodes and 2 for Call* and Newobj.
504                 bool useMethodDef = opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn) || opcode.Equals(OpCodes.Ldvirtftn);
505                 int tk = GetMethodToken(meth, null, useMethodDef);
506
507                 EnsureCapacity(7);
508                 InternalEmit(opcode);
509
510                 UpdateStackSize(opcode, stackchange);
511                 RecordTokenFixup();
512                 PutInteger4(tk);        
513             }
514         }
515
516
517         [System.Security.SecuritySafeCritical]  // auto-generated
518         public virtual void EmitCalli(OpCode opcode, CallingConventions callingConvention, 
519             Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
520         {
521             int stackchange = 0;
522             SignatureHelper     sig;
523             if (optionalParameterTypes != null)
524             {
525                 if ((callingConvention & CallingConventions.VarArgs) == 0)
526                 {
527                     // Client should not supply optional parameter in default calling convention
528                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention"));
529                 }
530             }
531
532             ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
533             sig = GetMemberRefSignature(callingConvention,
534                                         returnType,
535                                         parameterTypes,
536                                         optionalParameterTypes);
537
538             EnsureCapacity(7);
539             Emit(OpCodes.Calli);
540
541             // If there is a non-void return type, push one.
542             if (returnType != typeof(void))
543                 stackchange++;
544             // Pop off arguments if any.
545             if (parameterTypes != null)
546                 stackchange -= parameterTypes.Length;
547             // Pop off vararg arguments.
548             if (optionalParameterTypes != null)
549                 stackchange -= optionalParameterTypes.Length;
550             // Pop the this parameter if the method has a this parameter.
551             if ((callingConvention & CallingConventions.HasThis) == CallingConventions.HasThis)
552                 stackchange--;
553             // Pop the native function pointer.
554             stackchange--;
555             UpdateStackSize(OpCodes.Calli, stackchange);
556
557             RecordTokenFixup();
558             PutInteger4(modBuilder.GetSignatureToken(sig).Token);
559         }
560
561         public virtual void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
562         {
563             int             stackchange = 0;
564             int             cParams = 0;
565             int             i;
566             SignatureHelper sig;
567             
568             ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
569
570             if (parameterTypes != null)
571             {
572                 cParams = parameterTypes.Length;
573             }
574             
575             sig = SignatureHelper.GetMethodSigHelper(
576                 modBuilder, 
577                 unmanagedCallConv, 
578                 returnType);
579                             
580             if (parameterTypes != null)
581             {
582                 for (i = 0; i < cParams; i++) 
583                 {
584                     sig.AddArgument(parameterTypes[i]);
585                 }
586             }
587                                   
588             // If there is a non-void return type, push one.
589             if (returnType != typeof(void))
590                 stackchange++;
591                 
592             // Pop off arguments if any.
593             if (parameterTypes != null)
594                 stackchange -= cParams;
595                 
596             // Pop the native function pointer.
597             stackchange--;
598             UpdateStackSize(OpCodes.Calli, stackchange);
599
600             EnsureCapacity(7);
601             Emit(OpCodes.Calli);
602             RecordTokenFixup();
603             PutInteger4(modBuilder.GetSignatureToken(sig).Token);
604         }
605
606         [System.Security.SecuritySafeCritical]  // auto-generated
607         public virtual void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
608         {
609             if (methodInfo == null)
610                 throw new ArgumentNullException("methodInfo");
611
612             if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)))
613                 throw new ArgumentException(Environment.GetResourceString("Argument_NotMethodCallOpcode"), "opcode");
614
615             Contract.EndContractBlock();
616
617             int stackchange = 0;
618             int tk = GetMethodToken(methodInfo, optionalParameterTypes, false);
619
620             EnsureCapacity(7);
621             InternalEmit(opcode);
622
623             // Push the return value if there is one.
624             if (methodInfo.ReturnType != typeof(void))
625                 stackchange++;
626             // Pop the parameters.
627             Type[] parameters = methodInfo.GetParameterTypes();
628             if (parameters != null)
629                 stackchange -= parameters.Length;
630
631             // Pop the this parameter if the method is non-static and the
632             // instruction is not newobj.
633             if (!(methodInfo is SymbolMethod) && methodInfo.IsStatic == false && !(opcode.Equals(OpCodes.Newobj)))
634                 stackchange--;
635             // Pop the optional parameters off the stack.
636             if (optionalParameterTypes != null)
637                 stackchange -= optionalParameterTypes.Length;
638             UpdateStackSize(opcode, stackchange);
639
640             RecordTokenFixup();
641             PutInteger4(tk);
642         }
643
644         public virtual void Emit(OpCode opcode, SignatureHelper signature)
645         {
646             if (signature == null)
647                 throw new ArgumentNullException("signature");
648             Contract.EndContractBlock();
649
650             int stackchange = 0;
651             ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
652             SignatureToken sig = modBuilder.GetSignatureToken(signature);
653
654             int tempVal = sig.Token;
655
656             EnsureCapacity(7);
657             InternalEmit(opcode);
658
659             // The only IL instruction that has VarPop behaviour, that takes a
660             // Signature token as a parameter is calli.  Pop the parameters and
661             // the native function pointer.  To be conservative, do not pop the
662             // this pointer since this information is not easily derived from
663             // SignatureHelper.
664             if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
665             {
666                 Contract.Assert(opcode.Equals(OpCodes.Calli),
667                                 "Unexpected opcode encountered for StackBehaviour VarPop.");
668                 // Pop the arguments..
669                 stackchange -= signature.ArgumentCount;
670                 // Pop native function pointer off the stack.
671                 stackchange--;
672                 UpdateStackSize(opcode, stackchange);
673             }
674
675             RecordTokenFixup();
676             PutInteger4(tempVal);
677         }
678
679         [System.Security.SecuritySafeCritical]  // auto-generated
680         [System.Runtime.InteropServices.ComVisible(true)]
681         public virtual void Emit(OpCode opcode, ConstructorInfo con)
682         {
683             if (con == null)
684                 throw new ArgumentNullException("con");
685             Contract.EndContractBlock();
686
687             int stackchange = 0;
688
689             // Constructors cannot be generic so the value of UseMethodDef doesn't matter.
690             int tk = GetMethodToken(con, null, true);
691
692             EnsureCapacity(7);
693             InternalEmit(opcode);
694
695             // Make a conservative estimate by assuming a return type and no
696             // this parameter.
697             if (opcode.StackBehaviourPush == StackBehaviour.Varpush)
698             {
699                 // Instruction must be one of call or callvirt.
700                 Contract.Assert(opcode.Equals(OpCodes.Call) ||
701                                 opcode.Equals(OpCodes.Callvirt),
702                                 "Unexpected opcode encountered for StackBehaviour of VarPush.");
703                 stackchange++;
704             }
705             if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
706             {
707                 // Instruction must be one of call, callvirt or newobj.
708                 Contract.Assert(opcode.Equals(OpCodes.Call) ||
709                                 opcode.Equals(OpCodes.Callvirt) ||
710                                 opcode.Equals(OpCodes.Newobj),
711                                 "Unexpected opcode encountered for StackBehaviour of VarPop.");
712
713                 Type[] parameters = con.GetParameterTypes();
714                 if (parameters != null)
715                     stackchange -= parameters.Length;
716             }
717             UpdateStackSize(opcode, stackchange);
718
719             RecordTokenFixup();
720             PutInteger4(tk);
721         }
722
723         [System.Security.SecuritySafeCritical]  // auto-generated
724         public virtual void Emit(OpCode opcode, Type cls)
725         {
726             // Puts opcode onto the stream and then the metadata token represented
727             // by cls.  The location of cls is recorded so that the token can be
728             // patched if necessary when persisting the module to a PE.
729
730             int tempVal = 0;
731             ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
732             if (opcode == OpCodes.Ldtoken && cls != null && cls.IsGenericTypeDefinition)
733             {
734                 // This gets the token for the generic type definition if cls is one.
735                 tempVal = modBuilder.GetTypeToken( cls ).Token;
736             }
737             else
738             {
739                 // This gets the token for the generic type instantiated on the formal parameters
740                 // if cls is a generic type definition.
741                 tempVal = modBuilder.GetTypeTokenInternal(cls).Token;
742             }
743
744             EnsureCapacity(7);
745             InternalEmit(opcode);
746             RecordTokenFixup();
747             PutInteger4(tempVal);
748         }
749
750         public virtual void Emit(OpCode opcode, long arg) {
751             EnsureCapacity(11);
752             InternalEmit(opcode);
753             m_ILStream[m_length++] = (byte) arg;
754             m_ILStream[m_length++] = (byte) (arg>>8);
755             m_ILStream[m_length++] = (byte) (arg>>16);
756             m_ILStream[m_length++] = (byte) (arg>>24);
757             m_ILStream[m_length++] = (byte) (arg>>32);
758             m_ILStream[m_length++] = (byte) (arg>>40);
759             m_ILStream[m_length++] = (byte) (arg>>48);
760             m_ILStream[m_length++] = (byte) (arg>>56);
761         }
762
763         [System.Security.SecuritySafeCritical]  // auto-generated
764         unsafe public virtual void Emit(OpCode opcode, float arg) {
765             EnsureCapacity(7);
766             InternalEmit(opcode);
767             uint tempVal = *(uint*)&arg;
768             m_ILStream[m_length++] = (byte) tempVal;
769             m_ILStream[m_length++] = (byte) (tempVal>>8);
770             m_ILStream[m_length++] = (byte) (tempVal>>16);
771             m_ILStream[m_length++] = (byte) (tempVal>>24);
772         }
773
774         [System.Security.SecuritySafeCritical]  // auto-generated
775         unsafe public virtual void Emit(OpCode opcode, double arg) {
776             EnsureCapacity(11);
777             InternalEmit(opcode);
778             ulong tempVal = *(ulong*)&arg;           
779             m_ILStream[m_length++] = (byte) tempVal;
780             m_ILStream[m_length++] = (byte) (tempVal>>8);
781             m_ILStream[m_length++] = (byte) (tempVal>>16);
782             m_ILStream[m_length++] = (byte) (tempVal>>24);
783             m_ILStream[m_length++] = (byte) (tempVal>>32);
784             m_ILStream[m_length++] = (byte) (tempVal>>40);
785             m_ILStream[m_length++] = (byte) (tempVal>>48);
786             m_ILStream[m_length++] = (byte) (tempVal>>56);
787         }
788
789         public virtual void Emit(OpCode opcode, Label label) 
790         {
791             // Puts opcode onto the stream and leaves space to include label
792             // when fixups are done.  Labels are created using ILGenerator.DefineLabel and
793             // their location within the stream is fixed by using ILGenerator.MarkLabel.
794             // If a single-byte instruction (designated by the _S suffix in OpCodes.cs) is used,
795             // the label can represent a jump of at most 127 bytes along the stream.
796             //
797             // opcode must represent a branch instruction (although we don't explicitly
798             // verify this).  Since branches are relative instructions, label will be replaced with the
799             // correct offset to branch during the fixup process.
800             
801             int tempVal = label.GetLabelValue();
802             EnsureCapacity(7);
803
804              
805             InternalEmit(opcode);
806             if (OpCodes.TakesSingleByteArgument(opcode)) {
807                 AddFixup(label, m_length, 1);
808                 m_length++;
809             } else {
810                 AddFixup(label, m_length, 4);
811                 m_length+=4;
812             }
813         }
814
815         public virtual void Emit(OpCode opcode, Label[] labels)
816         {
817             if (labels == null)
818                 throw new ArgumentNullException("labels");
819             Contract.EndContractBlock();
820
821             // Emitting a switch table
822
823             int i;
824             int remaining;                  // number of bytes remaining for this switch instruction to be substracted
825             // for computing the offset
826
827             int count = labels.Length;
828
829             EnsureCapacity( count * 4 + 7 );
830             InternalEmit(opcode);
831             PutInteger4(count);
832             for ( remaining = count * 4, i = 0; remaining > 0; remaining -= 4, i++ ) {
833                 AddFixup( labels[i], m_length, remaining );
834                 m_length += 4;
835             }
836         }
837
838         public virtual void Emit(OpCode opcode, FieldInfo field)
839         {
840             ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
841             int tempVal = modBuilder.GetFieldToken( field ).Token;
842             EnsureCapacity(7);
843             InternalEmit(opcode);
844             RecordTokenFixup();
845             PutInteger4(tempVal);
846         }
847
848         public virtual void Emit(OpCode opcode, String str) 
849         {
850             // Puts the opcode onto the IL stream followed by the metadata token
851             // represented by str.  The location of str is recorded for future
852             // fixups if the module is persisted to a PE.
853
854             ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
855             int tempVal = modBuilder.GetStringConstant(str).Token;
856             EnsureCapacity(7);
857             InternalEmit(opcode);
858             PutInteger4(tempVal);
859         }
860
861         public virtual void Emit(OpCode opcode, LocalBuilder local)
862         {
863             // Puts the opcode onto the IL stream followed by the information for local variable local.
864
865             if (local == null)
866             {
867                 throw new ArgumentNullException("local");
868             }
869             Contract.EndContractBlock();
870             int tempVal = local.GetLocalIndex();
871             if (local.GetMethodBuilder() != m_methodBuilder)
872             {
873                 throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchedMethodForLocal"), "local");
874             }
875             // If the instruction is a ldloc, ldloca a stloc, morph it to the optimal form.
876             if (opcode.Equals(OpCodes.Ldloc))
877             {
878                 switch(tempVal)
879                 {
880                     case 0:
881                         opcode = OpCodes.Ldloc_0;
882                         break;
883                     case 1:
884                         opcode = OpCodes.Ldloc_1;
885                         break;
886                     case 2:
887                         opcode = OpCodes.Ldloc_2;
888                         break;
889                     case 3:
890                         opcode = OpCodes.Ldloc_3;
891                         break;
892                     default:
893                         if (tempVal <= 255)
894                             opcode = OpCodes.Ldloc_S;
895                         break;
896                 }
897             }
898             else if (opcode.Equals(OpCodes.Stloc))
899             {
900                 switch(tempVal)
901                 {
902                     case 0:
903                         opcode = OpCodes.Stloc_0;
904                         break;
905                     case 1:
906                         opcode = OpCodes.Stloc_1;
907                         break;
908                     case 2:
909                         opcode = OpCodes.Stloc_2;
910                         break;
911                     case 3:
912                         opcode = OpCodes.Stloc_3;
913                         break;
914                     default:
915                         if (tempVal <= 255)
916                             opcode = OpCodes.Stloc_S;
917                         break;
918                 }
919             }
920             else if (opcode.Equals(OpCodes.Ldloca))
921             {
922                 if (tempVal <= 255)
923                     opcode = OpCodes.Ldloca_S;
924             }
925
926             EnsureCapacity(7);
927             InternalEmit(opcode);
928              
929             if (opcode.OperandType == OperandType.InlineNone)
930                 return;
931             else if (!OpCodes.TakesSingleByteArgument(opcode))
932             {
933                 m_ILStream[m_length++]=(byte) tempVal;
934                 m_ILStream[m_length++]=(byte) (tempVal>>8);
935             }
936             else
937             {
938                 //Handle stloc_1, ldloc_1
939                 if (tempVal > Byte.MaxValue)
940                 {
941                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadInstructionOrIndexOutOfBound"));
942                 }
943                 m_ILStream[m_length++]=(byte)tempVal;
944             }
945         }
946         #endregion
947
948         #region Exceptions
949         public virtual Label BeginExceptionBlock() 
950         {
951             // Begin an Exception block.  Creating an Exception block records some information,
952             // but does not actually emit any IL onto the stream.  Exceptions should be created and
953             // marked in the following form:
954             //
955             // Emit Some IL
956             // BeginExceptionBlock
957             // Emit the IL which should appear within the "try" block
958             // BeginCatchBlock
959             // Emit the IL which should appear within the "catch" block
960             // Optional: BeginCatchBlock (this can be repeated an arbitrary number of times
961             // EndExceptionBlock
962
963             // Delay init
964             if (m_exceptions == null)
965             {
966                 m_exceptions = new __ExceptionInfo[DefaultExceptionArraySize];
967             }
968
969             if (m_currExcStack == null)
970             {
971                 m_currExcStack = new __ExceptionInfo[DefaultExceptionArraySize];
972             }
973
974             if (m_exceptionCount>=m_exceptions.Length) {
975                 m_exceptions=EnlargeArray(m_exceptions);
976             }
977
978             if (m_currExcStackCount>=m_currExcStack.Length) {
979                 m_currExcStack = EnlargeArray(m_currExcStack);
980             }
981
982             Label endLabel = DefineLabel();
983             __ExceptionInfo exceptionInfo = new __ExceptionInfo(m_length, endLabel);
984
985             // add the exception to the tracking list
986             m_exceptions[m_exceptionCount++] = exceptionInfo;
987
988             // Make this exception the current active exception
989             m_currExcStack[m_currExcStackCount++] = exceptionInfo;
990             return endLabel;
991         }
992
993         public virtual void EndExceptionBlock() {
994             if (m_currExcStackCount==0) {
995                 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
996             }
997
998            // Pop the current exception block
999             __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1000             m_currExcStack[m_currExcStackCount-1] = null;
1001             m_currExcStackCount--;
1002
1003             Label endLabel = current.GetEndLabel();
1004             int state = current.GetCurrentState();
1005
1006             if (state == __ExceptionInfo.State_Filter ||
1007                 state == __ExceptionInfo.State_Try)
1008             {
1009                  
1010                  
1011                 throw new InvalidOperationException(Environment.GetResourceString("Argument_BadExceptionCodeGen"));
1012             }
1013
1014             if (state == __ExceptionInfo.State_Catch) {
1015                 this.Emit(OpCodes.Leave, endLabel);
1016             } else if (state == __ExceptionInfo.State_Finally || state == __ExceptionInfo.State_Fault) {
1017                 this.Emit(OpCodes.Endfinally);
1018             }
1019
1020             //Check if we've alredy set this label.
1021             //The only reason why we might have set this is if we have a finally block.
1022             if (m_labelList[endLabel.GetLabelValue()]==-1) {
1023                 MarkLabel(endLabel);
1024             } else {
1025                 MarkLabel(current.GetFinallyEndLabel());
1026             }
1027
1028             current.Done(m_length);
1029         }
1030
1031         public virtual void BeginExceptFilterBlock() 
1032         {
1033             // Begins a eception filter block.  Emits a branch instruction to the end of the current exception block.
1034
1035             if (m_currExcStackCount == 0)
1036                 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1037
1038             __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1039
1040             Label endLabel = current.GetEndLabel();
1041             this.Emit(OpCodes.Leave, endLabel);
1042
1043             current.MarkFilterAddr(m_length);
1044         }
1045
1046         public virtual void BeginCatchBlock(Type exceptionType) 
1047         {
1048             // Begins a catch block.  Emits a branch instruction to the end of the current exception block.
1049
1050             if (m_currExcStackCount==0) {
1051                 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1052             }
1053             __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1054
1055             if (current.GetCurrentState() == __ExceptionInfo.State_Filter) {
1056                 if (exceptionType != null) {
1057                     throw new ArgumentException(Environment.GetResourceString("Argument_ShouldNotSpecifyExceptionType"));
1058                 }
1059
1060                 this.Emit(OpCodes.Endfilter);
1061             } else {
1062                 // execute this branch if previous clause is Catch or Fault
1063                 if (exceptionType==null) {
1064                     throw new ArgumentNullException("exceptionType");
1065                 }
1066
1067                 Label endLabel = current.GetEndLabel();
1068                 this.Emit(OpCodes.Leave, endLabel);
1069
1070             }
1071
1072             current.MarkCatchAddr(m_length, exceptionType);
1073         }
1074
1075         public virtual void BeginFaultBlock()
1076         {
1077             if (m_currExcStackCount==0) {
1078                 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1079             }
1080             __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1081
1082             // emit the leave for the clause before this one.
1083             Label endLabel = current.GetEndLabel();
1084             this.Emit(OpCodes.Leave, endLabel);
1085
1086             current.MarkFaultAddr(m_length);
1087         }
1088
1089         public virtual void BeginFinallyBlock() 
1090         {
1091             if (m_currExcStackCount==0) {
1092                 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1093             }
1094             __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1095             int         state = current.GetCurrentState();
1096             Label       endLabel = current.GetEndLabel();
1097             int         catchEndAddr = 0;
1098             if (state != __ExceptionInfo.State_Try)
1099             {
1100                 // generate leave for any preceeding catch clause
1101                 this.Emit(OpCodes.Leave, endLabel);                
1102                 catchEndAddr = m_length;
1103             }
1104             
1105             MarkLabel(endLabel);
1106
1107
1108             Label finallyEndLabel = this.DefineLabel();
1109             current.SetFinallyEndLabel(finallyEndLabel);
1110             
1111             // generate leave for try clause                                                  
1112             this.Emit(OpCodes.Leave, finallyEndLabel);
1113             if (catchEndAddr == 0)
1114                 catchEndAddr = m_length;
1115             current.MarkFinallyAddr(m_length, catchEndAddr);
1116         }
1117
1118         #endregion
1119
1120         #region Labels
1121         public virtual Label DefineLabel() 
1122         {
1123             // Declares a new Label.  This is just a token and does not yet represent any particular location
1124             // within the stream.  In order to set the position of the label within the stream, you must call
1125             // Mark Label.
1126
1127             // Delay init the lable array in case we dont use it
1128             if (m_labelList == null){
1129                 m_labelList = new int[DefaultLabelArraySize];
1130             }
1131
1132             if (m_labelCount>=m_labelList.Length) {
1133                 m_labelList = EnlargeArray(m_labelList);
1134             }
1135             m_labelList[m_labelCount]=-1;
1136             return new Label(m_labelCount++);
1137         }
1138
1139         public virtual void MarkLabel(Label loc) 
1140         {
1141             // Defines a label by setting the position where that label is found within the stream.
1142             // Does not allow a label to be defined more than once.
1143
1144             int labelIndex = loc.GetLabelValue();
1145
1146             //This should never happen.
1147             if (labelIndex<0 || labelIndex>=m_labelList.Length) {
1148                 throw new ArgumentException (Environment.GetResourceString("Argument_InvalidLabel"));
1149             }
1150
1151             if (m_labelList[labelIndex]!=-1) {
1152                 throw new ArgumentException (Environment.GetResourceString("Argument_RedefinedLabel"));
1153             }
1154
1155             m_labelList[labelIndex]=m_length;
1156         }
1157
1158         #endregion
1159
1160         #region IL Macros
1161         public virtual void ThrowException(Type excType)
1162         {
1163             // Emits the il to throw an exception
1164
1165             if (excType==null) {
1166                 throw new ArgumentNullException("excType");
1167             }
1168
1169             if (!excType.IsSubclassOf(typeof(Exception)) && excType!=typeof(Exception)) {
1170                 throw new ArgumentException(Environment.GetResourceString("Argument_NotExceptionType"));
1171             }
1172             Contract.EndContractBlock();
1173             ConstructorInfo con = excType.GetConstructor(Type.EmptyTypes);
1174             if (con==null) {
1175                 throw new ArgumentException(Environment.GetResourceString("Argument_MissingDefaultConstructor"));
1176             }
1177             this.Emit(OpCodes.Newobj, con);
1178             this.Emit(OpCodes.Throw);
1179         }
1180
1181         public virtual void EmitWriteLine(String value)
1182         {
1183             // Emits the IL to call Console.WriteLine with a string.
1184
1185             Emit(OpCodes.Ldstr, value);
1186             Type[] parameterTypes = new Type[1];
1187             parameterTypes[0] = typeof(String);
1188             MethodInfo mi = typeof(Console).GetMethod("WriteLine", parameterTypes);
1189             Emit(OpCodes.Call, mi);
1190         }
1191
1192         public virtual void EmitWriteLine(LocalBuilder localBuilder) 
1193         {
1194             // Emits the IL necessary to call WriteLine with lcl.  It is
1195             // an error to call EmitWriteLine with a lcl which is not of
1196             // one of the types for which Console.WriteLine implements overloads. (e.g.
1197             // we do *not* call ToString on the locals.
1198
1199             Object          cls;
1200             if (m_methodBuilder==null)
1201             {
1202                 throw new ArgumentException(Environment.GetResourceString("InvalidOperation_BadILGeneratorUsage"));
1203             }
1204
1205             MethodInfo prop = typeof(Console).GetMethod("get_Out");
1206             Emit(OpCodes.Call, prop);
1207             Emit(OpCodes.Ldloc, localBuilder);
1208             Type[] parameterTypes = new Type[1];
1209             cls = localBuilder.LocalType;
1210             if (cls is TypeBuilder || cls is EnumBuilder) {
1211                 throw new ArgumentException(Environment.GetResourceString("NotSupported_OutputStreamUsingTypeBuilder"));
1212             }
1213             parameterTypes[0] = (Type)cls;
1214             MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
1215              if (mi==null) {
1216                 throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "localBuilder");
1217             }
1218
1219             Emit(OpCodes.Callvirt, mi);
1220         }
1221
1222         public virtual void EmitWriteLine(FieldInfo fld)
1223         {
1224             // Emits the IL necessary to call WriteLine with fld.  It is
1225             // an error to call EmitWriteLine with a fld which is not of
1226             // one of the types for which Console.WriteLine implements overloads. (e.g.
1227             // we do *not* call ToString on the fields.
1228
1229             Object cls;
1230
1231             if (fld == null)
1232             {
1233                 throw new ArgumentNullException("fld");
1234             }
1235             Contract.EndContractBlock();
1236             
1237             MethodInfo prop = typeof(Console).GetMethod("get_Out");
1238             Emit(OpCodes.Call, prop);
1239
1240             if ((fld.Attributes & FieldAttributes.Static)!=0) {
1241                 Emit(OpCodes.Ldsfld, fld);
1242             } else {
1243                 Emit(OpCodes.Ldarg, (short)0); //Load the this ref.
1244                 Emit(OpCodes.Ldfld, fld);
1245             }
1246             Type[] parameterTypes = new Type[1];
1247             cls = fld.FieldType;
1248             if (cls is TypeBuilder || cls is EnumBuilder) {
1249                 throw new NotSupportedException(Environment.GetResourceString("NotSupported_OutputStreamUsingTypeBuilder"));
1250             }
1251             parameterTypes[0] = (Type)cls;
1252             MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
1253             if (mi==null) {
1254                 throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "fld");
1255             }
1256             Emit(OpCodes.Callvirt, mi);
1257         }
1258
1259         #endregion
1260
1261         #region Debug API
1262         public virtual LocalBuilder DeclareLocal(Type localType)
1263         {
1264             return DeclareLocal(localType, false);
1265         }
1266
1267         public virtual LocalBuilder DeclareLocal(Type localType, bool pinned)
1268         {
1269             // Declare a local of type "local". The current active lexical scope
1270             // will be the scope that local will live.
1271
1272             LocalBuilder    localBuilder;
1273
1274             MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
1275             if (methodBuilder == null) 
1276                 throw new NotSupportedException();
1277
1278             if (methodBuilder.IsTypeCreated())
1279             {
1280                 // cannot change method after its containing type has been created
1281                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TypeHasBeenCreated"));
1282             }
1283
1284             if (localType==null) {
1285                 throw new ArgumentNullException("localType");
1286             }
1287
1288             if (methodBuilder.m_bIsBaked) {
1289                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBaked"));
1290             }
1291
1292             // add the localType to local signature
1293             m_localSignature.AddArgument(localType, pinned);
1294
1295             localBuilder = new LocalBuilder(m_localCount, localType, methodBuilder, pinned);
1296             m_localCount++;
1297             return localBuilder;
1298         }
1299
1300         public virtual void UsingNamespace(String usingNamespace)
1301         {
1302             // Specifying the namespace to be used in evaluating locals and watches
1303             // for the current active lexical scope.
1304
1305             if (usingNamespace == null)
1306                 throw new ArgumentNullException("usingNamespace");
1307
1308             if (usingNamespace.Length == 0)
1309                 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "usingNamespace");
1310             Contract.EndContractBlock();
1311
1312             int index;
1313             MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
1314             if (methodBuilder == null) 
1315                 throw new NotSupportedException();
1316
1317             index = methodBuilder.GetILGenerator().m_ScopeTree.GetCurrentActiveScopeIndex();
1318             if (index == -1)
1319             {
1320                 methodBuilder.m_localSymInfo.AddUsingNamespace(usingNamespace);
1321             }
1322             else
1323             {
1324                 m_ScopeTree.AddUsingNamespaceToCurrentScope(usingNamespace);
1325             }
1326         }
1327
1328         public virtual void MarkSequencePoint(
1329             ISymbolDocumentWriter document,
1330             int startLine,       // line number is 1 based
1331             int startColumn,     // column is 0 based
1332             int endLine,         // line number is 1 based
1333             int endColumn)       // column is 0 based
1334         {
1335             if (startLine == 0 || startLine < 0 || endLine == 0 || endLine < 0)
1336             {
1337                 throw new ArgumentOutOfRangeException("startLine");
1338             }
1339             Contract.EndContractBlock();
1340             m_LineNumberInfo.AddLineNumberInfo(document, m_length, startLine, startColumn, endLine, endColumn);
1341         }
1342
1343         public virtual void BeginScope()
1344         {
1345             m_ScopeTree.AddScopeInfo(ScopeAction.Open, m_length);
1346         }
1347
1348         public virtual void EndScope()
1349         {
1350             m_ScopeTree.AddScopeInfo(ScopeAction.Close, m_length);
1351         }
1352
1353         public virtual int ILOffset
1354         {
1355             get
1356             {
1357                 return m_length;
1358             }
1359         }
1360
1361         #endregion
1362
1363         #endregion
1364
1365 #if !FEATURE_CORECLR
1366         void _ILGenerator.GetTypeInfoCount(out uint pcTInfo)
1367         {
1368             throw new NotImplementedException();
1369         }
1370
1371         void _ILGenerator.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
1372         {
1373             throw new NotImplementedException();
1374         }
1375
1376         void _ILGenerator.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1377         {
1378             throw new NotImplementedException();
1379         }
1380
1381         void _ILGenerator.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1382         {
1383             throw new NotImplementedException();
1384         }
1385 #endif
1386     }
1387
1388     internal struct __FixupData
1389     {
1390         internal Label m_fixupLabel;
1391         internal int m_fixupPos;
1392          
1393         internal int m_fixupInstSize;
1394     }
1395
1396     internal sealed class __ExceptionInfo {
1397
1398         internal const int None             = 0x0000;  //COR_ILEXCEPTION_CLAUSE_NONE
1399         internal const int Filter           = 0x0001;  //COR_ILEXCEPTION_CLAUSE_FILTER
1400         internal const int Finally          = 0x0002;  //COR_ILEXCEPTION_CLAUSE_FINALLY
1401         internal const int Fault            = 0x0004;  //COR_ILEXCEPTION_CLAUSE_FAULT
1402         internal const int PreserveStack    = 0x0004;  //COR_ILEXCEPTION_CLAUSE_PRESERVESTACK
1403
1404         internal const int State_Try = 0;
1405         internal const int State_Filter =1;
1406         internal const int State_Catch = 2;
1407         internal const int State_Finally = 3;
1408         internal const int State_Fault = 4;
1409         internal const int State_Done = 5;
1410
1411         internal int m_startAddr;
1412         internal int []m_filterAddr;
1413         internal int []m_catchAddr;
1414         internal int []m_catchEndAddr;
1415         internal int []m_type;
1416         internal Type []m_catchClass;
1417         internal Label m_endLabel;
1418         internal Label m_finallyEndLabel;
1419         internal int m_endAddr;
1420         internal int m_endFinally;
1421         internal int m_currentCatch;
1422
1423         int m_currentState;
1424
1425
1426         //This will never get called.  The values exist merely to keep the
1427         //compiler happy.
1428         private __ExceptionInfo() {
1429             m_startAddr = 0;
1430             m_filterAddr = null;
1431             m_catchAddr = null;
1432             m_catchEndAddr = null;
1433             m_endAddr = 0;
1434             m_currentCatch = 0;
1435             m_type = null;
1436             m_endFinally = -1;
1437             m_currentState = State_Try;
1438         }
1439
1440         internal __ExceptionInfo(int startAddr, Label endLabel) {
1441             m_startAddr=startAddr;
1442             m_endAddr=-1;
1443             m_filterAddr=new int[4];
1444             m_catchAddr=new int[4];
1445             m_catchEndAddr=new int[4];
1446             m_catchClass=new Type[4];
1447             m_currentCatch=0;
1448             m_endLabel=endLabel;
1449             m_type=new int[4];
1450             m_endFinally=-1;
1451             m_currentState = State_Try;
1452         }
1453
1454         private static Type[] EnlargeArray(Type[] incoming)
1455         {
1456             Type[] temp = new Type[incoming.Length * 2];
1457             Array.Copy(incoming, temp, incoming.Length);
1458             return temp;
1459         }
1460
1461         private void MarkHelper(
1462             int         catchorfilterAddr,      // the starting address of a clause
1463             int         catchEndAddr,           // the end address of a previous catch clause. Only use when finally is following a catch
1464             Type        catchClass,             // catch exception type
1465             int         type)                   // kind of clause
1466         {
1467             if (m_currentCatch>=m_catchAddr.Length) {
1468                 m_filterAddr=ILGenerator.EnlargeArray(m_filterAddr);
1469                 m_catchAddr=ILGenerator.EnlargeArray(m_catchAddr);
1470                 m_catchEndAddr=ILGenerator.EnlargeArray(m_catchEndAddr);
1471                 m_catchClass=__ExceptionInfo.EnlargeArray(m_catchClass);
1472                 m_type = ILGenerator.EnlargeArray(m_type);
1473             }
1474             if (type == Filter)
1475             {
1476                 m_type[m_currentCatch]=type;
1477                 m_filterAddr[m_currentCatch] = catchorfilterAddr;
1478                 m_catchAddr[m_currentCatch] = -1;
1479                 if (m_currentCatch > 0)
1480                 {
1481                     Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
1482                     m_catchEndAddr[m_currentCatch-1] = catchorfilterAddr;
1483                 }
1484             }
1485             else
1486             {
1487                 // catch or Fault clause
1488                 m_catchClass[m_currentCatch]=catchClass;
1489                 if (m_type[m_currentCatch] != Filter)
1490                 {
1491                     m_type[m_currentCatch]=type;
1492                 }
1493                 m_catchAddr[m_currentCatch]=catchorfilterAddr;
1494                 if (m_currentCatch > 0)
1495                 {
1496                         if (m_type[m_currentCatch] != Filter)
1497                         {
1498                             Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
1499                             m_catchEndAddr[m_currentCatch-1] = catchEndAddr;
1500                         }
1501                 }
1502                 m_catchEndAddr[m_currentCatch]=-1;  
1503                 m_currentCatch++;
1504             }
1505
1506             if (m_endAddr==-1)
1507             {
1508                 m_endAddr=catchorfilterAddr;
1509             }
1510         }
1511
1512         internal void MarkFilterAddr(int filterAddr)
1513         {
1514             m_currentState = State_Filter;
1515             MarkHelper(filterAddr, filterAddr, null, Filter);
1516         }
1517
1518         internal void MarkFaultAddr(int faultAddr)
1519         {
1520             m_currentState = State_Fault;
1521             MarkHelper(faultAddr, faultAddr, null, Fault);
1522         }
1523
1524         internal void MarkCatchAddr(int catchAddr, Type catchException) {
1525             m_currentState = State_Catch;
1526             MarkHelper(catchAddr, catchAddr, catchException, None);
1527         }
1528
1529         internal void MarkFinallyAddr(int finallyAddr, int endCatchAddr) {
1530             if (m_endFinally!=-1) {
1531                 throw new ArgumentException(Environment.GetResourceString("Argument_TooManyFinallyClause"));
1532             } else {
1533                 m_currentState = State_Finally;
1534                 m_endFinally=finallyAddr;
1535             }
1536             MarkHelper(finallyAddr, endCatchAddr, null, Finally);
1537         }
1538
1539         internal void Done(int endAddr) {
1540             Contract.Assert(m_currentCatch > 0,"m_currentCatch > 0");
1541             Contract.Assert(m_catchAddr[m_currentCatch-1] > 0,"m_catchAddr[m_currentCatch-1] > 0");
1542             Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
1543             m_catchEndAddr[m_currentCatch-1] = endAddr;
1544             m_currentState = State_Done;
1545         }
1546
1547         internal int GetStartAddress() {
1548             return m_startAddr;
1549         }
1550
1551         internal int GetEndAddress() {
1552             return m_endAddr;
1553         }
1554
1555         internal int GetFinallyEndAddress() {
1556             return m_endFinally;
1557         }
1558
1559         internal Label GetEndLabel() {
1560             return m_endLabel;
1561         }
1562
1563         internal int [] GetFilterAddresses() {
1564             return m_filterAddr;
1565         }
1566
1567         internal int [] GetCatchAddresses() {
1568             return m_catchAddr;
1569         }
1570
1571         internal int [] GetCatchEndAddresses() {
1572             return m_catchEndAddr;
1573         }
1574
1575         internal Type [] GetCatchClass() {
1576             return m_catchClass;
1577         }
1578
1579         internal int GetNumberOfCatches() {
1580             return m_currentCatch;
1581         }
1582
1583         internal int[] GetExceptionTypes() {
1584             return m_type;
1585         }
1586
1587         internal void SetFinallyEndLabel(Label lbl) {
1588             m_finallyEndLabel=lbl;
1589         }
1590
1591         internal Label GetFinallyEndLabel() {
1592             return m_finallyEndLabel;
1593         }
1594
1595         // Specifies whether exc is an inner exception for "this".  The way
1596         // its determined is by comparing the end address for the last catch
1597         // clause for both exceptions.  If they're the same, the start address
1598         // for the exception is compared.
1599         // WARNING: This is not a generic function to determine the innerness
1600         // of an exception.  This is somewhat of a mis-nomer.  This gives a
1601         // random result for cases where the two exceptions being compared do
1602         // not having a nesting relation. 
1603         internal bool IsInner(__ExceptionInfo exc) {
1604             Contract.Requires(exc != null);
1605             Contract.Assert(m_currentCatch > 0,"m_currentCatch > 0");
1606             Contract.Assert(exc.m_currentCatch > 0,"exc.m_currentCatch > 0");
1607
1608             int exclast = exc.m_currentCatch - 1;
1609             int last = m_currentCatch - 1;
1610
1611             if (exc.m_catchEndAddr[exclast]  < m_catchEndAddr[last])
1612                 return true;
1613             else if (exc.m_catchEndAddr[exclast] == m_catchEndAddr[last])
1614             {
1615                 Contract.Assert(exc.GetEndAddress() != GetEndAddress(),
1616                                 "exc.GetEndAddress() != GetEndAddress()");
1617                 if (exc.GetEndAddress() > GetEndAddress())
1618                     return true;
1619             }
1620             return false;
1621         }
1622
1623         // 0 indicates in a try block
1624         // 1 indicates in a filter block
1625         // 2 indicates in a catch block
1626         // 3 indicates in a finally block
1627         // 4 indicates Done
1628         internal int GetCurrentState() {
1629             return m_currentState;
1630         }
1631     }
1632
1633
1634     /***************************
1635     *
1636     * Scope Tree is a class that track the scope structure within a method body
1637     * It keeps track two parallel array. m_ScopeAction keeps track the action. It can be
1638     * OpenScope or CloseScope. m_iOffset records the offset where the action
1639     * takes place.
1640     *
1641     ***************************/
1642     [Serializable]
1643     enum ScopeAction
1644     {
1645         Open        = 0x0,
1646         Close       = 0x1,
1647     }
1648
1649     internal sealed class ScopeTree
1650     {
1651         internal ScopeTree()
1652         {
1653             // initialize data variables
1654             m_iOpenScopeCount = 0;
1655             m_iCount = 0;
1656         }
1657
1658         /***************************
1659         *
1660         * Find the current active lexcial scope. For example, if we have
1661         * "Open Open Open Close",
1662         * we will return 1 as the second BeginScope is currently active.
1663         *
1664         ***************************/
1665         internal int GetCurrentActiveScopeIndex()
1666         {
1667             int         cClose = 0;
1668             int         i = m_iCount - 1;
1669
1670             if (m_iCount == 0)
1671             {
1672                 return -1;
1673             }
1674             for (; cClose > 0 || m_ScopeActions[i] == ScopeAction.Close; i--)
1675             {
1676                 if (m_ScopeActions[i] == ScopeAction.Open)
1677                 {
1678                     cClose--;
1679                 }
1680                 else
1681                     cClose++;
1682             }
1683
1684             return i;
1685         }
1686
1687         internal void AddLocalSymInfoToCurrentScope(
1688             String          strName,
1689             byte[]          signature,
1690             int             slot,
1691             int             startOffset,
1692             int             endOffset)
1693         {
1694             int         i = GetCurrentActiveScopeIndex();
1695             if (m_localSymInfos[i] == null)
1696             {
1697                 m_localSymInfos[i] = new LocalSymInfo();
1698             }
1699             m_localSymInfos[i].AddLocalSymInfo(strName, signature, slot, startOffset, endOffset);
1700         }
1701
1702         internal void AddUsingNamespaceToCurrentScope(
1703             String          strNamespace)
1704         {
1705             int         i = GetCurrentActiveScopeIndex();
1706             if (m_localSymInfos[i] == null)
1707             {
1708                 m_localSymInfos[i] = new LocalSymInfo();
1709             }
1710             m_localSymInfos[i].AddUsingNamespace(strNamespace);
1711         }
1712
1713         internal void AddScopeInfo(ScopeAction sa, int iOffset)
1714         {
1715             if (sa == ScopeAction.Close && m_iOpenScopeCount <=0)
1716             {
1717                 throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchingSymScope"));
1718             }
1719             Contract.EndContractBlock();
1720
1721             // make sure that arrays are large enough to hold addition info
1722             EnsureCapacity();             
1723              
1724              
1725             m_ScopeActions[m_iCount] = sa;
1726             m_iOffsets[m_iCount] = iOffset;
1727             m_localSymInfos[m_iCount] = null;
1728             checked { m_iCount++; }
1729             if (sa == ScopeAction.Open)
1730             {
1731                 m_iOpenScopeCount++;
1732             }
1733             else
1734                 m_iOpenScopeCount--;
1735
1736         }
1737
1738         /**************************
1739         *
1740         * Helper to ensure arrays are large enough
1741         *
1742         **************************/
1743         internal void EnsureCapacity()
1744         {
1745             if (m_iCount == 0)
1746             {
1747                 // First time. Allocate the arrays.
1748                 m_iOffsets = new int[InitialSize];
1749                 m_ScopeActions = new ScopeAction[InitialSize];
1750                 m_localSymInfos = new LocalSymInfo[InitialSize];
1751             }
1752             else if (m_iCount == m_iOffsets.Length)
1753             {
1754                 // the arrays are full. Enlarge the arrays
1755                 // It would probably be simpler to just use Lists here.
1756                 int newSize = checked(m_iCount * 2);
1757                 int[] temp = new int[newSize];
1758                 Array.Copy(m_iOffsets, temp, m_iCount);
1759                 m_iOffsets = temp;
1760
1761                 ScopeAction[] tempSA = new ScopeAction[newSize];
1762                 Array.Copy(m_ScopeActions, tempSA, m_iCount);
1763                 m_ScopeActions = tempSA;
1764
1765                 LocalSymInfo[] tempLSI = new LocalSymInfo[newSize];
1766                 Array.Copy(m_localSymInfos, tempLSI, m_iCount);
1767                 m_localSymInfos = tempLSI;
1768             }
1769         }
1770
1771         #if FEATURE_CORECLR
1772         [System.Security.SecurityCritical] // auto-generated
1773         #endif
1774         internal void EmitScopeTree(ISymbolWriter symWriter)
1775         {
1776             int         i;
1777             for (i = 0; i < m_iCount; i++)
1778             {
1779                 if (m_ScopeActions[i] == ScopeAction.Open)
1780                 {
1781                     symWriter.OpenScope(m_iOffsets[i]);
1782                 }
1783                 else
1784                 {
1785                     symWriter.CloseScope(m_iOffsets[i]);
1786                 }
1787                 if (m_localSymInfos[i] != null)
1788                 {
1789                     m_localSymInfos[i].EmitLocalSymInfo(symWriter);
1790                 }
1791             }
1792         }
1793
1794         internal int[]          m_iOffsets;                 // array of offsets
1795         internal ScopeAction[]  m_ScopeActions;             // array of scope actions
1796         internal int            m_iCount;                   // how many entries in the arrays are occupied
1797         internal int            m_iOpenScopeCount;          // keep track how many scopes are open
1798         internal const int      InitialSize = 16;
1799         internal LocalSymInfo[] m_localSymInfos;            // keep track debugging local information
1800     }
1801
1802
1803     /***************************
1804     *
1805     * This class tracks the line number info
1806     *
1807     ***************************/
1808     internal sealed class LineNumberInfo
1809     {
1810         internal LineNumberInfo()
1811         {
1812             // initialize data variables
1813             m_DocumentCount = 0;
1814             m_iLastFound = 0;
1815         }
1816
1817         internal void AddLineNumberInfo(
1818             ISymbolDocumentWriter document,
1819             int             iOffset,
1820             int             iStartLine,
1821             int             iStartColumn,
1822             int             iEndLine,
1823             int             iEndColumn)
1824         {
1825             int         i;
1826             
1827             // make sure that arrays are large enough to hold addition info
1828             i = FindDocument(document);
1829             
1830             Contract.Assert(i < m_DocumentCount, "Bad document look up!");
1831             m_Documents[i].AddLineNumberInfo(document, iOffset, iStartLine, iStartColumn, iEndLine, iEndColumn);
1832         }
1833         
1834         // Find a REDocument representing document. If we cannot find one, we will add a new entry into
1835         // the REDocument array.
1836         private int FindDocument(ISymbolDocumentWriter document)
1837         {
1838             int         i;
1839             
1840             // This is an optimization. The chance that the previous line is coming from the same
1841             // document is very high.
1842             if (m_iLastFound < m_DocumentCount && m_Documents[m_iLastFound].m_document == document)
1843                 return m_iLastFound;
1844                 
1845             for (i = 0; i < m_DocumentCount; i++)
1846             {
1847                 if (m_Documents[i].m_document == document)
1848                 {
1849                     m_iLastFound = i;
1850                     return m_iLastFound;
1851                 }
1852             }
1853             
1854             // cannot find an existing document so add one to the array                                       
1855             EnsureCapacity();
1856             m_iLastFound = m_DocumentCount;
1857             m_Documents[m_iLastFound] = new REDocument(document);
1858             checked { m_DocumentCount++; }
1859             return m_iLastFound;
1860         }
1861
1862         /**************************
1863         *
1864         * Helper to ensure arrays are large enough
1865         *
1866         **************************/
1867         private void EnsureCapacity()
1868         {
1869             if (m_DocumentCount == 0)
1870             {
1871                 // First time. Allocate the arrays.
1872                 m_Documents = new REDocument[InitialSize];
1873             }
1874             else if (m_DocumentCount == m_Documents.Length)
1875             {
1876                 // the arrays are full. Enlarge the arrays
1877                 REDocument[] temp = new REDocument [m_DocumentCount * 2];
1878                 Array.Copy(m_Documents, temp, m_DocumentCount);
1879                 m_Documents = temp;
1880             }
1881         }
1882
1883         #if FEATURE_CORECLR
1884         [System.Security.SecurityCritical] // auto-generated
1885         #endif
1886         internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1887         {
1888             for (int i = 0; i < m_DocumentCount; i++)
1889                 m_Documents[i].EmitLineNumberInfo(symWriter);
1890         }
1891
1892         private int          m_DocumentCount;         // how many documents that we have right now
1893         private REDocument[] m_Documents;             // array of documents
1894         private const int    InitialSize = 16;
1895         private int          m_iLastFound;
1896     }
1897
1898
1899     /***************************
1900     *
1901     * This class tracks the line number info
1902     *
1903     ***************************/
1904     internal sealed class REDocument
1905     {
1906         internal REDocument(ISymbolDocumentWriter document)
1907         {
1908             // initialize data variables
1909             m_iLineNumberCount = 0;
1910             m_document = document;
1911         }
1912
1913         internal void AddLineNumberInfo(
1914             ISymbolDocumentWriter document,
1915             int             iOffset,
1916             int             iStartLine,
1917             int             iStartColumn,
1918             int             iEndLine,
1919             int             iEndColumn)
1920         {
1921             Contract.Assert(document == m_document, "Bad document look up!");
1922             
1923             // make sure that arrays are large enough to hold addition info
1924             EnsureCapacity();
1925             
1926             m_iOffsets[m_iLineNumberCount] = iOffset;
1927             m_iLines[m_iLineNumberCount] = iStartLine;
1928             m_iColumns[m_iLineNumberCount] = iStartColumn;
1929             m_iEndLines[m_iLineNumberCount] = iEndLine;
1930             m_iEndColumns[m_iLineNumberCount] = iEndColumn;
1931             checked { m_iLineNumberCount++; }
1932         }
1933
1934         /**************************
1935         *
1936         * Helper to ensure arrays are large enough
1937         *
1938         **************************/
1939         private void EnsureCapacity()
1940         {
1941             if (m_iLineNumberCount == 0)
1942             {
1943                 // First time. Allocate the arrays.
1944                 m_iOffsets = new int[InitialSize];
1945                 m_iLines = new int[InitialSize];
1946                 m_iColumns = new int[InitialSize];
1947                 m_iEndLines = new int[InitialSize];
1948                 m_iEndColumns = new int[InitialSize];
1949             }
1950             else if (m_iLineNumberCount == m_iOffsets.Length)
1951             {            
1952                 // the arrays are full. Enlarge the arrays
1953                 // It would probably be simpler to just use Lists here
1954                 int newSize = checked(m_iLineNumberCount * 2);
1955                 int[] temp = new int [newSize];
1956                 Array.Copy(m_iOffsets, temp, m_iLineNumberCount);
1957                 m_iOffsets = temp;
1958
1959                 temp = new int [newSize];
1960                 Array.Copy(m_iLines, temp, m_iLineNumberCount);
1961                 m_iLines = temp;
1962
1963                 temp = new int [newSize];
1964                 Array.Copy(m_iColumns, temp, m_iLineNumberCount);
1965                 m_iColumns = temp;
1966
1967                 temp = new int [newSize];
1968                 Array.Copy(m_iEndLines, temp, m_iLineNumberCount);
1969                 m_iEndLines = temp;
1970
1971                 temp = new int [newSize];
1972                 Array.Copy(m_iEndColumns, temp, m_iLineNumberCount);
1973                 m_iEndColumns = temp;
1974             }
1975         }
1976
1977         #if FEATURE_CORECLR
1978         [System.Security.SecurityCritical] // auto-generated
1979         #endif
1980         internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1981         {
1982             int[]       iOffsetsTemp;
1983             int[]       iLinesTemp;
1984             int[]       iColumnsTemp;
1985             int[]       iEndLinesTemp;
1986             int[]       iEndColumnsTemp;
1987
1988             if (m_iLineNumberCount == 0)
1989                 return;
1990             // reduce the array size to be exact
1991             iOffsetsTemp = new int [m_iLineNumberCount];
1992             Array.Copy(m_iOffsets, iOffsetsTemp, m_iLineNumberCount);
1993
1994             iLinesTemp = new int [m_iLineNumberCount];
1995             Array.Copy(m_iLines, iLinesTemp, m_iLineNumberCount);
1996
1997             iColumnsTemp = new int [m_iLineNumberCount];
1998             Array.Copy(m_iColumns, iColumnsTemp, m_iLineNumberCount);
1999
2000             iEndLinesTemp = new int [m_iLineNumberCount];
2001             Array.Copy(m_iEndLines, iEndLinesTemp, m_iLineNumberCount);
2002
2003             iEndColumnsTemp = new int [m_iLineNumberCount];
2004             Array.Copy(m_iEndColumns, iEndColumnsTemp, m_iLineNumberCount);
2005
2006             symWriter.DefineSequencePoints(m_document, iOffsetsTemp, iLinesTemp, iColumnsTemp, iEndLinesTemp, iEndColumnsTemp); 
2007         }
2008
2009         private  int[]       m_iOffsets;                 // array of offsets
2010         private  int[]       m_iLines;                   // array of offsets
2011         private  int[]       m_iColumns;                 // array of offsets
2012         private  int[]       m_iEndLines;                // array of offsets
2013         private  int[]       m_iEndColumns;              // array of offsets
2014         internal ISymbolDocumentWriter m_document;       // The ISymbolDocumentWriter that this REDocument is tracking.
2015         private  int         m_iLineNumberCount;         // how many entries in the arrays are occupied
2016         private  const int   InitialSize = 16;
2017     }       // end of REDocument
2018 }