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
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Diagnostics.SymbolStore;
39 using System.Runtime.InteropServices;
41 namespace System.Reflection.Emit {
43 internal struct ILExceptionBlock {
44 public const int CATCH = 0;
45 public const int FILTER = 1;
46 public const int FINALLY = 2;
47 public const int FAULT = 4;
48 public const int FILTER_START = -1;
54 internal int filter_offset;
56 internal void Debug () {
58 System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
60 System.Console.WriteLine (" extype="+extype.ToString());
62 System.Console.WriteLine (String.Empty);
66 internal struct ILExceptionInfo {
67 #pragma warning disable 169
68 #pragma warning disable 414
69 internal ILExceptionBlock[] handlers;
73 #pragma warning restore 169
74 #pragma warning restore 414
76 internal int NumHandlers ()
78 return handlers.Length;
81 internal void AddCatch (Type extype, int offset)
86 i = handlers.Length - 1;
87 handlers [i].type = ILExceptionBlock.CATCH;
88 handlers [i].start = offset;
89 handlers [i].extype = extype;
92 internal void AddFinally (int offset)
97 i = handlers.Length - 1;
98 handlers [i].type = ILExceptionBlock.FINALLY;
99 handlers [i].start = offset;
100 handlers [i].extype = null;
103 internal void AddFault (int offset)
108 i = handlers.Length - 1;
109 handlers [i].type = ILExceptionBlock.FAULT;
110 handlers [i].start = offset;
111 handlers [i].extype = null;
114 internal void AddFilter (int offset)
119 i = handlers.Length - 1;
120 handlers [i].type = ILExceptionBlock.FILTER_START;
121 handlers [i].extype = null;
122 handlers [i].filter_offset = offset;
125 internal void End (int offset)
127 if (handlers == null)
129 int i = handlers.Length - 1;
131 handlers [i].len = offset - handlers [i].start;
134 internal int LastClauseType ()
136 if (handlers != null)
137 return handlers [handlers.Length-1].type;
139 return ILExceptionBlock.CATCH;
142 internal void PatchFilterClause (int start)
144 if (handlers != null && handlers.Length > 0) {
145 handlers [handlers.Length - 1].start = start;
146 handlers [handlers.Length - 1].type = ILExceptionBlock.FILTER;
150 internal void Debug (int b)
153 System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
154 for (int i = 0; i < handlers.Length; ++i)
155 handlers [i].Debug ();
159 void add_block (int offset)
161 if (handlers != null) {
162 int i = handlers.Length;
163 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
164 System.Array.Copy (handlers, new_b, i);
166 handlers [i].len = offset - handlers [i].start;
168 handlers = new ILExceptionBlock [1];
169 len = offset - start;
174 internal struct ILTokenInfo {
175 public MemberInfo member;
179 internal interface TokenGenerator {
180 int GetToken (string str);
182 int GetToken (MemberInfo member, bool create_open_instance);
184 int GetToken (MethodBase method, Type[] opt_param_types);
186 int GetToken (SignatureHelper helper);
190 [ComDefaultInterface (typeof (_ILGenerator))]
191 [ClassInterface (ClassInterfaceType.None)]
192 [StructLayout (LayoutKind.Sequential)]
193 public class ILGenerator: _ILGenerator {
194 private struct LabelFixup {
195 public int offset; // The number of bytes between pos and the
196 // offset of the jump
197 public int pos; // Where offset of the label is placed
198 public int label_idx; // The label to jump to
202 public LabelData (int addr, int maxStack)
205 this.maxStack = maxStack;
212 #region Sync with reflection.h
214 private int code_len;
215 private int max_stack;
216 private int cur_stack;
217 private LocalBuilder[] locals;
218 private ILExceptionInfo[] ex_handlers;
219 private int num_token_fixups;
220 private ILTokenInfo[] token_fixups;
223 private LabelData [] labels;
224 private int num_labels;
225 private LabelFixup[] fixups;
226 private int num_fixups;
227 internal Module module;
228 private int cur_block;
229 private Stack open_blocks;
230 private TokenGenerator token_gen;
232 const int defaultFixupSize = 4;
233 const int defaultLabelsSize = 4;
234 const int defaultExceptionStackSize = 2;
236 ArrayList sequencePointLists;
237 SequencePointList currentSequence;
239 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
243 code = new byte [size];
244 token_fixups = new ILTokenInfo [8];
246 this.token_gen = token_gen;
249 private void add_token_fixup (MemberInfo mi)
251 if (num_token_fixups == token_fixups.Length) {
252 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
253 token_fixups.CopyTo (ntf, 0);
256 token_fixups [num_token_fixups].member = mi;
257 token_fixups [num_token_fixups++].code_pos = code_len;
260 private void make_room (int nbytes)
262 if (code_len + nbytes < code.Length)
264 byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
265 System.Array.Copy (code, 0, new_code, 0, code.Length);
269 private void emit_int (int val)
271 code [code_len++] = (byte) (val & 0xFF);
272 code [code_len++] = (byte) ((val >> 8) & 0xFF);
273 code [code_len++] = (byte) ((val >> 16) & 0xFF);
274 code [code_len++] = (byte) ((val >> 24) & 0xFF);
277 /* change to pass by ref to avoid copy */
278 private void ll_emit (OpCode opcode)
281 * there is already enough room allocated in code.
283 // access op1 and op2 directly since the Value property is useless
284 if (opcode.Size == 2)
285 code [code_len++] = opcode.op1;
286 code [code_len++] = opcode.op2;
288 * We should probably keep track of stack needs here.
289 * Or we may want to run the verifier on the code before saving it
290 * (this may be needed anyway when the ILGenerator is not used...).
292 switch (opcode.StackBehaviourPush) {
293 case StackBehaviour.Push1:
294 case StackBehaviour.Pushi:
295 case StackBehaviour.Pushi8:
296 case StackBehaviour.Pushr4:
297 case StackBehaviour.Pushr8:
298 case StackBehaviour.Pushref:
299 case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
302 case StackBehaviour.Push1_push1:
306 if (max_stack < cur_stack)
307 max_stack = cur_stack;
310 * Note that we adjust for the pop behaviour _after_ setting max_stack.
312 switch (opcode.StackBehaviourPop) {
313 case StackBehaviour.Varpop:
314 break; /* we are conservative and assume it doesn't decrease the stack needs */
315 case StackBehaviour.Pop1:
316 case StackBehaviour.Popi:
317 case StackBehaviour.Popref:
320 case StackBehaviour.Pop1_pop1:
321 case StackBehaviour.Popi_pop1:
322 case StackBehaviour.Popi_popi:
323 case StackBehaviour.Popi_popi8:
324 case StackBehaviour.Popi_popr4:
325 case StackBehaviour.Popi_popr8:
326 case StackBehaviour.Popref_pop1:
327 case StackBehaviour.Popref_popi:
330 case StackBehaviour.Popi_popi_popi:
331 case StackBehaviour.Popref_popi_popi:
332 case StackBehaviour.Popref_popi_popi8:
333 case StackBehaviour.Popref_popi_popr4:
334 case StackBehaviour.Popref_popi_popr8:
335 case StackBehaviour.Popref_popi_popref:
341 private static int target_len (OpCode opcode)
343 if (opcode.OperandType == OperandType.InlineBrTarget)
348 private void InternalEndClause ()
350 switch (ex_handlers [cur_block].LastClauseType ()) {
351 case ILExceptionBlock.CATCH:
352 case ILExceptionBlock.FILTER:
353 case ILExceptionBlock.FILTER_START:
354 // how could we optimize code size here?
355 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
357 case ILExceptionBlock.FAULT:
358 case ILExceptionBlock.FINALLY:
359 Emit (OpCodes.Endfinally);
364 public virtual void BeginCatchBlock (Type exceptionType)
366 if (open_blocks == null)
367 open_blocks = new Stack (defaultExceptionStackSize);
369 if (open_blocks.Count <= 0)
370 throw new NotSupportedException ("Not in an exception block");
371 if (exceptionType != null && exceptionType.IsUserType)
372 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
373 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
374 if (exceptionType != null)
375 throw new ArgumentException ("Do not supply an exception type for filter clause");
376 Emit (OpCodes.Endfilter);
377 ex_handlers [cur_block].PatchFilterClause (code_len);
379 InternalEndClause ();
380 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
383 cur_stack = 1; // the exception object is on the stack by default
384 if (max_stack < cur_stack)
385 max_stack = cur_stack;
387 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
390 public virtual void BeginExceptFilterBlock ()
392 if (open_blocks == null)
393 open_blocks = new Stack (defaultExceptionStackSize);
395 if (open_blocks.Count <= 0)
396 throw new NotSupportedException ("Not in an exception block");
397 InternalEndClause ();
399 ex_handlers [cur_block].AddFilter (code_len);
402 public virtual Label BeginExceptionBlock ()
404 //System.Console.WriteLine ("Begin Block");
405 if (open_blocks == null)
406 open_blocks = new Stack (defaultExceptionStackSize);
408 if (ex_handlers != null) {
409 cur_block = ex_handlers.Length;
410 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
411 System.Array.Copy (ex_handlers, new_ex, cur_block);
412 ex_handlers = new_ex;
414 ex_handlers = new ILExceptionInfo [1];
417 open_blocks.Push (cur_block);
418 ex_handlers [cur_block].start = code_len;
419 return ex_handlers [cur_block].end = DefineLabel ();
422 public virtual void BeginFaultBlock()
424 if (open_blocks == null)
425 open_blocks = new Stack (defaultExceptionStackSize);
427 if (open_blocks.Count <= 0)
428 throw new NotSupportedException ("Not in an exception block");
430 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
431 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
432 ex_handlers [cur_block].PatchFilterClause (code_len);
435 InternalEndClause ();
436 //System.Console.WriteLine ("Begin fault Block");
437 ex_handlers [cur_block].AddFault (code_len);
440 public virtual void BeginFinallyBlock()
442 if (open_blocks == null)
443 open_blocks = new Stack (defaultExceptionStackSize);
445 if (open_blocks.Count <= 0)
446 throw new NotSupportedException ("Not in an exception block");
448 InternalEndClause ();
450 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
451 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
452 ex_handlers [cur_block].PatchFilterClause (code_len);
455 //System.Console.WriteLine ("Begin finally Block");
456 ex_handlers [cur_block].AddFinally (code_len);
459 public virtual void BeginScope ()
462 public virtual LocalBuilder DeclareLocal (Type localType)
464 return DeclareLocal (localType, false);
468 public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
470 if (localType == null)
471 throw new ArgumentNullException ("localType");
472 if (localType.IsUserType)
473 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
474 LocalBuilder res = new LocalBuilder (localType, this);
475 res.is_pinned = pinned;
477 if (locals != null) {
478 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
479 System.Array.Copy (locals, new_l, locals.Length);
480 new_l [locals.Length] = res;
483 locals = new LocalBuilder [1];
486 res.position = (ushort)(locals.Length - 1);
490 public virtual Label DefineLabel ()
493 labels = new LabelData [defaultLabelsSize];
494 else if (num_labels >= labels.Length) {
495 LabelData [] t = new LabelData [labels.Length * 2];
496 Array.Copy (labels, t, labels.Length);
500 labels [num_labels] = new LabelData (-1, 0);
502 return new Label (num_labels++);
505 public virtual void Emit (OpCode opcode)
511 public virtual void Emit (OpCode opcode, Byte arg)
515 code [code_len++] = arg;
519 public virtual void Emit (OpCode opcode, ConstructorInfo con)
521 int token = token_gen.GetToken (con, true);
524 if (con.DeclaringType.Module == module)
525 add_token_fixup (con);
528 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
529 cur_stack -= con.GetParametersCount ();
532 public virtual void Emit (OpCode opcode, double arg)
534 byte[] s = System.BitConverter.GetBytes (arg);
537 if (BitConverter.IsLittleEndian){
538 System.Array.Copy (s, 0, code, code_len, 8);
541 code [code_len++] = s [7];
542 code [code_len++] = s [6];
543 code [code_len++] = s [5];
544 code [code_len++] = s [4];
545 code [code_len++] = s [3];
546 code [code_len++] = s [2];
547 code [code_len++] = s [1];
548 code [code_len++] = s [0];
552 public virtual void Emit (OpCode opcode, FieldInfo field)
554 int token = token_gen.GetToken (field, true);
557 if (field.DeclaringType.Module == module)
558 add_token_fixup (field);
562 public virtual void Emit (OpCode opcode, Int16 arg)
566 code [code_len++] = (byte) (arg & 0xFF);
567 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
570 public virtual void Emit (OpCode opcode, int arg)
577 public virtual void Emit (OpCode opcode, long arg)
581 code [code_len++] = (byte) (arg & 0xFF);
582 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
583 code [code_len++] = (byte) ((arg >> 16) & 0xFF);
584 code [code_len++] = (byte) ((arg >> 24) & 0xFF);
585 code [code_len++] = (byte) ((arg >> 32) & 0xFF);
586 code [code_len++] = (byte) ((arg >> 40) & 0xFF);
587 code [code_len++] = (byte) ((arg >> 48) & 0xFF);
588 code [code_len++] = (byte) ((arg >> 56) & 0xFF);
591 public virtual void Emit (OpCode opcode, Label label)
593 int tlen = target_len (opcode);
596 if (cur_stack > labels [label.label].maxStack)
597 labels [label.label].maxStack = cur_stack;
600 fixups = new LabelFixup [defaultFixupSize];
601 else if (num_fixups >= fixups.Length) {
602 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
603 System.Array.Copy (fixups, newf, fixups.Length);
606 fixups [num_fixups].offset = tlen;
607 fixups [num_fixups].pos = code_len;
608 fixups [num_fixups].label_idx = label.label;
614 public virtual void Emit (OpCode opcode, Label[] labels)
617 throw new ArgumentNullException ("labels");
619 /* opcode needs to be switch. */
620 int count = labels.Length;
621 make_room (6 + count * 4);
624 for (int i = 0; i < count; ++i)
625 if (cur_stack > this.labels [labels [i].label].maxStack)
626 this.labels [labels [i].label].maxStack = cur_stack;
630 fixups = new LabelFixup [defaultFixupSize + count];
631 else if (num_fixups + count >= fixups.Length) {
632 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
633 System.Array.Copy (fixups, newf, fixups.Length);
637 // ECMA 335, Partition III, p94 (7-10)
639 // The switch instruction implements a jump table. The format of
640 // the instruction is an unsigned int32 representing the number of targets N,
641 // followed by N int32 values specifying jump targets: these targets are
642 // represented as offsets (positive or negative) from the beginning of the
643 // instruction following this switch instruction.
645 // We must make sure it gets an offset from the *end* of the last label
646 // (eg, the beginning of the instruction following this).
648 // remaining is the number of bytes from the current instruction to the
649 // instruction that will be emitted.
651 for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
652 fixups [num_fixups].offset = remaining;
653 fixups [num_fixups].pos = code_len;
654 fixups [num_fixups].label_idx = labels [i].label;
660 public virtual void Emit (OpCode opcode, LocalBuilder local)
663 throw new ArgumentNullException ("local");
664 if (local.ilgen != this)
665 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
667 uint pos = local.position;
668 bool load_addr = false;
669 bool is_store = false;
670 bool is_load = false;
673 /* inline the code from ll_emit () to optimize il code size */
674 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
677 } else if (opcode.StackBehaviourPush == StackBehaviour.Push1 || opcode.StackBehaviourPush == StackBehaviour.Pushi) {
680 if (cur_stack > max_stack)
681 max_stack = cur_stack;
682 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
686 code [code_len++] = (byte)0x12;
687 code [code_len++] = (byte)pos;
689 code [code_len++] = (byte)0xfe;
690 code [code_len++] = (byte)0x0d;
691 code [code_len++] = (byte)(pos & 0xff);
692 code [code_len++] = (byte)((pos >> 8) & 0xff);
697 code [code_len++] = (byte)(0x0a + pos);
698 } else if (pos < 256) {
699 code [code_len++] = (byte)0x13;
700 code [code_len++] = (byte)pos;
702 code [code_len++] = (byte)0xfe;
703 code [code_len++] = (byte)0x0e;
704 code [code_len++] = (byte)(pos & 0xff);
705 code [code_len++] = (byte)((pos >> 8) & 0xff);
707 } else if (is_load) {
709 code [code_len++] = (byte)(0x06 + pos);
710 } else if (pos < 256) {
711 code [code_len++] = (byte)0x11;
712 code [code_len++] = (byte)pos;
714 code [code_len++] = (byte)0xfe;
715 code [code_len++] = (byte)0x0c;
716 code [code_len++] = (byte)(pos & 0xff);
717 code [code_len++] = (byte)((pos >> 8) & 0xff);
725 public virtual void Emit (OpCode opcode, MethodInfo meth)
728 throw new ArgumentNullException ("meth");
730 // For compatibility with MS
731 if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
732 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
734 int token = token_gen.GetToken (meth, true);
737 Type declaringType = meth.DeclaringType;
738 // Might be a DynamicMethod with no declaring type
739 if (declaringType != null) {
740 if (declaringType.Module == module)
741 add_token_fixup (meth);
744 if (meth.ReturnType != typeof (void))
747 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
748 cur_stack -= meth.GetParametersCount ();
751 private void Emit (OpCode opcode, MethodInfo method, int token)
755 // Might be a DynamicMethod with no declaring type
756 Type declaringType = method.DeclaringType;
757 if (declaringType != null) {
758 if (declaringType.Module == module)
759 add_token_fixup (method);
762 if (method.ReturnType != typeof (void))
765 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
766 cur_stack -= method.GetParametersCount ();
769 [CLSCompliant(false)]
770 public void Emit (OpCode opcode, sbyte arg)
774 code [code_len++] = (byte)arg;
777 public virtual void Emit (OpCode opcode, SignatureHelper signature)
779 int token = token_gen.GetToken (signature);
785 public virtual void Emit (OpCode opcode, float arg)
787 byte[] s = System.BitConverter.GetBytes (arg);
790 if (BitConverter.IsLittleEndian){
791 System.Array.Copy (s, 0, code, code_len, 4);
794 code [code_len++] = s [3];
795 code [code_len++] = s [2];
796 code [code_len++] = s [1];
797 code [code_len++] = s [0];
801 public virtual void Emit (OpCode opcode, string str)
803 int token = token_gen.GetToken (str);
809 public virtual void Emit (OpCode opcode, Type cls)
811 if (cls != null && cls.IsByRef)
812 throw new ArgumentException ("Cannot get TypeToken for a ByRef type.");
816 emit_int (token_gen.GetToken (cls, opcode != OpCodes.Ldtoken));
819 [MonoLimitation ("vararg methods are not supported")]
820 public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
822 if (methodInfo == null)
823 throw new ArgumentNullException ("methodInfo");
824 short value = opcode.Value;
825 if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
826 throw new NotSupportedException ("Only Call and CallVirt are allowed");
827 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
828 optionalParameterTypes = null;
829 if (optionalParameterTypes != null){
830 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
831 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
834 int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
835 Emit (opcode, methodInfo, token);
838 Emit (opcode, methodInfo);
841 public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
843 // GetMethodSigHelper expects a ModuleBuilder or null, and module might be
844 // a normal module when using dynamic methods.
845 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, 0, unmanagedCallConv, returnType, parameterTypes);
846 Emit (opcode, helper);
849 public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
851 if (optionalParameterTypes != null)
852 throw new NotImplementedException ();
854 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module as ModuleBuilder, callingConvention, 0, returnType, parameterTypes);
855 Emit (opcode, helper);
858 public virtual void EmitWriteLine (FieldInfo fld)
861 throw new ArgumentNullException ("fld");
863 // The MS implementation does not check for valuetypes here but it
864 // should. Also, it should check that if the field is not static,
865 // then it is a member of this type.
867 Emit (OpCodes.Ldsfld, fld);
869 Emit (OpCodes.Ldarg_0);
870 Emit (OpCodes.Ldfld, fld);
872 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
875 public virtual void EmitWriteLine (LocalBuilder localBuilder)
877 if (localBuilder == null)
878 throw new ArgumentNullException ("localBuilder");
879 if (localBuilder.LocalType is TypeBuilder)
880 throw new ArgumentException ("Output streams do not support TypeBuilders.");
881 // The MS implementation does not check for valuetypes here but it
883 Emit (OpCodes.Ldloc, localBuilder);
884 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
887 public virtual void EmitWriteLine (string value)
889 Emit (OpCodes.Ldstr, value);
890 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
893 public virtual void EndExceptionBlock ()
895 if (open_blocks == null)
896 open_blocks = new Stack (defaultExceptionStackSize);
898 if (open_blocks.Count <= 0)
899 throw new NotSupportedException ("Not in an exception block");
901 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
902 throw new InvalidOperationException ("Incorrect code generation for exception block.");
904 InternalEndClause ();
905 MarkLabel (ex_handlers [cur_block].end);
906 ex_handlers [cur_block].End (code_len);
907 ex_handlers [cur_block].Debug (cur_block);
908 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
910 if (open_blocks.Count > 0)
911 cur_block = (int)open_blocks.Peek ();
912 //Console.WriteLine ("curblock restored to {0}", cur_block);
913 //throw new NotImplementedException ();
916 public virtual void EndScope ()
919 public virtual void MarkLabel (Label loc)
921 if (loc.label < 0 || loc.label >= num_labels)
922 throw new System.ArgumentException ("The label is not valid");
923 if (labels [loc.label].addr >= 0)
924 throw new System.ArgumentException ("The label was already defined");
925 labels [loc.label].addr = code_len;
926 if (labels [loc.label].maxStack > cur_stack)
927 cur_stack = labels [loc.label].maxStack;
930 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
931 int startColumn, int endLine, int endColumn)
933 if (currentSequence == null || currentSequence.Document != document) {
934 if (sequencePointLists == null)
935 sequencePointLists = new ArrayList ();
936 currentSequence = new SequencePointList (document);
937 sequencePointLists.Add (currentSequence);
940 currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
943 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
945 if (sequencePointLists != null) {
946 SequencePointList first = (SequencePointList) sequencePointLists [0];
947 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
948 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
950 foreach (SequencePointList list in sequencePointLists)
951 symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
953 if (locals != null) {
954 foreach (LocalBuilder local in locals) {
955 if (local.Name != null && local.Name.Length > 0) {
956 SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module as ModuleBuilder);
957 sighelper.AddArgument (local.LocalType);
958 byte[] signature = sighelper.GetSignature ();
959 symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
963 sequencePointLists = null;
967 internal bool HasDebugInfo
969 get { return sequencePointLists != null; }
972 public virtual void ThrowException (Type excType)
975 throw new ArgumentNullException ("excType");
976 if (! ((excType == typeof (Exception)) ||
977 excType.IsSubclassOf (typeof (Exception))))
978 throw new ArgumentException ("Type should be an exception type", "excType");
979 ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
981 throw new ArgumentException ("Type should have a default constructor", "excType");
982 Emit (OpCodes.Newobj, ctor);
983 Emit (OpCodes.Throw);
986 [MonoTODO("Not implemented")]
987 public virtual void UsingNamespace (String usingNamespace)
989 throw new NotImplementedException ();
992 internal void label_fixup (MethodBase mb)
994 for (int i = 0; i < num_fixups; ++i) {
995 if (labels [fixups [i].label_idx].addr < 0)
996 throw new ArgumentException (string.Format ("Label #{0} is not marked in method `{1}'", fixups [i].label_idx + 1, mb.Name));
997 // Diff is the offset from the end of the jump instruction to the address of the label
998 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
999 if (fixups [i].offset == 1) {
1000 code [fixups [i].pos] = (byte)((sbyte) diff);
1002 int old_cl = code_len;
1003 code_len = fixups [i].pos;
1010 // Used by MethodBuilder.SetMethodBody
1011 internal void SetExceptionHandlers (ILExceptionInfo[] exHandlers) {
1012 this.ex_handlers = exHandlers;
1015 // Used by MethodBuilder.SetMethodBody
1016 internal void SetTokenFixups (ILTokenInfo[] tokenFixups) {
1017 this.token_fixups = tokenFixups;
1020 // Used by DynamicILGenerator and MethodBuilder.SetMethodBody
1021 internal void SetCode (byte[] code, int max_stack) {
1022 // Make a copy to avoid possible security problems
1023 this.code = (byte[])code.Clone ();
1024 this.code_len = code.Length;
1025 this.max_stack = max_stack;
1029 internal unsafe void SetCode (byte *code, int code_size, int max_stack) {
1030 // Make a copy to avoid possible security problems
1031 this.code = new byte [code_size];
1032 for (int i = 0; i < code_size; ++i)
1033 this.code [i] = code [i];
1034 this.code_len = code_size;
1035 this.max_stack = max_stack;
1039 internal void Init (byte[] il, int maxStack, byte[] localSignature,
1040 IEnumerable<ExceptionHandler> exceptionHandlers, IEnumerable<int> tokenFixups)
1042 SetCode (il, maxStack);
1044 // FIXME: Process local signature
1046 // Process exception handlers
1047 if (exceptionHandlers != null) {
1048 // Group exception handlers by try blocks
1049 var tryBlocks = new Dictionary <Tuple<int, int>, List<ExceptionHandler>> ();
1050 foreach (var h in exceptionHandlers) {
1051 List<ExceptionHandler> list;
1052 var key = new Tuple <int, int> (h.TryOffset, h.TryLength);
1053 if (!tryBlocks.TryGetValue (key, out list)) {
1054 list = new List<ExceptionHandler> ();
1055 tryBlocks.Add (key, list);
1060 // Generate ILExceptionInfo from tryBlocks
1061 var infos = new List<ILExceptionInfo> ();
1062 foreach (var kv in tryBlocks) {
1063 var info = new ILExceptionInfo () {
1064 start = kv.Key.Item1,
1066 handlers = new ILExceptionBlock [kv.Value.Count],
1070 foreach (var b in kv.Value) {
1071 info.handlers [i++] = new ILExceptionBlock () {
1072 start = b.HandlerOffset,
1073 len = b.HandlerLength,
1074 filter_offset = b.FilterOffset,
1075 type = (int) b.Kind,
1076 extype = module.ResolveType (b.ExceptionTypeToken),
1081 SetExceptionHandlers (infos.ToArray ());
1084 // Process token fixups
1085 if (tokenFixups != null) {
1086 var tokenInfos = new List<ILTokenInfo> ();
1087 foreach (var pos in tokenFixups) {
1088 var token = (int) BitConverter.ToUInt32 (il, pos);
1089 var tokenInfo = new ILTokenInfo () {
1091 member = ((ModuleBuilder) module).ResolveOrGetRegisteredToken (token, null, null)
1093 tokenInfos.Add (tokenInfo);
1096 SetTokenFixups (tokenInfos.ToArray ());
1101 internal TokenGenerator TokenGenerator {
1107 // Still used by symbolwriter
1108 [Obsolete ("Use ILOffset", true)]
1109 internal static int Mono_GetCurrentOffset (ILGenerator ig)
1115 virtual int ILOffset {
1116 get { return code_len; }
1119 void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1121 throw new NotImplementedException ();
1124 void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1126 throw new NotImplementedException ();
1129 void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
1131 throw new NotImplementedException ();
1134 void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1136 throw new NotImplementedException ();
1140 internal class SequencePointList
1142 ISymbolDocumentWriter doc;
1143 SequencePoint[] points;
1145 const int arrayGrow = 10;
1147 public SequencePointList (ISymbolDocumentWriter doc)
1152 public ISymbolDocumentWriter Document {
1156 public int[] GetOffsets()
1158 int[] data = new int [count];
1159 for (int n=0; n<count; n++) data [n] = points[n].Offset;
1162 public int[] GetLines()
1164 int[] data = new int [count];
1165 for (int n=0; n<count; n++) data [n] = points[n].Line;
1168 public int[] GetColumns()
1170 int[] data = new int [count];
1171 for (int n=0; n<count; n++) data [n] = points[n].Col;
1174 public int[] GetEndLines()
1176 int[] data = new int [count];
1177 for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1180 public int[] GetEndColumns()
1182 int[] data = new int [count];
1183 for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1186 public int StartLine {
1187 get { return points[0].Line; }
1189 public int EndLine {
1190 get { return points[count - 1].Line; }
1192 public int StartColumn {
1193 get { return points[0].Col; }
1195 public int EndColumn {
1196 get { return points[count - 1].Col; }
1199 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1201 SequencePoint s = new SequencePoint ();
1205 s.EndLine = endLine;
1208 if (points == null) {
1209 points = new SequencePoint [arrayGrow];
1210 } else if (count >= points.Length) {
1211 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1212 Array.Copy (points, temp, points.Length);
1221 struct SequencePoint {