3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
9 namespace System.Reflection.Emit
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;
20 [ClassInterface(ClassInterfaceType.None)]
21 [ComDefaultInterface(typeof(_ILGenerator))]
22 [System.Runtime.InteropServices.ComVisible(true)]
23 public class ILGenerator : _ILGenerator
26 private const int defaultSize = 16;
27 private const int DefaultFixupArraySize = 8;
28 private const int DefaultLabelArraySize = 4;
29 private const int DefaultExceptionArraySize = 2;
32 #region Internal Statics
33 internal static int[] EnlargeArray(int[] incoming)
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);
43 private static byte[] EnlargeArray(byte[] incoming)
45 byte [] temp = new byte [incoming.Length*2];
46 Array.Copy(incoming, temp, incoming.Length);
50 private static byte[] EnlargeArray(byte[] incoming, int requiredSize)
52 byte [] temp = new byte [requiredSize];
53 Array.Copy(incoming, temp, incoming.Length);
57 private static __FixupData[] EnlargeArray(__FixupData[] incoming)
59 __FixupData [] temp = new __FixupData[incoming.Length*2];
60 //Does arraycopy work for value classes?
61 Array.Copy(incoming, temp, incoming.Length);
65 private static __ExceptionInfo[] EnlargeArray(__ExceptionInfo[] incoming)
67 __ExceptionInfo[] temp = new __ExceptionInfo[incoming.Length*2];
68 Array.Copy(incoming, temp, incoming.Length);
73 #region Internal Data Members
75 private byte[] m_ILStream;
77 private int[] m_labelList;
78 private int m_labelCount;
80 private __FixupData[] m_fixupData;
82 private int m_fixupCount;
84 private int[] m_RelocFixupList;
85 private int m_RelocFixupCount;
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.
92 internal ScopeTree m_ScopeTree; // this variable tracks all debugging scope information
93 internal LineNumberInfo m_LineNumberInfo; // this variable tracks all line number information
95 internal MethodInfo m_methodBuilder;
96 internal int m_localCount;
97 internal SignatureHelper m_localSignature;
99 private int m_maxStackSize = 0; // Maximum stack size not counting the exceptions.
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.
104 internal int CurrExcStackCount
106 get { return m_currExcStackCount; }
109 internal __ExceptionInfo[] CurrExcStack
111 get { return m_currExcStack; }
116 // package private constructor. This code path is used when client create
117 // ILGenerator through MethodBuilder.
118 internal ILGenerator(MethodInfo methodBuilder) : this(methodBuilder, 64)
122 internal ILGenerator(MethodInfo methodBuilder, int size)
124 Contract.Requires(methodBuilder != null);
125 Contract.Requires(methodBuilder is MethodBuilder || methodBuilder is DynamicMethod);
127 if (size < defaultSize)
129 m_ILStream = new byte[defaultSize];
133 m_ILStream = new byte[size];
145 m_exceptionCount = 0;
146 m_currExcStack = null;
147 m_currExcStackCount = 0;
149 m_RelocFixupList = null;
150 m_RelocFixupCount = 0;
152 // initialize the scope tree
153 m_ScopeTree = new ScopeTree();
154 m_LineNumberInfo = new LineNumberInfo();
155 m_methodBuilder = methodBuilder;
157 // initialize local signature
159 MethodBuilder mb = m_methodBuilder as MethodBuilder;
161 m_localSignature = SignatureHelper.GetLocalVarSigHelper(null);
163 m_localSignature = SignatureHelper.GetLocalVarSigHelper(mb.GetTypeBuilder().Module);
168 #region Internal Members
169 internal virtual void RecordTokenFixup()
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);
176 m_RelocFixupList[m_RelocFixupCount++] = m_length;
179 internal void InternalEmit(OpCode opcode)
181 if (opcode.Size != 1)
183 m_ILStream[m_length++] = (byte)(opcode.Value >> 8);
186 m_ILStream[m_length++] = (byte)opcode.Value;
188 UpdateStackSize(opcode, opcode.StackChange());
192 internal void UpdateStackSize(OpCode opcode, int stackchange)
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.
198 // Special case for the Return. Returns pops 1 if there is a
199 // non-void return value.
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;
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
214 if (opcode.EndsUncondJmpBlk())
216 m_maxStackSize += m_maxMidStack;
218 m_maxMidStackCur = 0;
222 [System.Security.SecurityCritical] // auto-generated
223 private int GetMethodToken(MethodBase method, Type[] optionalParameterTypes, bool useMethodDef)
225 return ((ModuleBuilder)m_methodBuilder.Module).GetMethodTokenInternal(method, optionalParameterTypes, useMethodDef);
228 [System.Security.SecurityCritical] // auto-generated
229 internal virtual SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType,
230 Type[] parameterTypes, Type[] optionalParameterTypes)
232 return GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, 0);
235 [System.Security.SecurityCritical] // auto-generated
236 private SignatureHelper GetMemberRefSignature(CallingConventions call, Type returnType,
237 Type[] parameterTypes, Type[] optionalParameterTypes, int cGenericParameters)
239 return ((ModuleBuilder)m_methodBuilder.Module).GetMemberRefSignature(call, returnType, parameterTypes, optionalParameterTypes, cGenericParameters);
242 internal byte[] BakeByteArray()
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.
251 if (m_currExcStackCount != 0)
253 throw new ArgumentException(Environment.GetResourceString("Argument_UnclosedExceptionBlock"));
258 //Calculate the size of the new array.
261 //Allocate space for the new array.
262 newBytes = new byte[newSize];
264 //Copy the data from the old array
265 Array.Copy(m_ILStream, newBytes, newSize);
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++)
272 updateAddr = GetLabelPos(m_fixupData[i].m_fixupLabel) - (m_fixupData[i].m_fixupPos + m_fixupData[i].m_fixupInstSize);
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)
279 //Verify that our one-byte arg will fit into a Signed Byte.
280 if (updateAddr < SByte.MinValue || updateAddr > SByte.MaxValue)
282 throw new NotSupportedException(Environment.GetResourceString("NotSupported_IllegalOneByteBranch",m_fixupData[i].m_fixupPos, updateAddr));
285 //Place the one-byte arg
288 newBytes[m_fixupData[i].m_fixupPos] = (byte)(256 + updateAddr);
292 newBytes[m_fixupData[i].m_fixupPos] = (byte)updateAddr;
297 //Place the four-byte arg
298 PutInteger4InArray(updateAddr, m_fixupData[i].m_fixupPos, newBytes);
304 internal __ExceptionInfo[] GetExceptions()
306 __ExceptionInfo []temp;
307 if (m_currExcStackCount != 0)
309 throw new NotSupportedException(Environment.GetResourceString(ResId.Argument_UnclosedExceptionBlock));
312 if (m_exceptionCount == 0)
317 temp = new __ExceptionInfo[m_exceptionCount];
318 Array.Copy(m_exceptions, temp, m_exceptionCount);
319 SortExceptions(temp);
323 internal void EnsureCapacity(int size)
325 // Guarantees an array capable of holding at least size elements.
326 if (m_length + size >= m_ILStream.Length)
328 if (m_length + size >= 2 * m_ILStream.Length)
330 m_ILStream = EnlargeArray(m_ILStream, m_length + size);
334 m_ILStream = EnlargeArray(m_ILStream);
339 internal void PutInteger4(int value)
341 m_length = PutInteger4InArray(value, m_length, m_ILStream);
344 private static int PutInteger4InArray(int value, int startPos, byte []array)
346 // Puts an Int32 onto the stream. This is an internal routine, so it does not do any error checking.
348 array[startPos++] = (byte)value;
349 array[startPos++] = (byte)(value >>8);
350 array[startPos++] = (byte)(value >>16);
351 array[startPos++] = (byte)(value >>24);
355 private int GetLabelPos(Label lbl)
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.
360 int index = lbl.GetLabelValue();
362 if (index < 0 || index >= m_labelCount)
363 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabel"));
365 if (m_labelList[index] < 0)
366 throw new ArgumentException(Environment.GetResourceString("Argument_BadLabelContent"));
368 return m_labelList[index];
371 private void AddFixup(Label lbl, int pos, int instSize)
373 // Notes the label, position, and instruction size of a new fixup. Expands
374 // all of the fixup arrays as appropriate.
376 if (m_fixupData == null)
378 m_fixupData = new __FixupData[DefaultFixupArraySize];
380 else if (m_fixupData.Length <= m_fixupCount)
382 m_fixupData = EnlargeArray(m_fixupData);
385 m_fixupData[m_fixupCount].m_fixupPos = pos;
386 m_fixupData[m_fixupCount].m_fixupLabel = lbl;
387 m_fixupData[m_fixupCount].m_fixupInstSize = instSize;
392 internal int GetMaxStackSize()
394 return m_maxStackSize;
397 private static void SortExceptions(__ExceptionInfo []exceptions)
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.
404 __ExceptionInfo temp;
405 int length = exceptions.Length;
406 for (int i =0; i < length; i++)
409 for (int j =i + 1; j < length; j++)
411 if (exceptions[least].IsInner(exceptions[j]))
416 temp = exceptions[i];
417 exceptions[i] = exceptions[least];
418 exceptions[least] = temp;
422 internal int[] GetTokenFixups()
424 if (m_RelocFixupCount == 0)
426 Contract.Assert(m_RelocFixupList == null);
430 int[] narrowTokens = new int[m_RelocFixupCount];
431 Array.Copy(m_RelocFixupList, narrowTokens, m_RelocFixupCount);
436 #region Public Members
439 public virtual void Emit(OpCode opcode)
442 InternalEmit(opcode);
446 public virtual void Emit(OpCode opcode, byte arg)
449 InternalEmit(opcode);
450 m_ILStream[m_length++]=arg;
453 [CLSCompliant(false)]
454 public void Emit(OpCode opcode, sbyte arg)
456 // Puts opcode onto the stream of instructions followed by arg
459 InternalEmit(opcode);
462 m_ILStream[m_length++]=(byte)(256+arg);
464 m_ILStream[m_length++]=(byte) arg;
468 public virtual void Emit(OpCode opcode, short arg)
470 // Puts opcode onto the stream of instructions followed by arg
472 InternalEmit(opcode);
473 m_ILStream[m_length++]=(byte) arg;
474 m_ILStream[m_length++]=(byte) (arg>>8);
477 public virtual void Emit(OpCode opcode, int arg)
479 // Puts opcode onto the stream of instructions followed by arg
481 InternalEmit(opcode);
485 [System.Security.SecuritySafeCritical] // auto-generated
486 public virtual void Emit(OpCode opcode, MethodInfo meth)
489 throw new ArgumentNullException("meth");
490 Contract.EndContractBlock();
492 if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))
494 EmitCall(opcode, meth, null);
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);
508 InternalEmit(opcode);
510 UpdateStackSize(opcode, stackchange);
517 [System.Security.SecuritySafeCritical] // auto-generated
518 public virtual void EmitCalli(OpCode opcode, CallingConventions callingConvention,
519 Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
523 if (optionalParameterTypes != null)
525 if ((callingConvention & CallingConventions.VarArgs) == 0)
527 // Client should not supply optional parameter in default calling convention
528 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAVarArgCallingConvention"));
532 ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
533 sig = GetMemberRefSignature(callingConvention,
536 optionalParameterTypes);
541 // If there is a non-void return type, push one.
542 if (returnType != typeof(void))
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)
553 // Pop the native function pointer.
555 UpdateStackSize(OpCodes.Calli, stackchange);
558 PutInteger4(modBuilder.GetSignatureToken(sig).Token);
561 public virtual void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
568 ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
570 if (parameterTypes != null)
572 cParams = parameterTypes.Length;
575 sig = SignatureHelper.GetMethodSigHelper(
580 if (parameterTypes != null)
582 for (i = 0; i < cParams; i++)
584 sig.AddArgument(parameterTypes[i]);
588 // If there is a non-void return type, push one.
589 if (returnType != typeof(void))
592 // Pop off arguments if any.
593 if (parameterTypes != null)
594 stackchange -= cParams;
596 // Pop the native function pointer.
598 UpdateStackSize(OpCodes.Calli, stackchange);
603 PutInteger4(modBuilder.GetSignatureToken(sig).Token);
606 [System.Security.SecuritySafeCritical] // auto-generated
607 public virtual void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
609 if (methodInfo == null)
610 throw new ArgumentNullException("methodInfo");
612 if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)))
613 throw new ArgumentException(Environment.GetResourceString("Argument_NotMethodCallOpcode"), "opcode");
615 Contract.EndContractBlock();
618 int tk = GetMethodToken(methodInfo, optionalParameterTypes, false);
621 InternalEmit(opcode);
623 // Push the return value if there is one.
624 if (methodInfo.ReturnType != typeof(void))
626 // Pop the parameters.
627 Type[] parameters = methodInfo.GetParameterTypes();
628 if (parameters != null)
629 stackchange -= parameters.Length;
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)))
635 // Pop the optional parameters off the stack.
636 if (optionalParameterTypes != null)
637 stackchange -= optionalParameterTypes.Length;
638 UpdateStackSize(opcode, stackchange);
644 public virtual void Emit(OpCode opcode, SignatureHelper signature)
646 if (signature == null)
647 throw new ArgumentNullException("signature");
648 Contract.EndContractBlock();
651 ModuleBuilder modBuilder = (ModuleBuilder)m_methodBuilder.Module;
652 SignatureToken sig = modBuilder.GetSignatureToken(signature);
654 int tempVal = sig.Token;
657 InternalEmit(opcode);
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
664 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
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.
672 UpdateStackSize(opcode, stackchange);
676 PutInteger4(tempVal);
679 [System.Security.SecuritySafeCritical] // auto-generated
680 [System.Runtime.InteropServices.ComVisible(true)]
681 public virtual void Emit(OpCode opcode, ConstructorInfo con)
684 throw new ArgumentNullException("con");
685 Contract.EndContractBlock();
689 // Constructors cannot be generic so the value of UseMethodDef doesn't matter.
690 int tk = GetMethodToken(con, null, true);
693 InternalEmit(opcode);
695 // Make a conservative estimate by assuming a return type and no
697 if (opcode.StackBehaviourPush == StackBehaviour.Varpush)
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.");
705 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
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.");
713 Type[] parameters = con.GetParameterTypes();
714 if (parameters != null)
715 stackchange -= parameters.Length;
717 UpdateStackSize(opcode, stackchange);
723 [System.Security.SecuritySafeCritical] // auto-generated
724 public virtual void Emit(OpCode opcode, Type cls)
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.
731 ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
732 if (opcode == OpCodes.Ldtoken && cls != null && cls.IsGenericTypeDefinition)
734 // This gets the token for the generic type definition if cls is one.
735 tempVal = modBuilder.GetTypeToken( cls ).Token;
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;
745 InternalEmit(opcode);
747 PutInteger4(tempVal);
750 public virtual void Emit(OpCode opcode, long arg) {
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);
763 [System.Security.SecuritySafeCritical] // auto-generated
764 unsafe public virtual void Emit(OpCode opcode, float arg) {
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);
774 [System.Security.SecuritySafeCritical] // auto-generated
775 unsafe public virtual void Emit(OpCode opcode, double arg) {
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);
789 public virtual void Emit(OpCode opcode, Label label)
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.
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.
801 int tempVal = label.GetLabelValue();
805 InternalEmit(opcode);
806 if (OpCodes.TakesSingleByteArgument(opcode)) {
807 AddFixup(label, m_length, 1);
810 AddFixup(label, m_length, 4);
815 public virtual void Emit(OpCode opcode, Label[] labels)
818 throw new ArgumentNullException("labels");
819 Contract.EndContractBlock();
821 // Emitting a switch table
824 int remaining; // number of bytes remaining for this switch instruction to be substracted
825 // for computing the offset
827 int count = labels.Length;
829 EnsureCapacity( count * 4 + 7 );
830 InternalEmit(opcode);
832 for ( remaining = count * 4, i = 0; remaining > 0; remaining -= 4, i++ ) {
833 AddFixup( labels[i], m_length, remaining );
838 public virtual void Emit(OpCode opcode, FieldInfo field)
840 ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
841 int tempVal = modBuilder.GetFieldToken( field ).Token;
843 InternalEmit(opcode);
845 PutInteger4(tempVal);
848 public virtual void Emit(OpCode opcode, String str)
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.
854 ModuleBuilder modBuilder = (ModuleBuilder) m_methodBuilder.Module;
855 int tempVal = modBuilder.GetStringConstant(str).Token;
857 InternalEmit(opcode);
858 PutInteger4(tempVal);
861 public virtual void Emit(OpCode opcode, LocalBuilder local)
863 // Puts the opcode onto the IL stream followed by the information for local variable local.
867 throw new ArgumentNullException("local");
869 Contract.EndContractBlock();
870 int tempVal = local.GetLocalIndex();
871 if (local.GetMethodBuilder() != m_methodBuilder)
873 throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchedMethodForLocal"), "local");
875 // If the instruction is a ldloc, ldloca a stloc, morph it to the optimal form.
876 if (opcode.Equals(OpCodes.Ldloc))
881 opcode = OpCodes.Ldloc_0;
884 opcode = OpCodes.Ldloc_1;
887 opcode = OpCodes.Ldloc_2;
890 opcode = OpCodes.Ldloc_3;
894 opcode = OpCodes.Ldloc_S;
898 else if (opcode.Equals(OpCodes.Stloc))
903 opcode = OpCodes.Stloc_0;
906 opcode = OpCodes.Stloc_1;
909 opcode = OpCodes.Stloc_2;
912 opcode = OpCodes.Stloc_3;
916 opcode = OpCodes.Stloc_S;
920 else if (opcode.Equals(OpCodes.Ldloca))
923 opcode = OpCodes.Ldloca_S;
927 InternalEmit(opcode);
929 if (opcode.OperandType == OperandType.InlineNone)
931 else if (!OpCodes.TakesSingleByteArgument(opcode))
933 m_ILStream[m_length++]=(byte) tempVal;
934 m_ILStream[m_length++]=(byte) (tempVal>>8);
938 //Handle stloc_1, ldloc_1
939 if (tempVal > Byte.MaxValue)
941 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_BadInstructionOrIndexOutOfBound"));
943 m_ILStream[m_length++]=(byte)tempVal;
949 public virtual Label BeginExceptionBlock()
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:
956 // BeginExceptionBlock
957 // Emit the IL which should appear within the "try" block
959 // Emit the IL which should appear within the "catch" block
960 // Optional: BeginCatchBlock (this can be repeated an arbitrary number of times
964 if (m_exceptions == null)
966 m_exceptions = new __ExceptionInfo[DefaultExceptionArraySize];
969 if (m_currExcStack == null)
971 m_currExcStack = new __ExceptionInfo[DefaultExceptionArraySize];
974 if (m_exceptionCount>=m_exceptions.Length) {
975 m_exceptions=EnlargeArray(m_exceptions);
978 if (m_currExcStackCount>=m_currExcStack.Length) {
979 m_currExcStack = EnlargeArray(m_currExcStack);
982 Label endLabel = DefineLabel();
983 __ExceptionInfo exceptionInfo = new __ExceptionInfo(m_length, endLabel);
985 // add the exception to the tracking list
986 m_exceptions[m_exceptionCount++] = exceptionInfo;
988 // Make this exception the current active exception
989 m_currExcStack[m_currExcStackCount++] = exceptionInfo;
993 public virtual void EndExceptionBlock() {
994 if (m_currExcStackCount==0) {
995 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
998 // Pop the current exception block
999 __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1000 m_currExcStack[m_currExcStackCount-1] = null;
1001 m_currExcStackCount--;
1003 Label endLabel = current.GetEndLabel();
1004 int state = current.GetCurrentState();
1006 if (state == __ExceptionInfo.State_Filter ||
1007 state == __ExceptionInfo.State_Try)
1011 throw new InvalidOperationException(Environment.GetResourceString("Argument_BadExceptionCodeGen"));
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);
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);
1025 MarkLabel(current.GetFinallyEndLabel());
1028 current.Done(m_length);
1031 public virtual void BeginExceptFilterBlock()
1033 // Begins a eception filter block. Emits a branch instruction to the end of the current exception block.
1035 if (m_currExcStackCount == 0)
1036 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1038 __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1040 Label endLabel = current.GetEndLabel();
1041 this.Emit(OpCodes.Leave, endLabel);
1043 current.MarkFilterAddr(m_length);
1046 public virtual void BeginCatchBlock(Type exceptionType)
1048 // Begins a catch block. Emits a branch instruction to the end of the current exception block.
1050 if (m_currExcStackCount==0) {
1051 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1053 __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1055 if (current.GetCurrentState() == __ExceptionInfo.State_Filter) {
1056 if (exceptionType != null) {
1057 throw new ArgumentException(Environment.GetResourceString("Argument_ShouldNotSpecifyExceptionType"));
1060 this.Emit(OpCodes.Endfilter);
1062 // execute this branch if previous clause is Catch or Fault
1063 if (exceptionType==null) {
1064 throw new ArgumentNullException("exceptionType");
1067 Label endLabel = current.GetEndLabel();
1068 this.Emit(OpCodes.Leave, endLabel);
1072 current.MarkCatchAddr(m_length, exceptionType);
1075 public virtual void BeginFaultBlock()
1077 if (m_currExcStackCount==0) {
1078 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
1080 __ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
1082 // emit the leave for the clause before this one.
1083 Label endLabel = current.GetEndLabel();
1084 this.Emit(OpCodes.Leave, endLabel);
1086 current.MarkFaultAddr(m_length);
1089 public virtual void BeginFinallyBlock()
1091 if (m_currExcStackCount==0) {
1092 throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
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)
1100 // generate leave for any preceeding catch clause
1101 this.Emit(OpCodes.Leave, endLabel);
1102 catchEndAddr = m_length;
1105 MarkLabel(endLabel);
1108 Label finallyEndLabel = this.DefineLabel();
1109 current.SetFinallyEndLabel(finallyEndLabel);
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);
1121 public virtual Label DefineLabel()
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
1127 // Delay init the lable array in case we dont use it
1128 if (m_labelList == null){
1129 m_labelList = new int[DefaultLabelArraySize];
1132 if (m_labelCount>=m_labelList.Length) {
1133 m_labelList = EnlargeArray(m_labelList);
1135 m_labelList[m_labelCount]=-1;
1136 return new Label(m_labelCount++);
1139 public virtual void MarkLabel(Label loc)
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.
1144 int labelIndex = loc.GetLabelValue();
1146 //This should never happen.
1147 if (labelIndex<0 || labelIndex>=m_labelList.Length) {
1148 throw new ArgumentException (Environment.GetResourceString("Argument_InvalidLabel"));
1151 if (m_labelList[labelIndex]!=-1) {
1152 throw new ArgumentException (Environment.GetResourceString("Argument_RedefinedLabel"));
1155 m_labelList[labelIndex]=m_length;
1161 public virtual void ThrowException(Type excType)
1163 // Emits the il to throw an exception
1165 if (excType==null) {
1166 throw new ArgumentNullException("excType");
1169 if (!excType.IsSubclassOf(typeof(Exception)) && excType!=typeof(Exception)) {
1170 throw new ArgumentException(Environment.GetResourceString("Argument_NotExceptionType"));
1172 Contract.EndContractBlock();
1173 ConstructorInfo con = excType.GetConstructor(Type.EmptyTypes);
1175 throw new ArgumentException(Environment.GetResourceString("Argument_MissingDefaultConstructor"));
1177 this.Emit(OpCodes.Newobj, con);
1178 this.Emit(OpCodes.Throw);
1181 public virtual void EmitWriteLine(String value)
1183 // Emits the IL to call Console.WriteLine with a string.
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);
1192 public virtual void EmitWriteLine(LocalBuilder localBuilder)
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.
1200 if (m_methodBuilder==null)
1202 throw new ArgumentException(Environment.GetResourceString("InvalidOperation_BadILGeneratorUsage"));
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"));
1213 parameterTypes[0] = (Type)cls;
1214 MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
1216 throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "localBuilder");
1219 Emit(OpCodes.Callvirt, mi);
1222 public virtual void EmitWriteLine(FieldInfo fld)
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.
1233 throw new ArgumentNullException("fld");
1235 Contract.EndContractBlock();
1237 MethodInfo prop = typeof(Console).GetMethod("get_Out");
1238 Emit(OpCodes.Call, prop);
1240 if ((fld.Attributes & FieldAttributes.Static)!=0) {
1241 Emit(OpCodes.Ldsfld, fld);
1243 Emit(OpCodes.Ldarg, (short)0); //Load the this ref.
1244 Emit(OpCodes.Ldfld, fld);
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"));
1251 parameterTypes[0] = (Type)cls;
1252 MethodInfo mi = typeof(TextWriter).GetMethod("WriteLine", parameterTypes);
1254 throw new ArgumentException(Environment.GetResourceString("Argument_EmitWriteLineType"), "fld");
1256 Emit(OpCodes.Callvirt, mi);
1262 public virtual LocalBuilder DeclareLocal(Type localType)
1264 return DeclareLocal(localType, false);
1267 public virtual LocalBuilder DeclareLocal(Type localType, bool pinned)
1269 // Declare a local of type "local". The current active lexical scope
1270 // will be the scope that local will live.
1272 LocalBuilder localBuilder;
1274 MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
1275 if (methodBuilder == null)
1276 throw new NotSupportedException();
1278 if (methodBuilder.IsTypeCreated())
1280 // cannot change method after its containing type has been created
1281 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TypeHasBeenCreated"));
1284 if (localType==null) {
1285 throw new ArgumentNullException("localType");
1288 if (methodBuilder.m_bIsBaked) {
1289 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MethodBaked"));
1292 // add the localType to local signature
1293 m_localSignature.AddArgument(localType, pinned);
1295 localBuilder = new LocalBuilder(m_localCount, localType, methodBuilder, pinned);
1297 return localBuilder;
1300 public virtual void UsingNamespace(String usingNamespace)
1302 // Specifying the namespace to be used in evaluating locals and watches
1303 // for the current active lexical scope.
1305 if (usingNamespace == null)
1306 throw new ArgumentNullException("usingNamespace");
1308 if (usingNamespace.Length == 0)
1309 throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "usingNamespace");
1310 Contract.EndContractBlock();
1313 MethodBuilder methodBuilder = m_methodBuilder as MethodBuilder;
1314 if (methodBuilder == null)
1315 throw new NotSupportedException();
1317 index = methodBuilder.GetILGenerator().m_ScopeTree.GetCurrentActiveScopeIndex();
1320 methodBuilder.m_localSymInfo.AddUsingNamespace(usingNamespace);
1324 m_ScopeTree.AddUsingNamespaceToCurrentScope(usingNamespace);
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
1335 if (startLine == 0 || startLine < 0 || endLine == 0 || endLine < 0)
1337 throw new ArgumentOutOfRangeException("startLine");
1339 Contract.EndContractBlock();
1340 m_LineNumberInfo.AddLineNumberInfo(document, m_length, startLine, startColumn, endLine, endColumn);
1343 public virtual void BeginScope()
1345 m_ScopeTree.AddScopeInfo(ScopeAction.Open, m_length);
1348 public virtual void EndScope()
1350 m_ScopeTree.AddScopeInfo(ScopeAction.Close, m_length);
1353 public virtual int ILOffset
1365 #if !FEATURE_CORECLR
1366 void _ILGenerator.GetTypeInfoCount(out uint pcTInfo)
1368 throw new NotImplementedException();
1371 void _ILGenerator.GetTypeInfo(uint iTInfo, uint lcid, IntPtr ppTInfo)
1373 throw new NotImplementedException();
1376 void _ILGenerator.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1378 throw new NotImplementedException();
1381 void _ILGenerator.Invoke(uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1383 throw new NotImplementedException();
1388 internal struct __FixupData
1390 internal Label m_fixupLabel;
1391 internal int m_fixupPos;
1393 internal int m_fixupInstSize;
1396 internal sealed class __ExceptionInfo {
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
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;
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;
1426 //This will never get called. The values exist merely to keep the
1428 private __ExceptionInfo() {
1430 m_filterAddr = null;
1432 m_catchEndAddr = null;
1437 m_currentState = State_Try;
1440 internal __ExceptionInfo(int startAddr, Label endLabel) {
1441 m_startAddr=startAddr;
1443 m_filterAddr=new int[4];
1444 m_catchAddr=new int[4];
1445 m_catchEndAddr=new int[4];
1446 m_catchClass=new Type[4];
1448 m_endLabel=endLabel;
1451 m_currentState = State_Try;
1454 private static Type[] EnlargeArray(Type[] incoming)
1456 Type[] temp = new Type[incoming.Length * 2];
1457 Array.Copy(incoming, temp, incoming.Length);
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
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);
1476 m_type[m_currentCatch]=type;
1477 m_filterAddr[m_currentCatch] = catchorfilterAddr;
1478 m_catchAddr[m_currentCatch] = -1;
1479 if (m_currentCatch > 0)
1481 Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
1482 m_catchEndAddr[m_currentCatch-1] = catchorfilterAddr;
1487 // catch or Fault clause
1488 m_catchClass[m_currentCatch]=catchClass;
1489 if (m_type[m_currentCatch] != Filter)
1491 m_type[m_currentCatch]=type;
1493 m_catchAddr[m_currentCatch]=catchorfilterAddr;
1494 if (m_currentCatch > 0)
1496 if (m_type[m_currentCatch] != Filter)
1498 Contract.Assert(m_catchEndAddr[m_currentCatch-1] == -1,"m_catchEndAddr[m_currentCatch-1] == -1");
1499 m_catchEndAddr[m_currentCatch-1] = catchEndAddr;
1502 m_catchEndAddr[m_currentCatch]=-1;
1508 m_endAddr=catchorfilterAddr;
1512 internal void MarkFilterAddr(int filterAddr)
1514 m_currentState = State_Filter;
1515 MarkHelper(filterAddr, filterAddr, null, Filter);
1518 internal void MarkFaultAddr(int faultAddr)
1520 m_currentState = State_Fault;
1521 MarkHelper(faultAddr, faultAddr, null, Fault);
1524 internal void MarkCatchAddr(int catchAddr, Type catchException) {
1525 m_currentState = State_Catch;
1526 MarkHelper(catchAddr, catchAddr, catchException, None);
1529 internal void MarkFinallyAddr(int finallyAddr, int endCatchAddr) {
1530 if (m_endFinally!=-1) {
1531 throw new ArgumentException(Environment.GetResourceString("Argument_TooManyFinallyClause"));
1533 m_currentState = State_Finally;
1534 m_endFinally=finallyAddr;
1536 MarkHelper(finallyAddr, endCatchAddr, null, Finally);
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;
1547 internal int GetStartAddress() {
1551 internal int GetEndAddress() {
1555 internal int GetFinallyEndAddress() {
1556 return m_endFinally;
1559 internal Label GetEndLabel() {
1563 internal int [] GetFilterAddresses() {
1564 return m_filterAddr;
1567 internal int [] GetCatchAddresses() {
1571 internal int [] GetCatchEndAddresses() {
1572 return m_catchEndAddr;
1575 internal Type [] GetCatchClass() {
1576 return m_catchClass;
1579 internal int GetNumberOfCatches() {
1580 return m_currentCatch;
1583 internal int[] GetExceptionTypes() {
1587 internal void SetFinallyEndLabel(Label lbl) {
1588 m_finallyEndLabel=lbl;
1591 internal Label GetFinallyEndLabel() {
1592 return m_finallyEndLabel;
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");
1608 int exclast = exc.m_currentCatch - 1;
1609 int last = m_currentCatch - 1;
1611 if (exc.m_catchEndAddr[exclast] < m_catchEndAddr[last])
1613 else if (exc.m_catchEndAddr[exclast] == m_catchEndAddr[last])
1615 Contract.Assert(exc.GetEndAddress() != GetEndAddress(),
1616 "exc.GetEndAddress() != GetEndAddress()");
1617 if (exc.GetEndAddress() > GetEndAddress())
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
1628 internal int GetCurrentState() {
1629 return m_currentState;
1634 /***************************
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
1641 ***************************/
1649 internal sealed class ScopeTree
1651 internal ScopeTree()
1653 // initialize data variables
1654 m_iOpenScopeCount = 0;
1658 /***************************
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.
1664 ***************************/
1665 internal int GetCurrentActiveScopeIndex()
1668 int i = m_iCount - 1;
1674 for (; cClose > 0 || m_ScopeActions[i] == ScopeAction.Close; i--)
1676 if (m_ScopeActions[i] == ScopeAction.Open)
1687 internal void AddLocalSymInfoToCurrentScope(
1694 int i = GetCurrentActiveScopeIndex();
1695 if (m_localSymInfos[i] == null)
1697 m_localSymInfos[i] = new LocalSymInfo();
1699 m_localSymInfos[i].AddLocalSymInfo(strName, signature, slot, startOffset, endOffset);
1702 internal void AddUsingNamespaceToCurrentScope(
1703 String strNamespace)
1705 int i = GetCurrentActiveScopeIndex();
1706 if (m_localSymInfos[i] == null)
1708 m_localSymInfos[i] = new LocalSymInfo();
1710 m_localSymInfos[i].AddUsingNamespace(strNamespace);
1713 internal void AddScopeInfo(ScopeAction sa, int iOffset)
1715 if (sa == ScopeAction.Close && m_iOpenScopeCount <=0)
1717 throw new ArgumentException(Environment.GetResourceString("Argument_UnmatchingSymScope"));
1719 Contract.EndContractBlock();
1721 // make sure that arrays are large enough to hold addition info
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)
1731 m_iOpenScopeCount++;
1734 m_iOpenScopeCount--;
1738 /**************************
1740 * Helper to ensure arrays are large enough
1742 **************************/
1743 internal void EnsureCapacity()
1747 // First time. Allocate the arrays.
1748 m_iOffsets = new int[InitialSize];
1749 m_ScopeActions = new ScopeAction[InitialSize];
1750 m_localSymInfos = new LocalSymInfo[InitialSize];
1752 else if (m_iCount == m_iOffsets.Length)
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);
1761 ScopeAction[] tempSA = new ScopeAction[newSize];
1762 Array.Copy(m_ScopeActions, tempSA, m_iCount);
1763 m_ScopeActions = tempSA;
1765 LocalSymInfo[] tempLSI = new LocalSymInfo[newSize];
1766 Array.Copy(m_localSymInfos, tempLSI, m_iCount);
1767 m_localSymInfos = tempLSI;
1772 [System.Security.SecurityCritical] // auto-generated
1774 internal void EmitScopeTree(ISymbolWriter symWriter)
1777 for (i = 0; i < m_iCount; i++)
1779 if (m_ScopeActions[i] == ScopeAction.Open)
1781 symWriter.OpenScope(m_iOffsets[i]);
1785 symWriter.CloseScope(m_iOffsets[i]);
1787 if (m_localSymInfos[i] != null)
1789 m_localSymInfos[i].EmitLocalSymInfo(symWriter);
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
1803 /***************************
1805 * This class tracks the line number info
1807 ***************************/
1808 internal sealed class LineNumberInfo
1810 internal LineNumberInfo()
1812 // initialize data variables
1813 m_DocumentCount = 0;
1817 internal void AddLineNumberInfo(
1818 ISymbolDocumentWriter document,
1827 // make sure that arrays are large enough to hold addition info
1828 i = FindDocument(document);
1830 Contract.Assert(i < m_DocumentCount, "Bad document look up!");
1831 m_Documents[i].AddLineNumberInfo(document, iOffset, iStartLine, iStartColumn, iEndLine, iEndColumn);
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)
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;
1845 for (i = 0; i < m_DocumentCount; i++)
1847 if (m_Documents[i].m_document == document)
1850 return m_iLastFound;
1854 // cannot find an existing document so add one to the array
1856 m_iLastFound = m_DocumentCount;
1857 m_Documents[m_iLastFound] = new REDocument(document);
1858 checked { m_DocumentCount++; }
1859 return m_iLastFound;
1862 /**************************
1864 * Helper to ensure arrays are large enough
1866 **************************/
1867 private void EnsureCapacity()
1869 if (m_DocumentCount == 0)
1871 // First time. Allocate the arrays.
1872 m_Documents = new REDocument[InitialSize];
1874 else if (m_DocumentCount == m_Documents.Length)
1876 // the arrays are full. Enlarge the arrays
1877 REDocument[] temp = new REDocument [m_DocumentCount * 2];
1878 Array.Copy(m_Documents, temp, m_DocumentCount);
1884 [System.Security.SecurityCritical] // auto-generated
1886 internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1888 for (int i = 0; i < m_DocumentCount; i++)
1889 m_Documents[i].EmitLineNumberInfo(symWriter);
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;
1899 /***************************
1901 * This class tracks the line number info
1903 ***************************/
1904 internal sealed class REDocument
1906 internal REDocument(ISymbolDocumentWriter document)
1908 // initialize data variables
1909 m_iLineNumberCount = 0;
1910 m_document = document;
1913 internal void AddLineNumberInfo(
1914 ISymbolDocumentWriter document,
1921 Contract.Assert(document == m_document, "Bad document look up!");
1923 // make sure that arrays are large enough to hold addition info
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++; }
1934 /**************************
1936 * Helper to ensure arrays are large enough
1938 **************************/
1939 private void EnsureCapacity()
1941 if (m_iLineNumberCount == 0)
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];
1950 else if (m_iLineNumberCount == m_iOffsets.Length)
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);
1959 temp = new int [newSize];
1960 Array.Copy(m_iLines, temp, m_iLineNumberCount);
1963 temp = new int [newSize];
1964 Array.Copy(m_iColumns, temp, m_iLineNumberCount);
1967 temp = new int [newSize];
1968 Array.Copy(m_iEndLines, temp, m_iLineNumberCount);
1971 temp = new int [newSize];
1972 Array.Copy(m_iEndColumns, temp, m_iLineNumberCount);
1973 m_iEndColumns = temp;
1978 [System.Security.SecurityCritical] // auto-generated
1980 internal void EmitLineNumberInfo(ISymbolWriter symWriter)
1985 int[] iEndLinesTemp;
1986 int[] iEndColumnsTemp;
1988 if (m_iLineNumberCount == 0)
1990 // reduce the array size to be exact
1991 iOffsetsTemp = new int [m_iLineNumberCount];
1992 Array.Copy(m_iOffsets, iOffsetsTemp, m_iLineNumberCount);
1994 iLinesTemp = new int [m_iLineNumberCount];
1995 Array.Copy(m_iLines, iLinesTemp, m_iLineNumberCount);
1997 iColumnsTemp = new int [m_iLineNumberCount];
1998 Array.Copy(m_iColumns, iColumnsTemp, m_iLineNumberCount);
2000 iEndLinesTemp = new int [m_iLineNumberCount];
2001 Array.Copy(m_iEndLines, iEndLinesTemp, m_iLineNumberCount);
2003 iEndColumnsTemp = new int [m_iLineNumberCount];
2004 Array.Copy(m_iEndColumns, iEndColumnsTemp, m_iLineNumberCount);
2006 symWriter.DefineSequencePoints(m_document, iOffsetsTemp, iLinesTemp, iColumnsTemp, iEndLinesTemp, iEndColumnsTemp);
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