2004-06-08 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ILGenerator.cs
1
2 //
3 // System.Reflection.Emit/ILGenerator.cs
4 //
5 // Author:
6 //   Paolo Molaro (lupus@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc.  http://www.ximian.com
9 //
10
11 using System;
12 using System.Collections;
13 using System.Diagnostics.SymbolStore;
14 using System.Runtime.InteropServices;
15 using Mono.CSharp.Debugger;
16
17 namespace System.Reflection.Emit {
18
19         internal struct ILExceptionBlock {
20                 public const int CATCH = 0;
21                 public const int FILTER = 1;
22                 public const int FINALLY = 2;
23                 public const int FAULT = 4;
24
25                 internal Type extype;
26                 internal int type;
27                 internal int start;
28                 internal int len;
29                 internal int filter_offset;
30                 
31                 internal void Debug () {
32 #if NO
33                         System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
34                         if (extype != null)
35                                 System.Console.WriteLine (" extype="+extype.ToString());
36                         else
37                                 System.Console.WriteLine ("");
38 #endif
39                 }
40         }
41         internal struct ILExceptionInfo {
42                 ILExceptionBlock[] handlers;
43                 internal int start;
44                 int len;
45                 internal Label end;
46
47                 internal int NumHandlers ()
48                 {
49                         return handlers.Length;
50                 }
51                 
52                 internal void AddCatch (Type extype, int offset)
53                 {
54                         int i;
55                         End (offset);
56                         add_block (offset);
57                         i = handlers.Length - 1;
58                         handlers [i].type = ILExceptionBlock.CATCH;
59                         handlers [i].start = offset;
60                         handlers [i].extype = extype;
61                 }
62
63                 internal void AddFinally (int offset)
64                 {
65                         int i;
66                         End (offset);
67                         add_block (offset);
68                         i = handlers.Length - 1;
69                         handlers [i].type = ILExceptionBlock.FINALLY;
70                         handlers [i].start = offset;
71                         handlers [i].extype = null;
72                 }
73
74                 internal void End (int offset)
75                 {
76                         if (handlers == null)
77                                 return;
78                         int i = handlers.Length - 1;
79                         if (i >= 0)
80                                 handlers [i].len = offset - handlers [i].start;
81                 }
82
83                 internal int LastClauseType ()
84                 {
85                         if (handlers != null)
86                                 return handlers [handlers.Length-1].type;
87                         else
88                                 return ILExceptionBlock.CATCH;
89                 }
90
91                 internal void Debug (int b)
92                 {
93 #if NO
94                         System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
95                         for (int i = 0; i < handlers.Length; ++i)
96                                 handlers [i].Debug ();
97 #endif
98                 }
99
100                 void add_block (int offset)
101                 {
102                         if (handlers != null) {
103                                 int i = handlers.Length;
104                                 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
105                                 System.Array.Copy (handlers, new_b, i);
106                                 handlers = new_b;
107                                 handlers [i].len = offset - handlers [i].start;
108                         } else {
109                                 handlers = new ILExceptionBlock [1];
110                                 len = offset - start;
111                         }
112                 }
113         }
114         
115         internal struct ILTokenInfo {
116                 public MemberInfo member;
117                 public int code_pos;
118         }
119
120         internal interface TokenGenerator {
121                 int GetToken (string str);
122
123                 int GetToken (MemberInfo member);
124
125                 int GetToken (MethodInfo method, Type[] opt_param_types);
126
127                 int GetToken (SignatureHelper helper);
128         }               
129
130         public class ILGenerator: Object {
131                 private struct LabelFixup {
132                         public int offset;    // The number of bytes between pos and the
133                                                               // offset of the jump
134                         public int pos;       // Where offset of the label is placed
135                         public int label_idx; // The label to jump to
136                 };
137                 
138                 struct LabelData {
139                         public LabelData (int addr, int maxStack)
140                         {
141                                 this.addr = addr;
142                                 this.maxStack = maxStack;
143                         }
144                         
145                         public int addr;
146                         public int maxStack; 
147                 }
148                 
149                 static readonly Type void_type = typeof (void);
150                 #region Sync with reflection.h
151                 private byte[] code;
152                 private int code_len;
153                 private int max_stack;
154                 private int cur_stack;
155                 private LocalBuilder[] locals;
156                 private ILExceptionInfo[] ex_handlers;
157                 private int num_token_fixups;
158                 private ILTokenInfo[] token_fixups;
159                 #endregion
160                 
161                 private LabelData [] labels;
162                 private int num_labels;
163                 private LabelFixup[] fixups;
164                 private int num_fixups;
165                 internal Module module;
166                 internal IMonoSymbolWriter sym_writer;
167                 private Stack scopes;
168                 private int cur_block;
169                 private Stack open_blocks;
170                 private TokenGenerator token_gen;
171                 
172                 const int defaultFixupSize = 8;
173                 const int defaultLabelsSize = 8;
174
175                 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
176                 {
177                         if (size < 0)
178                                 size = 128;
179                         code_len = 0;
180                         code = new byte [size];
181                         cur_stack = max_stack = 0;
182                         num_fixups = num_labels = 0;
183                         token_fixups = new ILTokenInfo [8];
184                         num_token_fixups = 0;
185                         module = m;
186                         if (module is ModuleBuilder)
187                                 sym_writer = ((ModuleBuilder)module).symbol_writer;
188                         open_blocks = new Stack ();
189                         this.token_gen = token_gen;
190                 }
191
192                 private void add_token_fixup (MemberInfo mi)
193                 {
194                         if (num_token_fixups == token_fixups.Length) {
195                                 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
196                                 token_fixups.CopyTo (ntf, 0);
197                                 token_fixups = ntf;
198                         }
199                         token_fixups [num_token_fixups].member = mi;
200                         token_fixups [num_token_fixups++].code_pos = code_len;
201                 }
202
203                 private void make_room (int nbytes)
204                 {
205                         if (code_len + nbytes < code.Length)
206                                 return;
207                         byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
208                         System.Array.Copy (code, 0, new_code, 0, code.Length);
209                         code = new_code;
210                 }
211
212                 private void emit_int (int val)
213                 {
214                         code [code_len++] = (byte) (val & 0xFF);
215                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
216                         code [code_len++] = (byte) ((val >> 16) & 0xFF);
217                         code [code_len++] = (byte) ((val >> 24) & 0xFF);
218                 }
219
220                 /* change to pass by ref to avoid copy */
221                 private void ll_emit (OpCode opcode)
222                 {
223                         /* 
224                          * there is already enough room allocated in code.
225                          */
226                         // access op1 and op2 directly since the Value property is useless
227                         if (opcode.Size == 2)
228                                 code [code_len++] = opcode.op1;
229                         code [code_len++] = opcode.op2;
230                         /*
231                          * We should probably keep track of stack needs here.
232                          * Or we may want to run the verifier on the code before saving it
233                          * (this may be needed anyway when the ILGenerator is not used...).
234                          */
235                         switch (opcode.StackBehaviourPush) {
236                         case StackBehaviour.Push1:
237                         case StackBehaviour.Pushi:
238                         case StackBehaviour.Pushi8:
239                         case StackBehaviour.Pushr4:
240                         case StackBehaviour.Pushr8:
241                         case StackBehaviour.Pushref:
242                         case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
243                                 cur_stack ++;
244                                 break;
245                         case StackBehaviour.Push1_push1:
246                                 cur_stack += 2;
247                                 break;
248                         }
249                         if (max_stack < cur_stack)
250                                 max_stack = cur_stack;
251
252                         /* 
253                          * Note that we adjust for the pop behaviour _after_ setting max_stack.
254                          */
255                         switch (opcode.StackBehaviourPop) {
256                         case StackBehaviour.Varpop:
257                                 break; /* we are conservative and assume it doesn't decrease the stack needs */
258                         case StackBehaviour.Pop1:
259                         case StackBehaviour.Popi:
260                         case StackBehaviour.Popref:
261                                 cur_stack --;
262                                 break;
263                         case StackBehaviour.Pop1_pop1:
264                         case StackBehaviour.Popi_pop1:
265                         case StackBehaviour.Popi_popi:
266                         case StackBehaviour.Popi_popi8:
267                         case StackBehaviour.Popi_popr4:
268                         case StackBehaviour.Popi_popr8:
269                         case StackBehaviour.Popref_pop1:
270                         case StackBehaviour.Popref_popi:
271                                 cur_stack -= 2;
272                                 break;
273                         case StackBehaviour.Popi_popi_popi:
274                         case StackBehaviour.Popref_popi_popi:
275                         case StackBehaviour.Popref_popi_popi8:
276                         case StackBehaviour.Popref_popi_popr4:
277                         case StackBehaviour.Popref_popi_popr8:
278                         case StackBehaviour.Popref_popi_popref:
279                                 cur_stack -= 3;
280                                 break;
281                         }
282                 }
283
284                 private static int target_len (OpCode opcode)
285                 {
286                         if (opcode.OperandType == OperandType.InlineBrTarget)
287                                 return 4;
288                         return 1;
289                 }
290
291                 private void InternalEndClause ()
292                 {
293                         switch (ex_handlers [cur_block].LastClauseType ()) {
294                         case ILExceptionBlock.CATCH:
295                                 // how could we optimize code size here?
296                                 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
297                                 break;
298                         case ILExceptionBlock.FAULT:
299                         case ILExceptionBlock.FINALLY:
300                                 Emit (OpCodes.Endfinally);
301                                 break;
302                         case ILExceptionBlock.FILTER:
303                                 Emit (OpCodes.Endfilter);
304                                 break;
305                         }
306                 }
307
308                 public virtual void BeginCatchBlock (Type exceptionType)
309                 {
310                         if (open_blocks.Count <= 0)
311                                 throw new NotSupportedException ("Not in an exception block");
312                         InternalEndClause ();
313                         ex_handlers [cur_block].AddCatch (exceptionType, code_len);
314                         cur_stack = 1; // the exception object is on the stack by default
315                         if (max_stack < cur_stack)
316                                 max_stack = cur_stack;
317                         //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
318                         //throw new NotImplementedException ();
319                 }
320
321                 [MonoTODO]
322                 public virtual void BeginExceptFilterBlock ()
323                 {
324                         throw new NotImplementedException ();
325                 }
326
327                 public virtual Label BeginExceptionBlock ()
328                 {
329                         //System.Console.WriteLine ("Begin Block");
330                         
331                         if (ex_handlers != null) {
332                                 cur_block = ex_handlers.Length;
333                                 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
334                                 System.Array.Copy (ex_handlers, new_ex, cur_block);
335                                 ex_handlers = new_ex;
336                         } else {
337                                 ex_handlers = new ILExceptionInfo [1];
338                                 cur_block = 0;
339                         }
340                         open_blocks.Push (cur_block);
341                         ex_handlers [cur_block].start = code_len;
342                         return ex_handlers [cur_block].end = DefineLabel ();
343                 }
344
345                 public virtual void BeginFaultBlock()
346                 {
347                         if (open_blocks.Count <= 0)
348                                 throw new NotSupportedException ("Not in an exception block");
349                         //System.Console.WriteLine ("Begin fault Block");
350                         //throw new NotImplementedException ();
351                 }
352                 
353                 public virtual void BeginFinallyBlock()
354                 {
355                         if (open_blocks.Count <= 0)
356                                 throw new NotSupportedException ("Not in an exception block");
357                         InternalEndClause ();
358                         //System.Console.WriteLine ("Begin finally Block");
359                         ex_handlers [cur_block].AddFinally (code_len);
360                 }
361                 
362                 public virtual void BeginScope ()
363                 {
364                         if (sym_writer != null) {
365                                 if (scopes == null)
366                                         scopes = new Stack ();
367                                 scopes.Push (sym_writer.OpenScope (code_len));
368                         }
369                 }
370                 
371                 public LocalBuilder DeclareLocal (Type localType)
372                 {
373                         LocalBuilder res = new LocalBuilder (localType, this);
374                         if (locals != null) {
375                                 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
376                                 System.Array.Copy (locals, new_l, locals.Length);
377                                 new_l [locals.Length] = res;
378                                 locals = new_l;
379                         } else {
380                                 locals = new LocalBuilder [1];
381                                 locals [0] = res;
382                         }
383                         res.position = (ushort)(locals.Length - 1);
384                         return res;
385                 }
386                 
387                 public virtual Label DefineLabel ()
388                 {
389                         if (labels == null)
390                                 labels = new LabelData [defaultLabelsSize];
391                         else if (num_labels >= labels.Length) {
392                                 LabelData [] t = new LabelData [labels.Length * 2];
393                                 Array.Copy (labels, t, labels.Length);
394                                 labels = t;
395                         }
396                         
397                         labels [num_labels] = new LabelData (-1, 0);
398                         
399                         return new Label (num_labels++);
400                 }
401                 
402                 public virtual void Emit (OpCode opcode)
403                 {
404                         make_room (2);
405                         ll_emit (opcode);
406                 }
407                 
408                 public virtual void Emit (OpCode opcode, Byte val)
409                 {
410                         make_room (3);
411                         ll_emit (opcode);
412                         code [code_len++] = val;
413                 }
414                 
415                 public virtual void Emit (OpCode opcode, ConstructorInfo constructor)
416                 {
417                         int token = token_gen.GetToken (constructor);
418                         make_room (6);
419                         ll_emit (opcode);
420                         if (constructor.DeclaringType.Module == module)
421                                 add_token_fixup (constructor);
422                         emit_int (token);
423                         
424                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
425                                 cur_stack -= constructor.GetParameterCount ();
426                 }
427                 
428                 public virtual void Emit (OpCode opcode, double val)
429                 {
430                         Double.AssertEndianity (out val);
431
432                         byte[] s = System.BitConverter.GetBytes (val);
433                         make_room (10);
434                         ll_emit (opcode);
435                         if (BitConverter.IsLittleEndian){
436                                 System.Array.Copy (s, 0, code, code_len, 8);
437                                 code_len += 8;
438                         } else {
439                                 code [code_len++] = s [7];
440                                 code [code_len++] = s [6];
441                                 code [code_len++] = s [5];
442                                 code [code_len++] = s [4];
443                                 code [code_len++] = s [3];
444                                 code [code_len++] = s [2];
445                                 code [code_len++] = s [1];
446                                 code [code_len++] = s [0];                              
447                         }
448                 }
449                 
450                 public virtual void Emit (OpCode opcode, FieldInfo field)
451                 {
452                         int token = token_gen.GetToken (field);
453                         make_room (6);
454                         ll_emit (opcode);
455                         if (field.DeclaringType.Module == module)
456                                 add_token_fixup (field);
457                         emit_int (token);
458                 }
459                 
460                 public virtual void Emit (OpCode opcode, Int16 val)
461                 {
462                         make_room (4);
463                         ll_emit (opcode);
464                         code [code_len++] = (byte) (val & 0xFF);
465                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
466                 }
467                 
468                 public virtual void Emit (OpCode opcode, int val)
469                 {
470                         make_room (6);
471                         ll_emit (opcode);
472                         emit_int (val);
473                 }
474                 
475                 public virtual void Emit (OpCode opcode, long val)
476                 {
477                         make_room (10);
478                         ll_emit (opcode);
479                         code [code_len++] = (byte) (val & 0xFF);
480                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
481                         code [code_len++] = (byte) ((val >> 16) & 0xFF);
482                         code [code_len++] = (byte) ((val >> 24) & 0xFF);
483                         code [code_len++] = (byte) ((val >> 32) & 0xFF);
484                         code [code_len++] = (byte) ((val >> 40) & 0xFF);
485                         code [code_len++] = (byte) ((val >> 48) & 0xFF);
486                         code [code_len++] = (byte) ((val >> 56) & 0xFF);
487                 }
488                 
489                 public virtual void Emit (OpCode opcode, Label label)
490                 {
491                         int tlen = target_len (opcode);
492                         make_room (6);
493                         ll_emit (opcode);
494                         if (cur_stack > labels [label.label].maxStack)
495                                 labels [label.label].maxStack = cur_stack;
496                         
497                         if (fixups == null)
498                                 fixups = new LabelFixup [defaultFixupSize]; 
499                         else if (num_fixups >= fixups.Length) {
500                                 LabelFixup[] newf = new LabelFixup [fixups.Length + 16];
501                                 System.Array.Copy (fixups, newf, fixups.Length);
502                                 fixups = newf;
503                         }
504                         fixups [num_fixups].offset = tlen;
505                         fixups [num_fixups].pos = code_len;
506                         fixups [num_fixups].label_idx = label.label;
507                         num_fixups++;
508                         code_len += tlen;
509
510                 }
511                 
512                 public virtual void Emit (OpCode opcode, Label[] labels)
513                 {
514                         /* opcode needs to be switch. */
515                         int count = labels.Length;
516                         make_room (6 + count * 4);
517                         ll_emit (opcode);
518
519                         for (int i = 0; i < count; ++i)
520                                 if (cur_stack > this.labels [labels [i].label].maxStack)
521                                         this.labels [labels [i].label].maxStack = cur_stack;
522
523                         emit_int (count);
524                         if (fixups == null)
525                                 fixups = new LabelFixup [defaultFixupSize + count]; 
526                         else if (num_fixups + count >= fixups.Length) {
527                                 LabelFixup[] newf = new LabelFixup [fixups.Length + count + 16];
528                                 System.Array.Copy (fixups, newf, fixups.Length);
529                                 fixups = newf;
530                         }
531                         
532                         // ECMA 335, Partition III, p94 (7-10)
533                         //
534                         // The switch instruction implements a jump table. The format of 
535                         // the instruction is an unsigned int32 representing the number of targets N,
536                         // followed by N int32 values specifying jump targets: these targets are
537                         // represented as offsets (positive or negative) from the beginning of the 
538                         // instruction following this switch instruction.
539                         //
540                         // We must make sure it gets an offset from the *end* of the last label
541                         // (eg, the beginning of the instruction following this).
542                         //
543                         // remaining is the number of bytes from the current instruction to the
544                         // instruction that will be emitted.
545                         
546                         for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
547                                 fixups [num_fixups].offset = remaining;
548                                 fixups [num_fixups].pos = code_len;
549                                 fixups [num_fixups].label_idx = labels [i].label;
550                                 num_fixups++;
551                                 code_len += 4;
552                         }
553                 }
554
555                 public virtual void Emit (OpCode opcode, LocalBuilder lbuilder)
556                 {
557                         uint pos = lbuilder.position;
558                         bool load_addr = false;
559                         bool is_store = false;
560                         make_room (6);
561
562                         if (lbuilder.ilgen != this)
563                                 throw new Exception ("Trying to emit a local from a different ILGenerator.");
564
565                         /* inline the code from ll_emit () to optimize il code size */
566                         if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
567                                 cur_stack --;
568                                 is_store = true;
569                         } else {
570                                 cur_stack++;
571                                 if (cur_stack > max_stack)
572                                         max_stack = cur_stack;
573                                 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
574                         }
575                         if (load_addr) {
576                                 if (pos < 256) {
577                                         code [code_len++] = (byte)0x12;
578                                         code [code_len++] = (byte)pos;
579                                 } else {
580                                         code [code_len++] = (byte)0xfe;
581                                         code [code_len++] = (byte)0x0d;
582                                         code [code_len++] = (byte)(pos & 0xff);
583                                         code [code_len++] = (byte)((pos >> 8) & 0xff);
584                                 }
585                         } else {
586                                 if (is_store) {
587                                         if (pos < 4) {
588                                                 code [code_len++] = (byte)(0x0a + pos);
589                                         } else if (pos < 256) {
590                                                 code [code_len++] = (byte)0x13;
591                                                 code [code_len++] = (byte)pos;
592                                         } else {
593                                                 code [code_len++] = (byte)0xfe;
594                                                 code [code_len++] = (byte)0x0e;
595                                                 code [code_len++] = (byte)(pos & 0xff);
596                                                 code [code_len++] = (byte)((pos >> 8) & 0xff);
597                                         }
598                                 } else {
599                                         if (pos < 4) {
600                                                 code [code_len++] = (byte)(0x06 + pos);
601                                         } else if (pos < 256) {
602                                                 code [code_len++] = (byte)0x11;
603                                                 code [code_len++] = (byte)pos;
604                                         } else {
605                                                 code [code_len++] = (byte)0xfe;
606                                                 code [code_len++] = (byte)0x0c;
607                                                 code [code_len++] = (byte)(pos & 0xff);
608                                                 code [code_len++] = (byte)((pos >> 8) & 0xff);
609                                         }
610                                 }
611                         }
612                 }
613
614                 public virtual void Emit (OpCode opcode, MethodInfo method)
615                 {
616                         if (method == null)
617                                 throw new ArgumentNullException ("method");
618
619                         int token = token_gen.GetToken (method);
620                         make_room (6);
621                         ll_emit (opcode);
622                         if (method.DeclaringType.Module == module)
623                                 add_token_fixup (method);
624                         emit_int (token);
625                         if (method.ReturnType != void_type)
626                                 cur_stack ++;
627
628                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
629                                 cur_stack -= method.GetParameterCount ();
630                 }
631
632                 private void Emit (OpCode opcode, MethodInfo method, int token)
633                 {
634                         make_room (6);
635                         ll_emit (opcode);
636                         if (method.DeclaringType.Module == module)
637                                 add_token_fixup (method);
638                         emit_int (token);
639                         if (method.ReturnType != void_type)
640                                 cur_stack ++;
641
642                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
643                                 cur_stack -= method.GetParameterCount ();
644                 }
645
646                 [CLSCompliant(false)]
647                 public void Emit (OpCode opcode, sbyte val)
648                 {
649                         make_room (3);
650                         ll_emit (opcode);
651                         code [code_len++] = (byte)val;
652                 }
653
654                 public virtual void Emit (OpCode opcode, SignatureHelper shelper)
655                 {
656                         int token = token_gen.GetToken (shelper);
657                         make_room (6);
658                         ll_emit (opcode);
659                         emit_int (token);
660                 }
661
662                 public virtual void Emit (OpCode opcode, float val)
663                 {
664                         byte[] s = System.BitConverter.GetBytes (val);
665                         make_room (6);
666                         ll_emit (opcode);
667                         if (BitConverter.IsLittleEndian){
668                                 System.Array.Copy (s, 0, code, code_len, 4);
669                                 code_len += 4;
670                         } else {
671                                 code [code_len++] = s [3];
672                                 code [code_len++] = s [2];
673                                 code [code_len++] = s [1];
674                                 code [code_len++] = s [0];                              
675                         }
676                 }
677
678                 public virtual void Emit (OpCode opcode, string val)
679                 {
680                         int token = token_gen.GetToken (val);
681                         make_room (6);
682                         ll_emit (opcode);
683                         emit_int (token);
684                 }
685
686                 public virtual void Emit (OpCode opcode, Type type)
687                 {
688                         make_room (6);
689                         ll_emit (opcode);
690                         emit_int (token_gen.GetToken (type));
691                 }
692
693                 [MonoTODO ("Do something about varargs method")]
694                 public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes)
695                 {
696                         if (methodinfo == null)
697                                 throw new ArgumentNullException ("methodinfo can not be null");
698                         short value = opcode.Value;
699                         if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
700                                 throw new NotSupportedException ("Only Call and CallVirt are allowed");
701                         if (optionalParamTypes != null){
702                                 if ((methodinfo.CallingConvention & CallingConventions.VarArgs)  == 0){
703                                         throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
704                                 }
705
706                                 int token = token_gen.GetToken (methodinfo, optionalParamTypes);
707                                 Emit (opcode, methodinfo, token);
708                                 return;
709                         }
710                         Emit (opcode, methodinfo);
711                 }
712
713                 public void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] paramTypes)
714                 {
715                         SignatureHelper helper 
716                                 = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, paramTypes);
717                         Emit (opcode, helper);
718                 }
719
720                 public void EmitCalli (OpCode opcode, CallingConventions callConv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes)
721                 {
722                         if (optionalParamTypes != null)
723                                 throw new NotImplementedException ();
724
725                         SignatureHelper helper 
726                                 = SignatureHelper.GetMethodSigHelper (module, callConv, 0, returnType, paramTypes);
727                         Emit (opcode, helper);
728                 }
729                 
730                 public virtual void EmitWriteLine (FieldInfo field)
731                 {
732                         if (field == null)
733                                 throw new ArgumentNullException ("field");
734                         
735                         // The MS implementation does not check for valuetypes here but it
736                         // should. Also, it should check that if the field is not static,
737                         // then it is a member of this type.
738                         if (field.IsStatic)
739                                 Emit (OpCodes.Ldsfld, field);
740                         else {
741                                 Emit (OpCodes.Ldarg_0);
742                                 Emit (OpCodes.Ldfld, field);
743                         }
744                         Emit (OpCodes.Call, 
745                               typeof (Console).GetMethod ("WriteLine",
746                                                           new Type[1] { field.FieldType }));
747                 }
748
749                 public virtual void EmitWriteLine (LocalBuilder lbuilder)
750                 {
751                         if (lbuilder == null)
752                                 throw new ArgumentNullException ("lbuilder");
753                         if (lbuilder.LocalType is TypeBuilder)
754                                 throw new  ArgumentException ("Output streams do not support TypeBuilders.");
755                         // The MS implementation does not check for valuetypes here but it
756                         // should.
757                         Emit (OpCodes.Ldloc, lbuilder);
758                         Emit (OpCodes.Call, 
759                               typeof (Console).GetMethod ("WriteLine",
760                                                           new Type[1] { lbuilder.LocalType }));
761                 }
762                 
763                 public virtual void EmitWriteLine (string val)
764                 {
765                         Emit (OpCodes.Ldstr, val);
766                         Emit (OpCodes.Call, 
767                               typeof (Console).GetMethod ("WriteLine",
768                                                           new Type[1] { typeof(string)}));
769                 }
770
771                 public virtual void EndExceptionBlock ()
772                 {
773                         if (open_blocks.Count <= 0)
774                                 throw new NotSupportedException ("Not in an exception block");
775                         InternalEndClause ();
776                         MarkLabel (ex_handlers [cur_block].end);
777                         ex_handlers [cur_block].End (code_len);
778                         ex_handlers [cur_block].Debug (cur_block);
779                         //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
780                         open_blocks.Pop ();
781                         if (open_blocks.Count > 0)
782                                 cur_block = (int)open_blocks.Peek ();
783                         //Console.WriteLine ("curblock restored to {0}", cur_block);
784                         //throw new NotImplementedException ();
785                 }
786
787                 public virtual void EndScope ()
788                 {
789                         if (sym_writer != null) {
790                                 sym_writer.CloseScope (code_len);
791                                 if (scopes == null)
792                                         throw new InvalidOperationException ();
793                                 scopes.Pop ();
794                         }
795                 }
796
797                 public virtual void MarkLabel (Label loc)
798                 {
799                         if (loc.label < 0 || loc.label >= num_labels)
800                                 throw new System.ArgumentException ("The label is not valid");
801                         if (labels [loc.label].addr >= 0)
802                                 throw new System.ArgumentException ("The label was already defined");
803                         labels [loc.label].addr = code_len;
804                         if (labels [loc.label].maxStack > cur_stack)
805                                 cur_stack = labels [loc.label].maxStack;
806                 }
807
808                 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
809                                                        int startColumn, int endLine, int endColumn)
810                 {
811                         if (sym_writer == null)
812                                 return;
813
814                         sym_writer.MarkSequencePoint (code_len, startLine, startColumn);
815                 }
816
817                 public virtual void ThrowException (Type exceptionType)
818                 {
819                         if (exceptionType == null)
820                                 throw new ArgumentNullException ("exceptionType");
821                         if (! ((exceptionType == typeof (Exception)) || 
822                                    exceptionType.IsSubclassOf (typeof (Exception))))
823                                 throw new ArgumentException ("Type should be an exception type", "exceptionType");
824                         ConstructorInfo ctor = exceptionType.GetConstructor (new Type[0]);
825                         if (ctor == null)
826                                 throw new ArgumentException ("Type should have a default constructor", "exceptionType");
827                         Emit (OpCodes.Newobj, ctor);
828                         Emit (OpCodes.Throw);
829                 }
830
831                 [MonoTODO]
832                 public void UsingNamespace (String usingNamespace)
833                 {
834                         throw new NotImplementedException ();
835                 }
836
837                 internal void label_fixup ()
838                 {
839                         for (int i = 0; i < num_fixups; ++i) {
840                                 
841                                 // Diff is the offset from the end of the jump instruction to the address of the label
842                                 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
843                                 if (fixups [i].offset == 1) {
844                                         code [fixups [i].pos] = (byte)((sbyte) diff);
845                                 } else {
846                                         int old_cl = code_len;
847                                         code_len = fixups [i].pos;
848                                         emit_int (diff);
849                                         code_len = old_cl;
850                                 }
851                         }
852                 }
853         }
854 }