2009-12-02 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Reflection.Emit / ILGenerator.cs
blob8e180b3c25ed63cf95078a5a81a14f3ea37adafb
2 //
3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
4 //
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:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
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
28 // Author:
29 // Paolo Molaro (lupus@ximian.com)
31 // (C) 2001 Ximian, Inc. http://www.ximian.com
34 using System;
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;
48 internal Type extype;
49 internal int type;
50 internal int start;
51 internal int len;
52 internal int filter_offset;
54 internal void Debug () {
55 #if NO
56 System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
57 if (extype != null)
58 System.Console.WriteLine (" extype="+extype.ToString());
59 else
60 System.Console.WriteLine (String.Empty);
61 #endif
64 internal struct ILExceptionInfo {
65 #pragma warning disable 169
66 #pragma warning disable 414
67 ILExceptionBlock[] handlers;
68 internal int start;
69 int len;
70 internal Label end;
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)
81 int i;
82 End (offset);
83 add_block (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)
92 int i;
93 End (offset);
94 add_block (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)
103 int i;
104 End (offset);
105 add_block (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)
114 int i;
115 End (offset);
116 add_block (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)
126 return;
127 int i = handlers.Length - 1;
128 if (i >= 0)
129 handlers [i].len = offset - handlers [i].start;
132 internal int LastClauseType ()
134 if (handlers != null)
135 return handlers [handlers.Length-1].type;
136 else
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)
150 #if NO
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 ();
154 #endif
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);
163 handlers = new_b;
164 handlers [i].len = offset - handlers [i].start;
165 } else {
166 handlers = new ILExceptionBlock [1];
167 len = offset - start;
172 internal struct ILTokenInfo {
173 public MemberInfo member;
174 public int code_pos;
177 internal interface TokenGenerator {
178 int GetToken (string str);
180 int GetToken (MemberInfo member);
182 int GetToken (MethodInfo method, Type[] opt_param_types);
184 int GetToken (SignatureHelper helper);
187 [ComVisible (true)]
188 [ComDefaultInterface (typeof (_ILGenerator))]
189 [ClassInterface (ClassInterfaceType.None)]
190 public class ILGenerator: _ILGenerator {
191 private struct LabelFixup {
192 public int offset; // The number of bytes between pos and the
193 // offset of the jump
194 public int pos; // Where offset of the label is placed
195 public int label_idx; // The label to jump to
198 struct LabelData {
199 public LabelData (int addr, int maxStack)
201 this.addr = addr;
202 this.maxStack = maxStack;
205 public int addr;
206 public int maxStack;
209 static readonly Type void_type = typeof (void);
210 #region Sync with reflection.h
211 private byte[] code;
212 private int code_len;
213 private int max_stack;
214 private int cur_stack;
215 private LocalBuilder[] locals;
216 private ILExceptionInfo[] ex_handlers;
217 private int num_token_fixups;
218 private ILTokenInfo[] token_fixups;
219 #endregion
221 private LabelData [] labels;
222 private int num_labels;
223 private LabelFixup[] fixups;
224 private int num_fixups;
225 internal Module module;
226 private int cur_block;
227 private Stack open_blocks;
228 private TokenGenerator token_gen;
230 const int defaultFixupSize = 4;
231 const int defaultLabelsSize = 4;
232 const int defaultExceptionStackSize = 2;
234 ArrayList sequencePointLists;
235 SequencePointList currentSequence;
237 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
239 if (size < 0)
240 size = 128;
241 code = new byte [size];
242 token_fixups = new ILTokenInfo [8];
243 module = m;
244 this.token_gen = token_gen;
247 private void add_token_fixup (MemberInfo mi)
249 if (num_token_fixups == token_fixups.Length) {
250 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
251 token_fixups.CopyTo (ntf, 0);
252 token_fixups = ntf;
254 token_fixups [num_token_fixups].member = mi;
255 token_fixups [num_token_fixups++].code_pos = code_len;
258 private void make_room (int nbytes)
260 if (code_len + nbytes < code.Length)
261 return;
262 byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
263 System.Array.Copy (code, 0, new_code, 0, code.Length);
264 code = new_code;
267 private void emit_int (int val)
269 code [code_len++] = (byte) (val & 0xFF);
270 code [code_len++] = (byte) ((val >> 8) & 0xFF);
271 code [code_len++] = (byte) ((val >> 16) & 0xFF);
272 code [code_len++] = (byte) ((val >> 24) & 0xFF);
275 /* change to pass by ref to avoid copy */
276 private void ll_emit (OpCode opcode)
279 * there is already enough room allocated in code.
281 // access op1 and op2 directly since the Value property is useless
282 if (opcode.Size == 2)
283 code [code_len++] = opcode.op1;
284 code [code_len++] = opcode.op2;
286 * We should probably keep track of stack needs here.
287 * Or we may want to run the verifier on the code before saving it
288 * (this may be needed anyway when the ILGenerator is not used...).
290 switch (opcode.StackBehaviourPush) {
291 case StackBehaviour.Push1:
292 case StackBehaviour.Pushi:
293 case StackBehaviour.Pushi8:
294 case StackBehaviour.Pushr4:
295 case StackBehaviour.Pushr8:
296 case StackBehaviour.Pushref:
297 case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
298 cur_stack ++;
299 break;
300 case StackBehaviour.Push1_push1:
301 cur_stack += 2;
302 break;
304 if (max_stack < cur_stack)
305 max_stack = cur_stack;
308 * Note that we adjust for the pop behaviour _after_ setting max_stack.
310 switch (opcode.StackBehaviourPop) {
311 case StackBehaviour.Varpop:
312 break; /* we are conservative and assume it doesn't decrease the stack needs */
313 case StackBehaviour.Pop1:
314 case StackBehaviour.Popi:
315 case StackBehaviour.Popref:
316 cur_stack --;
317 break;
318 case StackBehaviour.Pop1_pop1:
319 case StackBehaviour.Popi_pop1:
320 case StackBehaviour.Popi_popi:
321 case StackBehaviour.Popi_popi8:
322 case StackBehaviour.Popi_popr4:
323 case StackBehaviour.Popi_popr8:
324 case StackBehaviour.Popref_pop1:
325 case StackBehaviour.Popref_popi:
326 cur_stack -= 2;
327 break;
328 case StackBehaviour.Popi_popi_popi:
329 case StackBehaviour.Popref_popi_popi:
330 case StackBehaviour.Popref_popi_popi8:
331 case StackBehaviour.Popref_popi_popr4:
332 case StackBehaviour.Popref_popi_popr8:
333 case StackBehaviour.Popref_popi_popref:
334 cur_stack -= 3;
335 break;
339 private static int target_len (OpCode opcode)
341 if (opcode.OperandType == OperandType.InlineBrTarget)
342 return 4;
343 return 1;
346 private void InternalEndClause ()
348 switch (ex_handlers [cur_block].LastClauseType ()) {
349 case ILExceptionBlock.CATCH:
350 case ILExceptionBlock.FILTER:
351 case ILExceptionBlock.FILTER_START:
352 // how could we optimize code size here?
353 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
354 break;
355 case ILExceptionBlock.FAULT:
356 case ILExceptionBlock.FINALLY:
357 Emit (OpCodes.Endfinally);
358 break;
362 public virtual void BeginCatchBlock (Type exceptionType)
364 if (open_blocks == null)
365 open_blocks = new Stack (defaultExceptionStackSize);
367 if (open_blocks.Count <= 0)
368 throw new NotSupportedException ("Not in an exception block");
369 if (exceptionType != null && exceptionType.IsUserType)
370 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
371 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
372 if (exceptionType != null)
373 throw new ArgumentException ("Do not supply an exception type for filter clause");
374 Emit (OpCodes.Endfilter);
375 ex_handlers [cur_block].PatchFilterClause (code_len);
376 } else {
377 InternalEndClause ();
378 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
381 cur_stack = 1; // the exception object is on the stack by default
382 if (max_stack < cur_stack)
383 max_stack = cur_stack;
385 //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
388 public virtual void BeginExceptFilterBlock ()
390 if (open_blocks == null)
391 open_blocks = new Stack (defaultExceptionStackSize);
393 if (open_blocks.Count <= 0)
394 throw new NotSupportedException ("Not in an exception block");
395 InternalEndClause ();
397 ex_handlers [cur_block].AddFilter (code_len);
400 public virtual Label BeginExceptionBlock ()
402 //System.Console.WriteLine ("Begin Block");
403 if (open_blocks == null)
404 open_blocks = new Stack (defaultExceptionStackSize);
406 if (ex_handlers != null) {
407 cur_block = ex_handlers.Length;
408 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
409 System.Array.Copy (ex_handlers, new_ex, cur_block);
410 ex_handlers = new_ex;
411 } else {
412 ex_handlers = new ILExceptionInfo [1];
413 cur_block = 0;
415 open_blocks.Push (cur_block);
416 ex_handlers [cur_block].start = code_len;
417 return ex_handlers [cur_block].end = DefineLabel ();
420 public virtual void BeginFaultBlock()
422 if (open_blocks == null)
423 open_blocks = new Stack (defaultExceptionStackSize);
425 if (open_blocks.Count <= 0)
426 throw new NotSupportedException ("Not in an exception block");
428 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
429 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
430 ex_handlers [cur_block].PatchFilterClause (code_len);
433 InternalEndClause ();
434 //System.Console.WriteLine ("Begin fault Block");
435 ex_handlers [cur_block].AddFault (code_len);
438 public virtual void BeginFinallyBlock()
440 if (open_blocks == null)
441 open_blocks = new Stack (defaultExceptionStackSize);
443 if (open_blocks.Count <= 0)
444 throw new NotSupportedException ("Not in an exception block");
446 InternalEndClause ();
448 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START) {
449 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
450 ex_handlers [cur_block].PatchFilterClause (code_len);
453 //System.Console.WriteLine ("Begin finally Block");
454 ex_handlers [cur_block].AddFinally (code_len);
457 public virtual void BeginScope ()
460 public virtual LocalBuilder DeclareLocal (Type localType)
462 return DeclareLocal (localType, false);
466 public virtual LocalBuilder DeclareLocal (Type localType, bool pinned)
468 if (localType == null)
469 throw new ArgumentNullException ("localType");
470 if (localType.IsUserType)
471 throw new NotSupportedException ("User defined subclasses of System.Type are not yet supported.");
472 LocalBuilder res = new LocalBuilder (localType, this);
473 res.is_pinned = pinned;
475 if (locals != null) {
476 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
477 System.Array.Copy (locals, new_l, locals.Length);
478 new_l [locals.Length] = res;
479 locals = new_l;
480 } else {
481 locals = new LocalBuilder [1];
482 locals [0] = res;
484 res.position = (ushort)(locals.Length - 1);
485 return res;
488 public virtual Label DefineLabel ()
490 if (labels == null)
491 labels = new LabelData [defaultLabelsSize];
492 else if (num_labels >= labels.Length) {
493 LabelData [] t = new LabelData [labels.Length * 2];
494 Array.Copy (labels, t, labels.Length);
495 labels = t;
498 labels [num_labels] = new LabelData (-1, 0);
500 return new Label (num_labels++);
503 public virtual void Emit (OpCode opcode)
505 make_room (2);
506 ll_emit (opcode);
509 public virtual void Emit (OpCode opcode, Byte arg)
511 make_room (3);
512 ll_emit (opcode);
513 code [code_len++] = arg;
516 [ComVisible (true)]
517 public virtual void Emit (OpCode opcode, ConstructorInfo con)
519 int token = token_gen.GetToken (con);
520 make_room (6);
521 ll_emit (opcode);
522 if (con.DeclaringType.Module == module)
523 add_token_fixup (con);
524 emit_int (token);
526 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
527 cur_stack -= con.GetParameterCount ();
530 public virtual void Emit (OpCode opcode, double arg)
532 byte[] s = System.BitConverter.GetBytes (arg);
533 make_room (10);
534 ll_emit (opcode);
535 if (BitConverter.IsLittleEndian){
536 System.Array.Copy (s, 0, code, code_len, 8);
537 code_len += 8;
538 } else {
539 code [code_len++] = s [7];
540 code [code_len++] = s [6];
541 code [code_len++] = s [5];
542 code [code_len++] = s [4];
543 code [code_len++] = s [3];
544 code [code_len++] = s [2];
545 code [code_len++] = s [1];
546 code [code_len++] = s [0];
550 public virtual void Emit (OpCode opcode, FieldInfo field)
552 int token = token_gen.GetToken (field);
553 make_room (6);
554 ll_emit (opcode);
555 if (field.DeclaringType.Module == module)
556 add_token_fixup (field);
557 emit_int (token);
560 public virtual void Emit (OpCode opcode, Int16 arg)
562 make_room (4);
563 ll_emit (opcode);
564 code [code_len++] = (byte) (arg & 0xFF);
565 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
568 public virtual void Emit (OpCode opcode, int arg)
570 make_room (6);
571 ll_emit (opcode);
572 emit_int (arg);
575 public virtual void Emit (OpCode opcode, long arg)
577 make_room (10);
578 ll_emit (opcode);
579 code [code_len++] = (byte) (arg & 0xFF);
580 code [code_len++] = (byte) ((arg >> 8) & 0xFF);
581 code [code_len++] = (byte) ((arg >> 16) & 0xFF);
582 code [code_len++] = (byte) ((arg >> 24) & 0xFF);
583 code [code_len++] = (byte) ((arg >> 32) & 0xFF);
584 code [code_len++] = (byte) ((arg >> 40) & 0xFF);
585 code [code_len++] = (byte) ((arg >> 48) & 0xFF);
586 code [code_len++] = (byte) ((arg >> 56) & 0xFF);
589 public virtual void Emit (OpCode opcode, Label label)
591 int tlen = target_len (opcode);
592 make_room (6);
593 ll_emit (opcode);
594 if (cur_stack > labels [label.label].maxStack)
595 labels [label.label].maxStack = cur_stack;
597 if (fixups == null)
598 fixups = new LabelFixup [defaultFixupSize];
599 else if (num_fixups >= fixups.Length) {
600 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
601 System.Array.Copy (fixups, newf, fixups.Length);
602 fixups = newf;
604 fixups [num_fixups].offset = tlen;
605 fixups [num_fixups].pos = code_len;
606 fixups [num_fixups].label_idx = label.label;
607 num_fixups++;
608 code_len += tlen;
612 public virtual void Emit (OpCode opcode, Label[] labels)
614 if (labels == null)
615 throw new ArgumentNullException ("labels");
617 /* opcode needs to be switch. */
618 int count = labels.Length;
619 make_room (6 + count * 4);
620 ll_emit (opcode);
622 for (int i = 0; i < count; ++i)
623 if (cur_stack > this.labels [labels [i].label].maxStack)
624 this.labels [labels [i].label].maxStack = cur_stack;
626 emit_int (count);
627 if (fixups == null)
628 fixups = new LabelFixup [defaultFixupSize + count];
629 else if (num_fixups + count >= fixups.Length) {
630 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
631 System.Array.Copy (fixups, newf, fixups.Length);
632 fixups = newf;
635 // ECMA 335, Partition III, p94 (7-10)
637 // The switch instruction implements a jump table. The format of
638 // the instruction is an unsigned int32 representing the number of targets N,
639 // followed by N int32 values specifying jump targets: these targets are
640 // represented as offsets (positive or negative) from the beginning of the
641 // instruction following this switch instruction.
643 // We must make sure it gets an offset from the *end* of the last label
644 // (eg, the beginning of the instruction following this).
646 // remaining is the number of bytes from the current instruction to the
647 // instruction that will be emitted.
649 for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
650 fixups [num_fixups].offset = remaining;
651 fixups [num_fixups].pos = code_len;
652 fixups [num_fixups].label_idx = labels [i].label;
653 num_fixups++;
654 code_len += 4;
658 public virtual void Emit (OpCode opcode, LocalBuilder local)
660 if (local == null)
661 throw new ArgumentNullException ("local");
663 uint pos = local.position;
664 bool load_addr = false;
665 bool is_store = false;
666 make_room (6);
668 if (local.ilgen != this)
669 throw new ArgumentException ("Trying to emit a local from a different ILGenerator.");
671 /* inline the code from ll_emit () to optimize il code size */
672 if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
673 cur_stack --;
674 is_store = true;
675 } else {
676 cur_stack++;
677 if (cur_stack > max_stack)
678 max_stack = cur_stack;
679 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
681 if (load_addr) {
682 if (pos < 256) {
683 code [code_len++] = (byte)0x12;
684 code [code_len++] = (byte)pos;
685 } else {
686 code [code_len++] = (byte)0xfe;
687 code [code_len++] = (byte)0x0d;
688 code [code_len++] = (byte)(pos & 0xff);
689 code [code_len++] = (byte)((pos >> 8) & 0xff);
691 } else {
692 if (is_store) {
693 if (pos < 4) {
694 code [code_len++] = (byte)(0x0a + pos);
695 } else if (pos < 256) {
696 code [code_len++] = (byte)0x13;
697 code [code_len++] = (byte)pos;
698 } else {
699 code [code_len++] = (byte)0xfe;
700 code [code_len++] = (byte)0x0e;
701 code [code_len++] = (byte)(pos & 0xff);
702 code [code_len++] = (byte)((pos >> 8) & 0xff);
704 } else {
705 if (pos < 4) {
706 code [code_len++] = (byte)(0x06 + pos);
707 } else if (pos < 256) {
708 code [code_len++] = (byte)0x11;
709 code [code_len++] = (byte)pos;
710 } else {
711 code [code_len++] = (byte)0xfe;
712 code [code_len++] = (byte)0x0c;
713 code [code_len++] = (byte)(pos & 0xff);
714 code [code_len++] = (byte)((pos >> 8) & 0xff);
720 public virtual void Emit (OpCode opcode, MethodInfo meth)
722 if (meth == null)
723 throw new ArgumentNullException ("meth");
725 // For compatibility with MS
726 if ((meth is DynamicMethod) && ((opcode == OpCodes.Ldftn) || (opcode == OpCodes.Ldvirtftn) || (opcode == OpCodes.Ldtoken)))
727 throw new ArgumentException ("Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods.");
729 int token = token_gen.GetToken (meth);
730 make_room (6);
731 ll_emit (opcode);
732 Type declaringType = meth.DeclaringType;
733 // Might be a DynamicMethod with no declaring type
734 if (declaringType != null) {
735 if (declaringType.Module == module)
736 add_token_fixup (meth);
738 emit_int (token);
739 if (meth.ReturnType != void_type)
740 cur_stack ++;
742 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
743 cur_stack -= meth.GetParameterCount ();
746 private void Emit (OpCode opcode, MethodInfo method, int token)
748 make_room (6);
749 ll_emit (opcode);
750 // Might be a DynamicMethod with no declaring type
751 Type declaringType = method.DeclaringType;
752 if (declaringType != null) {
753 if (declaringType.Module == module)
754 add_token_fixup (method);
756 emit_int (token);
757 if (method.ReturnType != void_type)
758 cur_stack ++;
760 if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
761 cur_stack -= method.GetParameterCount ();
764 [CLSCompliant(false)]
765 public void Emit (OpCode opcode, sbyte arg)
767 make_room (3);
768 ll_emit (opcode);
769 code [code_len++] = (byte)arg;
772 public virtual void Emit (OpCode opcode, SignatureHelper signature)
774 int token = token_gen.GetToken (signature);
775 make_room (6);
776 ll_emit (opcode);
777 emit_int (token);
780 public virtual void Emit (OpCode opcode, float arg)
782 byte[] s = System.BitConverter.GetBytes (arg);
783 make_room (6);
784 ll_emit (opcode);
785 if (BitConverter.IsLittleEndian){
786 System.Array.Copy (s, 0, code, code_len, 4);
787 code_len += 4;
788 } else {
789 code [code_len++] = s [3];
790 code [code_len++] = s [2];
791 code [code_len++] = s [1];
792 code [code_len++] = s [0];
796 public virtual void Emit (OpCode opcode, string str)
798 int token = token_gen.GetToken (str);
799 make_room (6);
800 ll_emit (opcode);
801 emit_int (token);
804 public virtual void Emit (OpCode opcode, Type cls)
806 make_room (6);
807 ll_emit (opcode);
808 emit_int (token_gen.GetToken (cls));
811 [MonoLimitation ("vararg methods are not supported")]
812 public virtual void EmitCall (OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes)
814 if (methodInfo == null)
815 throw new ArgumentNullException ("methodInfo");
816 short value = opcode.Value;
817 if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
818 throw new NotSupportedException ("Only Call and CallVirt are allowed");
819 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0)
820 optionalParameterTypes = null;
821 if (optionalParameterTypes != null){
822 if ((methodInfo.CallingConvention & CallingConventions.VarArgs) == 0){
823 throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
826 int token = token_gen.GetToken (methodInfo, optionalParameterTypes);
827 Emit (opcode, methodInfo, token);
828 return;
830 Emit (opcode, methodInfo);
833 public virtual void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes)
835 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, parameterTypes);
836 Emit (opcode, helper);
839 public virtual void EmitCalli (OpCode opcode, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
841 if (optionalParameterTypes != null)
842 throw new NotImplementedException ();
844 SignatureHelper helper = SignatureHelper.GetMethodSigHelper (module, callingConvention, 0, returnType, parameterTypes);
845 Emit (opcode, helper);
848 public virtual void EmitWriteLine (FieldInfo fld)
850 if (fld == null)
851 throw new ArgumentNullException ("fld");
853 // The MS implementation does not check for valuetypes here but it
854 // should. Also, it should check that if the field is not static,
855 // then it is a member of this type.
856 if (fld.IsStatic)
857 Emit (OpCodes.Ldsfld, fld);
858 else {
859 Emit (OpCodes.Ldarg_0);
860 Emit (OpCodes.Ldfld, fld);
862 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { fld.FieldType }));
865 public virtual void EmitWriteLine (LocalBuilder localBuilder)
867 if (localBuilder == null)
868 throw new ArgumentNullException ("localBuilder");
869 if (localBuilder.LocalType is TypeBuilder)
870 throw new ArgumentException ("Output streams do not support TypeBuilders.");
871 // The MS implementation does not check for valuetypes here but it
872 // should.
873 Emit (OpCodes.Ldloc, localBuilder);
874 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { localBuilder.LocalType }));
877 public virtual void EmitWriteLine (string value)
879 Emit (OpCodes.Ldstr, value);
880 Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type[1] { typeof(string)}));
883 public virtual void EndExceptionBlock ()
885 if (open_blocks == null)
886 open_blocks = new Stack (defaultExceptionStackSize);
888 if (open_blocks.Count <= 0)
889 throw new NotSupportedException ("Not in an exception block");
891 if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER_START)
892 throw new InvalidOperationException ("Incorrect code generation for exception block.");
894 InternalEndClause ();
895 MarkLabel (ex_handlers [cur_block].end);
896 ex_handlers [cur_block].End (code_len);
897 ex_handlers [cur_block].Debug (cur_block);
898 //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
899 open_blocks.Pop ();
900 if (open_blocks.Count > 0)
901 cur_block = (int)open_blocks.Peek ();
902 //Console.WriteLine ("curblock restored to {0}", cur_block);
903 //throw new NotImplementedException ();
906 public virtual void EndScope ()
909 public virtual void MarkLabel (Label loc)
911 if (loc.label < 0 || loc.label >= num_labels)
912 throw new System.ArgumentException ("The label is not valid");
913 if (labels [loc.label].addr >= 0)
914 throw new System.ArgumentException ("The label was already defined");
915 labels [loc.label].addr = code_len;
916 if (labels [loc.label].maxStack > cur_stack)
917 cur_stack = labels [loc.label].maxStack;
920 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
921 int startColumn, int endLine, int endColumn)
923 if (currentSequence == null || currentSequence.Document != document) {
924 if (sequencePointLists == null)
925 sequencePointLists = new ArrayList ();
926 currentSequence = new SequencePointList (document);
927 sequencePointLists.Add (currentSequence);
930 currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
933 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
935 if (sequencePointLists != null) {
936 SequencePointList first = (SequencePointList) sequencePointLists [0];
937 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
938 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
940 foreach (SequencePointList list in sequencePointLists)
941 symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
943 if (locals != null) {
944 foreach (LocalBuilder local in locals) {
945 if (local.Name != null && local.Name.Length > 0) {
946 SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module);
947 sighelper.AddArgument (local.LocalType);
948 byte[] signature = sighelper.GetSignature ();
949 symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
953 sequencePointLists = null;
957 internal bool HasDebugInfo
959 get { return sequencePointLists != null; }
962 public virtual void ThrowException (Type excType)
964 if (excType == null)
965 throw new ArgumentNullException ("excType");
966 if (! ((excType == typeof (Exception)) ||
967 excType.IsSubclassOf (typeof (Exception))))
968 throw new ArgumentException ("Type should be an exception type", "excType");
969 ConstructorInfo ctor = excType.GetConstructor (Type.EmptyTypes);
970 if (ctor == null)
971 throw new ArgumentException ("Type should have a default constructor", "excType");
972 Emit (OpCodes.Newobj, ctor);
973 Emit (OpCodes.Throw);
976 [MonoTODO("Not implemented")]
977 public virtual void UsingNamespace (String usingNamespace)
979 throw new NotImplementedException ();
982 internal void label_fixup ()
984 for (int i = 0; i < num_fixups; ++i) {
985 if (labels [fixups [i].label_idx].addr < 0)
986 throw new ArgumentException ("Label not marked");
987 // Diff is the offset from the end of the jump instruction to the address of the label
988 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
989 if (fixups [i].offset == 1) {
990 code [fixups [i].pos] = (byte)((sbyte) diff);
991 } else {
992 int old_cl = code_len;
993 code_len = fixups [i].pos;
994 emit_int (diff);
995 code_len = old_cl;
1000 // Still used by symbolwriter
1001 [Obsolete ("Use ILOffset", true)]
1002 internal static int Mono_GetCurrentOffset (ILGenerator ig)
1004 return ig.code_len;
1007 #if NET_4_0 || BOOTSTRAP_NET_4_0
1008 public
1009 #else
1010 internal
1011 #endif
1012 virtual int ILOffset {
1013 get { return code_len; }
1016 void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1018 throw new NotImplementedException ();
1021 void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1023 throw new NotImplementedException ();
1026 void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
1028 throw new NotImplementedException ();
1031 void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1033 throw new NotImplementedException ();
1037 internal class SequencePointList
1039 ISymbolDocumentWriter doc;
1040 SequencePoint[] points;
1041 int count;
1042 const int arrayGrow = 10;
1044 public SequencePointList (ISymbolDocumentWriter doc)
1046 this.doc = doc;
1049 public ISymbolDocumentWriter Document {
1050 get { return doc; }
1053 public int[] GetOffsets()
1055 int[] data = new int [count];
1056 for (int n=0; n<count; n++) data [n] = points[n].Offset;
1057 return data;
1059 public int[] GetLines()
1061 int[] data = new int [count];
1062 for (int n=0; n<count; n++) data [n] = points[n].Line;
1063 return data;
1065 public int[] GetColumns()
1067 int[] data = new int [count];
1068 for (int n=0; n<count; n++) data [n] = points[n].Col;
1069 return data;
1071 public int[] GetEndLines()
1073 int[] data = new int [count];
1074 for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1075 return data;
1077 public int[] GetEndColumns()
1079 int[] data = new int [count];
1080 for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1081 return data;
1083 public int StartLine {
1084 get { return points[0].Line; }
1086 public int EndLine {
1087 get { return points[count - 1].Line; }
1089 public int StartColumn {
1090 get { return points[0].Col; }
1092 public int EndColumn {
1093 get { return points[count - 1].Col; }
1096 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1098 SequencePoint s = new SequencePoint ();
1099 s.Offset = offset;
1100 s.Line = line;
1101 s.Col = col;
1102 s.EndLine = endLine;
1103 s.EndCol = endCol;
1105 if (points == null) {
1106 points = new SequencePoint [arrayGrow];
1107 } else if (count >= points.Length) {
1108 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1109 Array.Copy (points, temp, points.Length);
1110 points = temp;
1113 points [count] = s;
1114 count++;
1118 struct SequencePoint {
1119 public int Offset;
1120 public int Line;
1121 public int Col;
1122 public int EndLine;
1123 public int EndCol;