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