3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 // System.Reflection.Emit/ILGenerator.cs
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
35 using System.Collections;
36 using System.Diagnostics.SymbolStore;
37 using System.Runtime.InteropServices;
39 namespace System.Reflection.Emit {
41 internal struct ILExceptionBlock {
42 public const int CATCH = 0;
43 public const int FILTER = 1;
44 public const int FINALLY = 2;
45 public const int FAULT = 4;
46 public const int FILTER_START = -1;
52 internal int filter_offset;
54 internal void Debug () {
56 System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
58 System.Console.WriteLine (" extype="+extype.ToString());
60 System.Console.WriteLine (String.Empty);
64 internal struct ILExceptionInfo {
65 ILExceptionBlock[] handlers;
70 internal int NumHandlers ()
72 return handlers.Length;
75 internal void AddCatch (Type extype, int offset)
80 i = handlers.Length - 1;
81 handlers [i].type = ILExceptionBlock.CATCH;
82 handlers [i].start = offset;
83 handlers [i].extype = extype;
86 internal void AddFinally (int offset)
91 i = handlers.Length - 1;
92 handlers [i].type = ILExceptionBlock.FINALLY;
93 handlers [i].start = offset;
94 handlers [i].extype = null;
97 internal void AddFault (int offset)
102 i = handlers.Length - 1;
103 handlers [i].type = ILExceptionBlock.FAULT;
104 handlers [i].start = offset;
105 handlers [i].extype = null;
108 internal void AddFilter (int offset)
113 i = handlers.Length - 1;
114 handlers [i].type = ILExceptionBlock.FILTER_START;
115 handlers [i].extype = null;
116 handlers [i].filter_offset = offset;
119 internal void End (int offset)
121 if (handlers == null)
123 int i = handlers.Length - 1;
125 handlers [i].len = offset - handlers [i].start;
128 internal int LastClauseType ()
130 if (handlers != null)
131 return handlers [handlers.Length-1].type;
133 return ILExceptionBlock.CATCH;
136 internal void PatchFilterClause (int start)
138 if (handlers != null && handlers.Length > 0) {
139 handlers [handlers.Length - 1].start = start;
140 handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
144 internal void Debug (int b)
147 System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
148 for (int i = 0; i < handlers.Length; ++i)
149 handlers [i].Debug ();
153 void add_block (int offset)
155 if (handlers != null) {
156 int i = handlers.Length;
157 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
158 System.Array.Copy (handlers, new_b, i);
160 handlers [i].len = offset - handlers [i].start;
162 handlers = new ILExceptionBlock [1];
163 len = offset - start;
168 internal struct ILTokenInfo {
169 public MemberInfo member;
173 internal interface TokenGenerator {
174 int GetToken (string str);
176 int GetToken (MemberInfo member);
178 int GetToken (MethodInfo method, Type[] opt_param_types);
180 int GetToken (SignatureHelper helper);
185 [ComDefaultInterface (typeof (_ILGenerator))]
187 [ClassInterface (ClassInterfaceType.None)]
188 public class ILGenerator: _ILGenerator {
189 private struct LabelFixup {
190 public int offset; // The number of bytes between pos and the
191 // offset of the jump
192 public int pos; // Where offset of the label is placed
193 public int label_idx; // The label to jump to
197 public LabelData (int addr, int maxStack)
200 this.maxStack = maxStack;
207 static readonly Type void_type = typeof (void);
208 #region Sync with reflection.h
210 private int code_len;
211 private int max_stack;
212 private int cur_stack;
213 private LocalBuilder[] locals;
214 private ILExceptionInfo[] ex_handlers;
215 private int num_token_fixups;
216 private ILTokenInfo[] token_fixups;
219 private LabelData [] labels;
220 private int num_labels;
221 private LabelFixup[] fixups;
222 private int num_fixups;
223 internal Module module;
224 private Stack scopes;
225 private int cur_block;
226 private Stack open_blocks;
227 private TokenGenerator token_gen;
229 const int defaultFixupSize = 4;
230 const int defaultLabelsSize = 4;
231 const int defaultExceptionStackSize = 2;
233 ArrayList sequencePointLists;
234 SequencePointList currentSequence;
236 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
240 code = new byte [size];
241 token_fixups = new ILTokenInfo [8];
243 this.token_gen = token_gen;
246 private void add_token_fixup (MemberInfo mi)
248 if (num_token_fixups == token_fixups.Length) {
249 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
250 token_fixups.CopyTo (ntf, 0);
253 token_fixups [num_token_fixups].member = mi;
254 token_fixups [num_token_fixups++].code_pos = code_len;
257 private void make_room (int nbytes)
259 if (code_len + nbytes < code.Length)
261 byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
262 System.Array.Copy (code, 0, new_code, 0, code.Length);
266 private void emit_int (int val)
268 code [code_len++] = (byte) (val & 0xFF);
269 code [code_len++] = (byte) ((val >> 8) & 0xFF);
270 code [code_len++] = (byte) ((val >> 16) & 0xFF);
271 code [code_len++] = (byte) ((val >> 24) & 0xFF);
274 /* change to pass by ref to avoid copy */
275 private void ll_emit (OpCode opcode)
278 * there is already enough room allocated in code.
280 // access op1 and op2 directly since the Value property is useless
281 if (opcode.Size == 2)
282 code [code_len++] = opcode.op1;
283 code [code_len++] = opcode.op2;
285 * We should probably keep track of stack needs here.
286 * Or we may want to run the verifier on the code before saving it
287 * (this may be needed anyway when the ILGenerator is not used...).
289 switch (opcode.StackBehaviourPush) {
290 case StackBehaviour.Push1:
291 case StackBehaviour.Pushi:
292 case StackBehaviour.Pushi8:
293 case StackBehaviour.Pushr4:
294 case StackBehaviour.Pushr8:
295 case StackBehaviour.Pushref:
296 case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
299 case StackBehaviour.Push1_push1:
303 if (max_stack < cur_stack)
304 max_stack = cur_stack;
307 * Note that we adjust for the pop behaviour _after_ setting max_stack.
309 switch (opcode.StackBehaviourPop) {
310 case StackBehaviour.Varpop:
311 break; /* we are conservative and assume it doesn't decrease the stack needs */
312 case StackBehaviour.Pop1:
313 case StackBehaviour.Popi:
314 case StackBehaviour.Popref:
317 case StackBehaviour.Pop1_pop1:
318 case StackBehaviour.Popi_pop1:
319 case StackBehaviour.Popi_popi:
320 case StackBehaviour.Popi_popi8:
321 case StackBehaviour.Popi_popr4:
322 case StackBehaviour.Popi_popr8:
323 case StackBehaviour.Popref_pop1:
324 case StackBehaviour.Popref_popi:
327 case StackBehaviour.Popi_popi_popi:
328 case StackBehaviour.Popref_popi_popi:
329 case StackBehaviour.Popref_popi_popi8:
330 case StackBehaviour.Popref_popi_popr4:
331 case StackBehaviour.Popref_popi_popr8:
332 case StackBehaviour.Popref_popi_popref:
338 private static int target_len (OpCode opcode)
340 if (opcode.OperandType == OperandType.InlineBrTarget)
345 private void InternalEndClause ()
347 switch (ex_handlers [cur_block].LastClauseType ()) {
348 case ILExceptionBlock.CATCH:
349 case ILExceptionBlock.FILTER:
350 case ILExceptionBlock.FILTER_START:
351 // how could we optimize code size here?
352 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
354 case ILExceptionBlock.FAULT:
355 case ILExceptionBlock.FINALLY:
356 Emit (OpCodes.Endfinally);
361 public virtual void BeginCatchBlock (Type exceptionType)
363 if (open_blocks == null)
364 open_blocks = new Stack (defaultExceptionStackSize);
366 if (open_blocks.Count <= 0)
367 throw new NotSupportedException ("Not in an exception block");
369 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
370 if (exceptionType != null)
371 throw new ArgumentException ("Do not supply an exception type for filter clause");
372 Emit (OpCodes.Endfilter);
373 ex_handlers [cur_block].PatchFilterClause (code_len);
375 InternalEndClause ();
376 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
379 cur_stack = 1; // the exception object is on the stack by default
380 if (max_stack < cur_stack)
381 max_stack = cur_stack;
383 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
386 public virtual void BeginExceptFilterBlock ()
388 if (open_blocks == null)
389 open_blocks = new Stack (defaultExceptionStackSize);
391 if (open_blocks.Count <= 0)
392 throw new NotSupportedException ("Not in an exception block");
393 InternalEndClause ();
395 ex_handlers [cur_block].AddFilter (code_len);
398 public virtual Label BeginExceptionBlock ()
400 //System.Console.WriteLine ("Begin Block");
401 if (open_blocks == null)
402 open_blocks = new Stack (defaultExceptionStackSize);
404 if (ex_handlers != null) {
405 cur_block = ex_handlers.Length;
406 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
407 System.Array.Copy (ex_handlers, new_ex, cur_block);
408 ex_handlers = new_ex;
410 ex_handlers = new ILExceptionInfo [1];
413 open_blocks.Push (cur_block);
414 ex_handlers [cur_block].start = code_len;
415 return ex_handlers [cur_block].end = DefineLabel ();
418 public virtual void BeginFaultBlock()
420 if (open_blocks == null)
421 open_blocks = new Stack (defaultExceptionStackSize);
423 if (open_blocks.Count <= 0)
424 throw new NotSupportedException ("Not in an exception block");
426 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
427 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
428 ex_handlers [cur_block].PatchFilterClause (code_len);
431 InternalEndClause ();
432 //System.Console.WriteLine ("Begin fault Block");
433 ex_handlers [cur_block].AddFault (code_len);
436 public virtual void BeginFinallyBlock()
438 if (open_blocks == null)
439 open_blocks = new Stack (defaultExceptionStackSize);
441 if (open_blocks.Count <= 0)
442 throw new NotSupportedException ("Not in an exception block");
444 InternalEndClause ();
446 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
447 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
448 ex_handlers [cur_block].PatchFilterClause (code_len);
451 //System.Console.WriteLine ("Begin finally Block");
452 ex_handlers [cur_block].AddFinally (code_len);
455 public virtual void BeginScope ()
463 LocalBuilder DeclareLocal (Type localType)
465 return DeclareLocal (localType, false);
474 virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
476 if (localType == null)
477 throw new ArgumentNullException ("localType");
479 LocalBuilder res = new LocalBuilder (localType, this);
480 res.is_pinned = pinned;
482 if (locals != null) {
483 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
484 System.Array.Copy (locals, new_l, locals.Length);
485 new_l [locals.Length] = res;
488 locals = new LocalBuilder [1];
491 res.position = (ushort)(locals.Length - 1);
495 public virtual Label DefineLabel ()
498 labels = new LabelData [defaultLabelsSize];
499 else if (num_labels >= labels.Length) {
500 LabelData [] t = new LabelData [labels.Length * 2];
501 Array.Copy (labels, t, labels.Length);
505 labels [num_labels] = new LabelData (-1, 0);
507 return new Label (num_labels++);
510 public virtual void Emit (OpCode opcode)
516 public virtual void Emit (OpCode opcode, Byte arg)
520 code [code_len++] = arg;
526 public virtual void Emit (OpCode opcode, ConstructorInfo con)
528 int token = token_gen.GetToken (con);
531 if (con.DeclaringType.Module == module)
532 add_token_fixup (con);
535 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
536 cur_stack -= con.GetParameterCount ();
539 public virtual void Emit (OpCode opcode, double arg)
541 byte[] s = System.BitConverter.GetBytes (arg);
544 if (BitConverter.IsLittleEndian){
545 System.Array.Copy (s, 0, code, code_len, 8);
548 code [code_len++] = s [7];
549 code [code_len++] = s [6];
550 code [code_len++] = s [5];
551 code [code_len++] = s [4];
552 code [code_len++] = s [3];
553 code [code_len++] = s [2];
554 code [code_len++] = s [1];
555 code [code_len++] = s [0];
559 public virtual void Emit (OpCode opcode, FieldInfo field)
561 int token = token_gen.GetToken (field);
564 if (field.DeclaringType.Module == module)
565 add_token_fixup (field);
569 public virtual void Emit (OpCode opcode, Int16 arg)
573 code [code_len++] = (byte) (arg & 0xFF);
574 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
577 public virtual void Emit (OpCode opcode, int arg)
584 public virtual void Emit (OpCode opcode, long arg)
588 code [code_len++] = (byte) (arg & 0xFF);
589 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
590 code [code_len++] = (byte) ((arg >> 16) & 0xFF);
591 code [code_len++] = (byte) ((arg >> 24) & 0xFF);
592 code [code_len++] = (byte) ((arg >> 32) & 0xFF);
593 code [code_len++] = (byte) ((arg >> 40) & 0xFF);
594 code [code_len++] = (byte) ((arg >> 48) & 0xFF);
595 code [code_len++] = (byte) ((arg >> 56) & 0xFF);
598 public virtual void Emit (OpCode opcode, Label label)
600 int tlen = target_len (opcode);
603 if (cur_stack > labels [label.label].maxStack)
604 labels [label.label].maxStack = cur_stack;
607 fixups = new LabelFixup [defaultFixupSize];
608 else if (num_fixups >= fixups.Length) {
609 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
610 System.Array.Copy (fixups, newf, fixups.Length);
613 fixups [num_fixups].offset = tlen;
614 fixups [num_fixups].pos = code_len;
615 fixups [num_fixups].label_idx = label.label;
621 public virtual void Emit (OpCode opcode, Label[] labels)
624 throw new ArgumentNullException ("labels");
626 /* opcode needs to be switch. */
627 int count = labels.Length;
628 make_room (6 + count * 4);
631 for (int i = 0; i < count; ++i)
632 if (cur_stack > this.labels [labels [i].label].maxStack)
633 this.labels [labels [i].label].maxStack = cur_stack;
637 fixups = new LabelFixup [defaultFixupSize + count];
638 else if (num_fixups + count >= fixups.Length) {
639 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
640 System.Array.Copy (fixups, newf, fixups.Length);
644 // ECMA 335, Partition III, p94 (7-10)
646 // The switch instruction implements a jump table. The format of
647 // the instruction is an unsigned int32 representing the number of targets N,
648 // followed by N int32 values specifying jump targets: these targets are
649 // represented as offsets (positive or negative) from the beginning of the
650 // instruction following this switch instruction.
652 // We must make sure it gets an offset from the *end* of the last label
653 // (eg, the beginning of the instruction following this).
655 // remaining is the number of bytes from the current instruction to the
656 // instruction that will be emitted.
658 for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
659 fixups [num_fixups].offset = remaining;
660 fixups [num_fixups].pos = code_len;
661 fixups [num_fixups].label_idx = labels [i].label;
667 public virtual void Emit (OpCode opcode, LocalBuilder local)
670 throw new ArgumentNullException ("local");
672 uint pos = local.position;
673 bool load_addr = false;
674 bool is_store = false;
677 if (local.ilgen != this)
678 throw new Exception ("Trying to emit a local from a different ILGenerator.");
680 /* inline the code from ll_emit () to optimize il code size */
681 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
686 if (cur_stack > max_stack)
687 max_stack = cur_stack;
688 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
692 code [code_len++] = (byte)0x12;
693 code [code_len++] = (byte)pos;
695 code [code_len++] = (byte)0xfe;
696 code [code_len++] = (byte)0x0d;
697 code [code_len++] = (byte)(pos & 0xff);
698 code [code_len++] = (byte)((pos >> 8) & 0xff);
703 code [code_len++] = (byte)(0x0a + pos);
704 } else if (pos < 256) {
705 code [code_len++] = (byte)0x13;
706 code [code_len++] = (byte)pos;
708 code [code_len++] = (byte)0xfe;
709 code [code_len++] = (byte)0x0e;
710 code [code_len++] = (byte)(pos & 0xff);
711 code [code_len++] = (byte)((pos >> 8) & 0xff);
715 code [code_len++] = (byte)(0x06 + pos);
716 } else if (pos < 256) {
717 code [code_len++] = (byte)0x11;
718 code [code_len++] = (byte)pos;
720 code [code_len++] = (byte)0xfe;
721 code [code_len++] = (byte)0x0c;
722 code [code_len++] = (byte)(pos & 0xff);
723 code [code_len++] = (byte)((pos >> 8) & 0xff);
729 public virtual void Emit (OpCode opcode, MethodInfo meth)
732 throw new ArgumentNullException ("meth");
735 // For compatibility with MS
736 if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
737 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
740 int token = token_gen.GetToken (meth);
743 Type declaringType = meth.DeclaringType;
744 // Might be a DynamicMethod with no declaring type
745 if (declaringType != null) {
746 if (declaringType.Module == module)
747 add_token_fixup (meth);
750 if (meth.ReturnType != void_type)
753 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
754 cur_stack -= meth.GetParameterCount ();
757 private void Emit (OpCode opcode, MethodInfo method, int token)
761 // Might be a DynamicMethod with no declaring type
762 Type declaringType = method.DeclaringType;
763 if (declaringType != null) {
764 if (declaringType.Module == module)
765 add_token_fixup (method);
768 if (method.ReturnType != void_type)
771 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
772 cur_stack -= method.GetParameterCount ();
775 [CLSCompliant(false)]
776 public void Emit (OpCode opcode, sbyte arg)
780 code [code_len++] = (byte)arg;
783 public virtual void Emit (OpCode opcode, SignatureHelper signature)
785 int token = token_gen.GetToken (signature);
791 public virtual void Emit (OpCode opcode, float arg)
793 byte[] s = System.BitConverter.GetBytes (arg);
796 if (BitConverter.IsLittleEndian){
797 System.Array.Copy (s, 0, code, code_len, 4);
800 code [code_len++] = s [3];
801 code [code_len++] = s [2];
802 code [code_len++] = s [1];
803 code [code_len++] = s [0];
807 public virtual void Emit (OpCode opcode, string str)
809 int token = token_gen.GetToken (str);
815 public virtual void Emit (OpCode opcode, Type cls)
819 emit_int (token_gen.GetToken (cls));
822 [MonoLimitation ("vararg methods are not supported")]
828 void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
830 if (methodInfo == null)
831 throw new ArgumentNullException ("methodInfo");
832 short value = opcode.Value;
833 if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
834 throw new NotSupportedException ("Only Call and CallVirt are allowed");
835 if (optionalParameterTypes != null){
836 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
837 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
840 int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
841 Emit (opcode, methodInfo, token);
844 Emit (opcode, methodInfo);
852 void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
854 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, parameterTypes);
855 Emit (opcode, helper);
863 void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
865 if (optionalParameterTypes != null)
866 throw new NotImplementedException ();
868 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, callingConvention, 0, returnType, parameterTypes);
869 Emit (opcode, helper);
872 public virtual void EmitWriteLine (FieldInfo fld)
875 throw new ArgumentNullException ("fld");
877 // The MS implementation does not check for valuetypes here but it
878 // should. Also, it should check that if the field is not static,
879 // then it is a member of this type.
881 Emit (OpCodes.Ldsfld, fld);
883 Emit (OpCodes.Ldarg_0);
884 Emit (OpCodes.Ldfld, fld);
886 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
889 public virtual void EmitWriteLine (LocalBuilder localBuilder)
891 if (localBuilder == null)
892 throw new ArgumentNullException ("localBuilder");
893 if (localBuilder.LocalType is TypeBuilder)
894 throw new ArgumentException ("Output streams do not support TypeBuilders.");
895 // The MS implementation does not check for valuetypes here but it
897 Emit (OpCodes.Ldloc, localBuilder);
898 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
901 public virtual void EmitWriteLine (string value)
903 Emit (OpCodes.Ldstr, value);
904 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
907 public virtual void EndExceptionBlock ()
909 if (open_blocks == null)
910 open_blocks = new Stack (defaultExceptionStackSize);
912 if (open_blocks.Count <= 0)
913 throw new NotSupportedException ("Not in an exception block");
915 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
916 throw new InvalidOperationException ("Incorrect code generation for exception block.");
918 InternalEndClause ();
919 MarkLabel (ex_handlers [cur_block].end);
920 ex_handlers [cur_block].End (code_len);
921 ex_handlers [cur_block].Debug (cur_block);
922 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
924 if (open_blocks.Count > 0)
925 cur_block = (int)open_blocks.Peek ();
926 //Console.WriteLine ("curblock restored to {0}", cur_block);
927 //throw new NotImplementedException ();
930 public virtual void EndScope ()
933 public virtual void MarkLabel (Label loc)
935 if (loc.label < 0 || loc.label >= num_labels)
936 throw new System.ArgumentException ("The label is not valid");
937 if (labels [loc.label].addr >= 0)
938 throw new System.ArgumentException ("The label was already defined");
939 labels [loc.label].addr = code_len;
940 if (labels [loc.label].maxStack > cur_stack)
941 cur_stack = labels [loc.label].maxStack;
944 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
945 int startColumn, int endLine, int endColumn)
947 if (currentSequence == null || currentSequence.Document != document) {
948 if (sequencePointLists == null)
949 sequencePointLists = new ArrayList ();
950 currentSequence = new SequencePointList (document);
951 sequencePointLists.Add (currentSequence);
954 currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
957 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
959 if (sequencePointLists != null) {
960 SequencePointList first = (SequencePointList) sequencePointLists [0];
961 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
962 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
964 foreach (SequencePointList list in sequencePointLists)
965 symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
967 if (locals != null) {
968 foreach (LocalBuilder local in locals) {
969 if (local.Name != null && local.Name.Length > 0) {
970 SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module);
971 sighelper.AddArgument (local.LocalType);
972 byte[] signature = sighelper.GetSignature ();
973 symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
977 sequencePointLists = null;
981 internal bool HasDebugInfo
983 get { return sequencePointLists != null; }
986 public virtual void ThrowException (Type excType)
989 throw new ArgumentNullException ("excType");
990 if (! ((excType == typeof (Exception)) ||
991 excType.IsSubclassOf (typeof (Exception))))
992 throw new ArgumentException ("Type should be an exception type", "excType");
993 ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
995 throw new ArgumentException ("Type should have a default constructor", "excType");
996 Emit (OpCodes.Newobj, ctor);
997 Emit (OpCodes.Throw);
1000 [MonoTODO("Not implemented")]
1006 void UsingNamespace (String usingNamespace)
1008 throw new NotImplementedException ();
1011 internal void label_fixup ()
1013 for (int i = 0; i < num_fixups; ++i) {
1015 // Diff is the offset from the end of the jump instruction to the address of the label
1016 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
1017 if (fixups [i].offset == 1) {
1018 code [fixups [i].pos] = (byte)((sbyte) diff);
1020 int old_cl = code_len;
1021 code_len = fixups [i].pos;
1028 internal static int Mono_GetCurrentOffset (ILGenerator ig)
1033 void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1035 throw new NotImplementedException ();
1038 void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1040 throw new NotImplementedException ();
1043 void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
1045 throw new NotImplementedException ();
1048 void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1050 throw new NotImplementedException ();
1054 internal class SequencePointList
1056 ISymbolDocumentWriter doc;
1057 SequencePoint[] points;
1059 const int arrayGrow = 10;
1061 public SequencePointList (ISymbolDocumentWriter doc)
1066 public ISymbolDocumentWriter Document {
1070 public int[] GetOffsets()
1072 int[] data = new int [count];
1073 for (int n=0; n<count; n++) data [n] = points[n].Offset;
1076 public int[] GetLines()
1078 int[] data = new int [count];
1079 for (int n=0; n<count; n++) data [n] = points[n].Line;
1082 public int[] GetColumns()
1084 int[] data = new int [count];
1085 for (int n=0; n<count; n++) data [n] = points[n].Col;
1088 public int[] GetEndLines()
1090 int[] data = new int [count];
1091 for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1094 public int[] GetEndColumns()
1096 int[] data = new int [count];
1097 for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1100 public int StartLine {
1101 get { return points[0].Line; }
1103 public int EndLine {
1104 get { return points[count - 1].Line; }
1106 public int StartColumn {
1107 get { return points[0].Col; }
1109 public int EndColumn {
1110 get { return points[count - 1].Col; }
1113 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1115 SequencePoint s = new SequencePoint ();
1119 s.EndLine = endLine;
1122 if (points == null) {
1123 points = new SequencePoint [arrayGrow];
1124 } else if (count >= points.Length) {
1125 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1126 Array.Copy (points, temp, points.Length);
1135 struct SequencePoint {