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