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