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 #pragma warning disable 169
66 #pragma warning disable 414
67 ILExceptionBlock[] handlers;
71 #pragma warning restore 169
72 #pragma warning restore 414
74 internal int NumHandlers ()
76 return handlers.Length;
79 internal void AddCatch (Type extype, int offset)
84 i = handlers.Length - 1;
85 handlers [i].type = ILExceptionBlock.CATCH;
86 handlers [i].start = offset;
87 handlers [i].extype = extype;
90 internal void AddFinally (int offset)
95 i = handlers.Length - 1;
96 handlers [i].type = ILExceptionBlock.FINALLY;
97 handlers [i].start = offset;
98 handlers [i].extype = null;
101 internal void AddFault (int offset)
106 i = handlers.Length - 1;
107 handlers [i].type = ILExceptionBlock.FAULT;
108 handlers [i].start = offset;
109 handlers [i].extype = null;
112 internal void AddFilter (int offset)
117 i = handlers.Length - 1;
118 handlers [i].type = ILExceptionBlock.FILTER_START;
119 handlers [i].extype = null;
120 handlers [i].filter_offset = offset;
123 internal void End (int offset)
125 if (handlers == null)
127 int i = handlers.Length - 1;
129 handlers [i].len = offset - handlers [i].start;
132 internal int LastClauseType ()
134 if (handlers != null)
135 return handlers [handlers.Length-1].type;
137 return ILExceptionBlock.CATCH;
140 internal void PatchFilterClause (int start)
142 if (handlers != null && handlers.Length > 0) {
143 handlers [handlers.Length - 1].start = start;
144 handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
148 internal void Debug (int b)
151 System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
152 for (int i = 0; i < handlers.Length; ++i)
153 handlers [i].Debug ();
157 void add_block (int offset)
159 if (handlers != null) {
160 int i = handlers.Length;
161 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
162 System.Array.Copy (handlers, new_b, i);
164 handlers [i].len = offset - handlers [i].start;
166 handlers = new ILExceptionBlock [1];
167 len = offset - start;
172 internal struct ILTokenInfo {
173 public MemberInfo member;
177 internal interface TokenGenerator {
178 int GetToken (string str);
180 int GetToken (MemberInfo member, bool create_open_instance);
182 int GetToken (MethodInfo method, Type[] opt_param_types);
184 int GetToken (SignatureHelper helper);
188 [ComDefaultInterface (typeof (_ILGenerator))]
189 [ClassInterface (ClassInterfaceType.None)]
190 [StructLayout (LayoutKind.Sequential)]
191 public class ILGenerator: _ILGenerator {
192 private struct LabelFixup {
193 public int offset; // The number of bytes between pos and the
194 // offset of the jump
195 public int pos; // Where offset of the label is placed
196 public int label_idx; // The label to jump to
200 public LabelData (int addr, int maxStack)
203 this.maxStack = maxStack;
210 static readonly Type void_type = typeof (void);
211 #region Sync with reflection.h
213 private int code_len;
214 private int max_stack;
215 private int cur_stack;
216 private LocalBuilder[] locals;
217 private ILExceptionInfo[] ex_handlers;
218 private int num_token_fixups;
219 private ILTokenInfo[] token_fixups;
222 private LabelData [] labels;
223 private int num_labels;
224 private LabelFixup[] fixups;
225 private int num_fixups;
226 internal Module module;
227 private int cur_block;
228 private Stack open_blocks;
229 private TokenGenerator token_gen;
231 const int defaultFixupSize = 4;
232 const int defaultLabelsSize = 4;
233 const int defaultExceptionStackSize = 2;
235 ArrayList sequencePointLists;
236 SequencePointList currentSequence;
238 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
242 code = new byte [size];
243 token_fixups = new ILTokenInfo [8];
245 this.token_gen = token_gen;
248 private void add_token_fixup (MemberInfo mi)
250 if (num_token_fixups == token_fixups.Length) {
251 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
252 token_fixups.CopyTo (ntf, 0);
255 token_fixups [num_token_fixups].member = mi;
256 token_fixups [num_token_fixups++].code_pos = code_len;
259 private void make_room (int nbytes)
261 if (code_len + nbytes < code.Length)
263 byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
264 System.Array.Copy (code, 0, new_code, 0, code.Length);
268 private void emit_int (int val)
270 code [code_len++] = (byte) (val & 0xFF);
271 code [code_len++] = (byte) ((val >> 8) & 0xFF);
272 code [code_len++] = (byte) ((val >> 16) & 0xFF);
273 code [code_len++] = (byte) ((val >> 24) & 0xFF);
276 /* change to pass by ref to avoid copy */
277 private void ll_emit (OpCode opcode)
280 * there is already enough room allocated in code.
282 // access op1 and op2 directly since the Value property is useless
283 if (opcode.Size == 2)
284 code [code_len++] = opcode.op1;
285 code [code_len++] = opcode.op2;
287 * We should probably keep track of stack needs here.
288 * Or we may want to run the verifier on the code before saving it
289 * (this may be needed anyway when the ILGenerator is not used...).
291 switch (opcode.StackBehaviourPush) {
292 case StackBehaviour.Push1:
293 case StackBehaviour.Pushi:
294 case StackBehaviour.Pushi8:
295 case StackBehaviour.Pushr4:
296 case StackBehaviour.Pushr8:
297 case StackBehaviour.Pushref:
298 case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
301 case StackBehaviour.Push1_push1:
305 if (max_stack < cur_stack)
306 max_stack = cur_stack;
309 * Note that we adjust for the pop behaviour _after_ setting max_stack.
311 switch (opcode.StackBehaviourPop) {
312 case StackBehaviour.Varpop:
313 break; /* we are conservative and assume it doesn't decrease the stack needs */
314 case StackBehaviour.Pop1:
315 case StackBehaviour.Popi:
316 case StackBehaviour.Popref:
319 case StackBehaviour.Pop1_pop1:
320 case StackBehaviour.Popi_pop1:
321 case StackBehaviour.Popi_popi:
322 case StackBehaviour.Popi_popi8:
323 case StackBehaviour.Popi_popr4:
324 case StackBehaviour.Popi_popr8:
325 case StackBehaviour.Popref_pop1:
326 case StackBehaviour.Popref_popi:
329 case StackBehaviour.Popi_popi_popi:
330 case StackBehaviour.Popref_popi_popi:
331 case StackBehaviour.Popref_popi_popi8:
332 case StackBehaviour.Popref_popi_popr4:
333 case StackBehaviour.Popref_popi_popr8:
334 case StackBehaviour.Popref_popi_popref:
340 private static int target_len (OpCode opcode)
342 if (opcode.OperandType == OperandType.InlineBrTarget)
347 private void InternalEndClause ()
349 switch (ex_handlers [cur_block].LastClauseType ()) {
350 case ILExceptionBlock.CATCH:
351 case ILExceptionBlock.FILTER:
352 case ILExceptionBlock.FILTER_START:
353 // how could we optimize code size here?
354 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
356 case ILExceptionBlock.FAULT:
357 case ILExceptionBlock.FINALLY:
358 Emit (OpCodes.Endfinally);
363 public virtual void BeginCatchBlock (Type exceptionType)
365 if (open_blocks == null)
366 open_blocks = new Stack (defaultExceptionStackSize);
368 if (open_blocks.Count <= 0)
369 throw new NotSupportedException ("Not in an exception block");
370 if (exceptionType != null && exceptionType.IsUserType)
371 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
372 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
373 if (exceptionType != null)
374 throw new ArgumentException ("Do not supply an exception type for filter clause");
375 Emit (OpCodes.Endfilter);
376 ex_handlers [cur_block].PatchFilterClause (code_len);
378 InternalEndClause ();
379 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
382 cur_stack = 1; // the exception object is on the stack by default
383 if (max_stack < cur_stack)
384 max_stack = cur_stack;
386 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
389 public virtual void BeginExceptFilterBlock ()
391 if (open_blocks == null)
392 open_blocks = new Stack (defaultExceptionStackSize);
394 if (open_blocks.Count <= 0)
395 throw new NotSupportedException ("Not in an exception block");
396 InternalEndClause ();
398 ex_handlers [cur_block].AddFilter (code_len);
401 public virtual Label BeginExceptionBlock ()
403 //System.Console.WriteLine ("Begin Block");
404 if (open_blocks == null)
405 open_blocks = new Stack (defaultExceptionStackSize);
407 if (ex_handlers != null) {
408 cur_block = ex_handlers.Length;
409 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
410 System.Array.Copy (ex_handlers, new_ex, cur_block);
411 ex_handlers = new_ex;
413 ex_handlers = new ILExceptionInfo [1];
416 open_blocks.Push (cur_block);
417 ex_handlers [cur_block].start = code_len;
418 return ex_handlers [cur_block].end = DefineLabel ();
421 public virtual void BeginFaultBlock()
423 if (open_blocks == null)
424 open_blocks = new Stack (defaultExceptionStackSize);
426 if (open_blocks.Count <= 0)
427 throw new NotSupportedException ("Not in an exception block");
429 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
430 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
431 ex_handlers [cur_block].PatchFilterClause (code_len);
434 InternalEndClause ();
435 //System.Console.WriteLine ("Begin fault Block");
436 ex_handlers [cur_block].AddFault (code_len);
439 public virtual void BeginFinallyBlock()
441 if (open_blocks == null)
442 open_blocks = new Stack (defaultExceptionStackSize);
444 if (open_blocks.Count <= 0)
445 throw new NotSupportedException ("Not in an exception block");
447 InternalEndClause ();
449 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
450 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
451 ex_handlers [cur_block].PatchFilterClause (code_len);
454 //System.Console.WriteLine ("Begin finally Block");
455 ex_handlers [cur_block].AddFinally (code_len);
458 public virtual void BeginScope ()
461 public virtual LocalBuilder DeclareLocal (Type localType)
463 return DeclareLocal (localType, false);
467 public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
469 if (localType == null)
470 throw new ArgumentNullException ("localType");
471 if (localType.IsUserType)
472 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
473 LocalBuilder res = new LocalBuilder (localType, this);
474 res.is_pinned = pinned;
476 if (locals != null) {
477 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
478 System.Array.Copy (locals, new_l, locals.Length);
479 new_l [locals.Length] = res;
482 locals = new LocalBuilder [1];
485 res.position = (ushort)(locals.Length - 1);
489 public virtual Label DefineLabel ()
492 labels = new LabelData [defaultLabelsSize];
493 else if (num_labels >= labels.Length) {
494 LabelData [] t = new LabelData [labels.Length * 2];
495 Array.Copy (labels, t, labels.Length);
499 labels [num_labels] = new LabelData (-1, 0);
501 return new Label (num_labels++);
504 public virtual void Emit (OpCode opcode)
510 public virtual void Emit (OpCode opcode, Byte arg)
514 code [code_len++] = arg;
518 public virtual void Emit (OpCode opcode, ConstructorInfo con)
520 int token = token_gen.GetToken (con, true);
523 if (con.DeclaringType.Module == module)
524 add_token_fixup (con);
527 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
528 cur_stack -= con.GetParameterCount ();
531 public virtual void Emit (OpCode opcode, double arg)
533 byte[] s = System.BitConverter.GetBytes (arg);
536 if (BitConverter.IsLittleEndian){
537 System.Array.Copy (s, 0, code, code_len, 8);
540 code [code_len++] = s [7];
541 code [code_len++] = s [6];
542 code [code_len++] = s [5];
543 code [code_len++] = s [4];
544 code [code_len++] = s [3];
545 code [code_len++] = s [2];
546 code [code_len++] = s [1];
547 code [code_len++] = s [0];
551 public virtual void Emit (OpCode opcode, FieldInfo field)
553 int token = token_gen.GetToken (field, true);
556 if (field.DeclaringType.Module == module)
557 add_token_fixup (field);
561 public virtual void Emit (OpCode opcode, Int16 arg)
565 code [code_len++] = (byte) (arg & 0xFF);
566 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
569 public virtual void Emit (OpCode opcode, int arg)
576 public virtual void Emit (OpCode opcode, long arg)
580 code [code_len++] = (byte) (arg & 0xFF);
581 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
582 code [code_len++] = (byte) ((arg >> 16) & 0xFF);
583 code [code_len++] = (byte) ((arg >> 24) & 0xFF);
584 code [code_len++] = (byte) ((arg >> 32) & 0xFF);
585 code [code_len++] = (byte) ((arg >> 40) & 0xFF);
586 code [code_len++] = (byte) ((arg >> 48) & 0xFF);
587 code [code_len++] = (byte) ((arg >> 56) & 0xFF);
590 public virtual void Emit (OpCode opcode, Label label)
592 int tlen = target_len (opcode);
595 if (cur_stack > labels [label.label].maxStack)
596 labels [label.label].maxStack = cur_stack;
599 fixups = new LabelFixup [defaultFixupSize];
600 else if (num_fixups >= fixups.Length) {
601 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
602 System.Array.Copy (fixups, newf, fixups.Length);
605 fixups [num_fixups].offset = tlen;
606 fixups [num_fixups].pos = code_len;
607 fixups [num_fixups].label_idx = label.label;
613 public virtual void Emit (OpCode opcode, Label[] labels)
616 throw new ArgumentNullException ("labels");
618 /* opcode needs to be switch. */
619 int count = labels.Length;
620 make_room (6 + count * 4);
623 for (int i = 0; i < count; ++i)
624 if (cur_stack > this.labels [labels [i].label].maxStack)
625 this.labels [labels [i].label].maxStack = cur_stack;
629 fixups = new LabelFixup [defaultFixupSize + count];
630 else if (num_fixups + count >= fixups.Length) {
631 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
632 System.Array.Copy (fixups, newf, fixups.Length);
636 // ECMA 335, Partition III, p94 (7-10)
638 // The switch instruction implements a jump table. The format of
639 // the instruction is an unsigned int32 representing the number of targets N,
640 // followed by N int32 values specifying jump targets: these targets are
641 // represented as offsets (positive or negative) from the beginning of the
642 // instruction following this switch instruction.
644 // We must make sure it gets an offset from the *end* of the last label
645 // (eg, the beginning of the instruction following this).
647 // remaining is the number of bytes from the current instruction to the
648 // instruction that will be emitted.
650 for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
651 fixups [num_fixups].offset = remaining;
652 fixups [num_fixups].pos = code_len;
653 fixups [num_fixups].label_idx = labels [i].label;
659 public virtual void Emit (OpCode opcode, LocalBuilder local)
662 throw new ArgumentNullException ("local");
663 if (local.ilgen != this)
664 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
666 uint pos = local.position;
667 bool load_addr = false;
668 bool is_store = false;
669 bool is_load = false;
672 /* inline the code from ll_emit () to optimize il code size */
673 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
676 } else if (opcode.StackBehaviourPush == StackBehaviour.Push1 || opcode.StackBehaviourPush == StackBehaviour.Pushi) {
679 if (cur_stack > max_stack)
680 max_stack = cur_stack;
681 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
685 code [code_len++] = (byte)0x12;
686 code [code_len++] = (byte)pos;
688 code [code_len++] = (byte)0xfe;
689 code [code_len++] = (byte)0x0d;
690 code [code_len++] = (byte)(pos & 0xff);
691 code [code_len++] = (byte)((pos >> 8) & 0xff);
696 code [code_len++] = (byte)(0x0a + pos);
697 } else if (pos < 256) {
698 code [code_len++] = (byte)0x13;
699 code [code_len++] = (byte)pos;
701 code [code_len++] = (byte)0xfe;
702 code [code_len++] = (byte)0x0e;
703 code [code_len++] = (byte)(pos & 0xff);
704 code [code_len++] = (byte)((pos >> 8) & 0xff);
706 } else if (is_load) {
708 code [code_len++] = (byte)(0x06 + pos);
709 } else if (pos < 256) {
710 code [code_len++] = (byte)0x11;
711 code [code_len++] = (byte)pos;
713 code [code_len++] = (byte)0xfe;
714 code [code_len++] = (byte)0x0c;
715 code [code_len++] = (byte)(pos & 0xff);
716 code [code_len++] = (byte)((pos >> 8) & 0xff);
724 public virtual void Emit (OpCode opcode, MethodInfo meth)
727 throw new ArgumentNullException ("meth");
729 // For compatibility with MS
730 if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
731 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
733 int token = token_gen.GetToken (meth, true);
736 Type declaringType = meth.DeclaringType;
737 // Might be a DynamicMethod with no declaring type
738 if (declaringType != null) {
739 if (declaringType.Module == module)
740 add_token_fixup (meth);
743 if (meth.ReturnType != void_type)
746 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
747 cur_stack -= meth.GetParameterCount ();
750 private void Emit (OpCode opcode, MethodInfo method, int token)
754 // Might be a DynamicMethod with no declaring type
755 Type declaringType = method.DeclaringType;
756 if (declaringType != null) {
757 if (declaringType.Module == module)
758 add_token_fixup (method);
761 if (method.ReturnType != void_type)
764 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
765 cur_stack -= method.GetParameterCount ();
768 [CLSCompliant(false)]
769 public void Emit (OpCode opcode, sbyte arg)
773 code [code_len++] = (byte)arg;
776 public virtual void Emit (OpCode opcode, SignatureHelper signature)
778 int token = token_gen.GetToken (signature);
784 public virtual void Emit (OpCode opcode, float arg)
786 byte[] s = System.BitConverter.GetBytes (arg);
789 if (BitConverter.IsLittleEndian){
790 System.Array.Copy (s, 0, code, code_len, 4);
793 code [code_len++] = s [3];
794 code [code_len++] = s [2];
795 code [code_len++] = s [1];
796 code [code_len++] = s [0];
800 public virtual void Emit (OpCode opcode, string str)
802 int token = token_gen.GetToken (str);
808 public virtual void Emit (OpCode opcode, Type cls)
810 if (cls != null && cls.IsByRef)
811 throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
815 emit_int (token_gen.GetToken (cls, opcode != OpCodes.Ldtoken));
818 [MonoLimitation ("vararg methods are not supported")]
819 public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
821 if (methodInfo == null)
822 throw new ArgumentNullException ("methodInfo");
823 short value = opcode.Value;
824 if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
825 throw new NotSupportedException ("Only Call and CallVirt are allowed");
826 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
827 optionalParameterTypes = null;
828 if (optionalParameterTypes != null){
829 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
830 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
833 int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
834 Emit (opcode, methodInfo, token);
837 Emit (opcode, methodInfo);
840 public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
842 // GetMethodSigHelper expects a ModuleBuilder or null, and module might be
843 // a normal module when using dynamic methods.
844 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, 0, unmanagedCallConv, returnType, parameterTypes);
845 Emit (opcode, helper);
848 public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
850 if (optionalParameterTypes != null)
851 throw new NotImplementedException ();
853 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, callingConvention, 0, returnType, parameterTypes);
854 Emit (opcode, helper);
857 public virtual void EmitWriteLine (FieldInfo fld)
860 throw new ArgumentNullException ("fld");
862 // The MS implementation does not check for valuetypes here but it
863 // should. Also, it should check that if the field is not static,
864 // then it is a member of this type.
866 Emit (OpCodes.Ldsfld, fld);
868 Emit (OpCodes.Ldarg_0);
869 Emit (OpCodes.Ldfld, fld);
871 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
874 public virtual void EmitWriteLine (LocalBuilder localBuilder)
876 if (localBuilder == null)
877 throw new ArgumentNullException ("localBuilder");
878 if (localBuilder.LocalType is TypeBuilder)
879 throw new ArgumentException ("Output streams do not support TypeBuilders.");
880 // The MS implementation does not check for valuetypes here but it
882 Emit (OpCodes.Ldloc, localBuilder);
883 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
886 public virtual void EmitWriteLine (string value)
888 Emit (OpCodes.Ldstr, value);
889 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
892 public virtual void EndExceptionBlock ()
894 if (open_blocks == null)
895 open_blocks = new Stack (defaultExceptionStackSize);
897 if (open_blocks.Count <= 0)
898 throw new NotSupportedException ("Not in an exception block");
900 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
901 throw new InvalidOperationException ("Incorrect code generation for exception block.");
903 InternalEndClause ();
904 MarkLabel (ex_handlers [cur_block].end);
905 ex_handlers [cur_block].End (code_len);
906 ex_handlers [cur_block].Debug (cur_block);
907 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
909 if (open_blocks.Count > 0)
910 cur_block = (int)open_blocks.Peek ();
911 //Console.WriteLine ("curblock restored to {0}", cur_block);
912 //throw new NotImplementedException ();
915 public virtual void EndScope ()
918 public virtual void MarkLabel (Label loc)
920 if (loc.label < 0 || loc.label >= num_labels)
921 throw new System.ArgumentException ("The label is not valid");
922 if (labels [loc.label].addr >= 0)
923 throw new System.ArgumentException ("The label was already defined");
924 labels [loc.label].addr = code_len;
925 if (labels [loc.label].maxStack > cur_stack)
926 cur_stack = labels [loc.label].maxStack;
929 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
930 int startColumn, int endLine, int endColumn)
932 if (currentSequence == null || currentSequence.Document != document) {
933 if (sequencePointLists == null)
934 sequencePointLists = new ArrayList ();
935 currentSequence = new SequencePointList (document);
936 sequencePointLists.Add (currentSequence);
939 currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
942 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
944 if (sequencePointLists != null) {
945 SequencePointList first = (SequencePointList) sequencePointLists [0];
946 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
947 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
949 foreach (SequencePointList list in sequencePointLists)
950 symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
952 if (locals != null) {
953 foreach (LocalBuilder local in locals) {
954 if (local.Name != null && local.Name.Length > 0) {
955 SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module as ModuleBuilder);
956 sighelper.AddArgument (local.LocalType);
957 byte[] signature = sighelper.GetSignature ();
958 symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
962 sequencePointLists = null;
966 internal bool HasDebugInfo
968 get { return sequencePointLists != null; }
971 public virtual void ThrowException (Type excType)
974 throw new ArgumentNullException ("excType");
975 if (! ((excType == typeof (Exception)) ||
976 excType.IsSubclassOf (typeof (Exception))))
977 throw new ArgumentException ("Type should be an exception type", "excType");
978 ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
980 throw new ArgumentException ("Type should have a default constructor", "excType");
981 Emit (OpCodes.Newobj, ctor);
982 Emit (OpCodes.Throw);
985 [MonoTODO("Not implemented")]
986 public virtual void UsingNamespace (String usingNamespace)
988 throw new NotImplementedException ();
991 internal void label_fixup ()
993 for (int i = 0; i < num_fixups; ++i) {
994 if (labels [fixups [i].label_idx].addr < 0)
995 throw new ArgumentException ("Label not marked");
996 // Diff is the offset from the end of the jump instruction to the address of the label
997 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
998 if (fixups [i].offset == 1) {
999 code [fixups [i].pos] = (byte)((sbyte) diff);
1001 int old_cl = code_len;
1002 code_len = fixups [i].pos;
1009 // Used by DynamicILGenerator
1010 internal void SetCode (byte[] code, int max_stack) {
1011 // Make a copy to avoid possible security problems
1012 this.code = (byte[])code.Clone ();
1013 this.code_len = code.Length;
1014 this.max_stack = max_stack;
1018 internal unsafe void SetCode (byte *code, int code_size, int max_stack) {
1019 // Make a copy to avoid possible security problems
1020 this.code = new byte [code_size];
1021 for (int i = 0; i < code_size; ++i)
1022 this.code [i] = code [i];
1023 this.code_len = code_size;
1024 this.max_stack = max_stack;
1028 internal TokenGenerator TokenGenerator {
1034 // Still used by symbolwriter
1035 [Obsolete ("Use ILOffset", true)]
1036 internal static int Mono_GetCurrentOffset (ILGenerator ig)
1046 virtual int ILOffset {
1047 get { return code_len; }
1050 void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1052 throw new NotImplementedException ();
1055 void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1057 throw new NotImplementedException ();
1060 void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
1062 throw new NotImplementedException ();
1065 void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1067 throw new NotImplementedException ();
1071 internal class SequencePointList
1073 ISymbolDocumentWriter doc;
1074 SequencePoint[] points;
1076 const int arrayGrow = 10;
1078 public SequencePointList (ISymbolDocumentWriter doc)
1083 public ISymbolDocumentWriter Document {
1087 public int[] GetOffsets()
1089 int[] data = new int [count];
1090 for (int n=0; n<count; n++) data [n] = points[n].Offset;
1093 public int[] GetLines()
1095 int[] data = new int [count];
1096 for (int n=0; n<count; n++) data [n] = points[n].Line;
1099 public int[] GetColumns()
1101 int[] data = new int [count];
1102 for (int n=0; n<count; n++) data [n] = points[n].Col;
1105 public int[] GetEndLines()
1107 int[] data = new int [count];
1108 for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1111 public int[] GetEndColumns()
1113 int[] data = new int [count];
1114 for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1117 public int StartLine {
1118 get { return points[0].Line; }
1120 public int EndLine {
1121 get { return points[count - 1].Line; }
1123 public int StartColumn {
1124 get { return points[0].Col; }
1126 public int EndColumn {
1127 get { return points[count - 1].Col; }
1130 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1132 SequencePoint s = new SequencePoint ();
1136 s.EndLine = endLine;
1139 if (points == null) {
1140 points = new SequencePoint [arrayGrow];
1141 } else if (count >= points.Length) {
1142 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1143 Array.Copy (points, temp, points.Length);
1152 struct SequencePoint {