New test.
[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 (String.Empty);
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 AddFilter (int offset)
108                 {
109                         int i;
110                         End (offset);
111                         add_block (offset);
112                         i = handlers.Length - 1;
113                         handlers [i].type = ILExceptionBlock.FILTER;
114                         handlers [i].extype = null;
115                         handlers [i].filter_offset = offset;
116                 }
117
118                 internal void End (int offset)
119                 {
120                         if (handlers == null)
121                                 return;
122                         int i = handlers.Length - 1;
123                         if (i >= 0)
124                                 handlers [i].len = offset - handlers [i].start;
125                 }
126
127                 internal int LastClauseType ()
128                 {
129                         if (handlers != null)
130                                 return handlers [handlers.Length-1].type;
131                         else
132                                 return ILExceptionBlock.CATCH;
133                 }
134
135                 internal void PatchLastClauseStart (int start)
136                 {
137                         if (handlers != null && handlers.Length > 0)
138                                 handlers [handlers.Length - 1].start = start;
139                 }
140
141                 internal void Debug (int b)
142                 {
143 #if NO
144                         System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
145                         for (int i = 0; i < handlers.Length; ++i)
146                                 handlers [i].Debug ();
147 #endif
148                 }
149
150                 void add_block (int offset)
151                 {
152                         if (handlers != null) {
153                                 int i = handlers.Length;
154                                 ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
155                                 System.Array.Copy (handlers, new_b, i);
156                                 handlers = new_b;
157                                 handlers [i].len = offset - handlers [i].start;
158                         } else {
159                                 handlers = new ILExceptionBlock [1];
160                                 len = offset - start;
161                         }
162                 }
163         }
164         
165         internal struct ILTokenInfo {
166                 public MemberInfo member;
167                 public int code_pos;
168         }
169
170         internal interface TokenGenerator {
171                 int GetToken (string str);
172
173                 int GetToken (MemberInfo member);
174
175                 int GetToken (MethodInfo method, Type[] opt_param_types);
176
177                 int GetToken (SignatureHelper helper);
178         }               
179
180 #if NET_2_0
181         [ComVisible (true)]
182 #endif
183         [ClassInterface (ClassInterfaceType.None)]
184         public class ILGenerator: _ILGenerator {
185                 private struct LabelFixup {
186                         public int offset;    // The number of bytes between pos and the
187                                                               // offset of the jump
188                         public int pos;       // Where offset of the label is placed
189                         public int label_idx; // The label to jump to
190                 };
191                 
192                 struct LabelData {
193                         public LabelData (int addr, int maxStack)
194                         {
195                                 this.addr = addr;
196                                 this.maxStack = maxStack;
197                         }
198                         
199                         public int addr;
200                         public int maxStack; 
201                 }
202                 
203                 static readonly Type void_type = typeof (void);
204                 #region Sync with reflection.h
205                 private byte[] code;
206                 private int code_len;
207                 private int max_stack;
208                 private int cur_stack;
209                 private LocalBuilder[] locals;
210                 private ILExceptionInfo[] ex_handlers;
211                 private int num_token_fixups;
212                 private ILTokenInfo[] token_fixups;
213                 #endregion
214                 
215                 private LabelData [] labels;
216                 private int num_labels;
217                 private LabelFixup[] fixups;
218                 private int num_fixups;
219                 internal Module module;
220                 private Stack scopes;
221                 private int cur_block;
222                 private Stack open_blocks;
223                 private TokenGenerator token_gen;
224                 
225                 const int defaultFixupSize = 4;
226                 const int defaultLabelsSize = 4;
227                 const int defaultExceptionStackSize = 2;
228                 
229                 ArrayList sequencePointLists;
230                 SequencePointList currentSequence;
231
232                 internal ILGenerator (Module m, TokenGenerator token_gen, int size)
233                 {
234                         if (size < 0)
235                                 size = 128;
236                         code = new byte [size];
237                         token_fixups = new ILTokenInfo [8];
238                         module = m;
239                         this.token_gen = token_gen;
240                 }
241                 
242                 private void add_token_fixup (MemberInfo mi)
243                 {
244                         if (num_token_fixups == token_fixups.Length) {
245                                 ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
246                                 token_fixups.CopyTo (ntf, 0);
247                                 token_fixups = ntf;
248                         }
249                         token_fixups [num_token_fixups].member = mi;
250                         token_fixups [num_token_fixups++].code_pos = code_len;
251                 }
252
253                 private void make_room (int nbytes)
254                 {
255                         if (code_len + nbytes < code.Length)
256                                 return;
257                         byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
258                         System.Array.Copy (code, 0, new_code, 0, code.Length);
259                         code = new_code;
260                 }
261
262                 private void emit_int (int val)
263                 {
264                         code [code_len++] = (byte) (val & 0xFF);
265                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
266                         code [code_len++] = (byte) ((val >> 16) & 0xFF);
267                         code [code_len++] = (byte) ((val >> 24) & 0xFF);
268                 }
269
270                 /* change to pass by ref to avoid copy */
271                 private void ll_emit (OpCode opcode)
272                 {
273                         /* 
274                          * there is already enough room allocated in code.
275                          */
276                         // access op1 and op2 directly since the Value property is useless
277                         if (opcode.Size == 2)
278                                 code [code_len++] = opcode.op1;
279                         code [code_len++] = opcode.op2;
280                         /*
281                          * We should probably keep track of stack needs here.
282                          * Or we may want to run the verifier on the code before saving it
283                          * (this may be needed anyway when the ILGenerator is not used...).
284                          */
285                         switch (opcode.StackBehaviourPush) {
286                         case StackBehaviour.Push1:
287                         case StackBehaviour.Pushi:
288                         case StackBehaviour.Pushi8:
289                         case StackBehaviour.Pushr4:
290                         case StackBehaviour.Pushr8:
291                         case StackBehaviour.Pushref:
292                         case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
293                                 cur_stack ++;
294                                 break;
295                         case StackBehaviour.Push1_push1:
296                                 cur_stack += 2;
297                                 break;
298                         }
299                         if (max_stack < cur_stack)
300                                 max_stack = cur_stack;
301
302                         /* 
303                          * Note that we adjust for the pop behaviour _after_ setting max_stack.
304                          */
305                         switch (opcode.StackBehaviourPop) {
306                         case StackBehaviour.Varpop:
307                                 break; /* we are conservative and assume it doesn't decrease the stack needs */
308                         case StackBehaviour.Pop1:
309                         case StackBehaviour.Popi:
310                         case StackBehaviour.Popref:
311                                 cur_stack --;
312                                 break;
313                         case StackBehaviour.Pop1_pop1:
314                         case StackBehaviour.Popi_pop1:
315                         case StackBehaviour.Popi_popi:
316                         case StackBehaviour.Popi_popi8:
317                         case StackBehaviour.Popi_popr4:
318                         case StackBehaviour.Popi_popr8:
319                         case StackBehaviour.Popref_pop1:
320                         case StackBehaviour.Popref_popi:
321                                 cur_stack -= 2;
322                                 break;
323                         case StackBehaviour.Popi_popi_popi:
324                         case StackBehaviour.Popref_popi_popi:
325                         case StackBehaviour.Popref_popi_popi8:
326                         case StackBehaviour.Popref_popi_popr4:
327                         case StackBehaviour.Popref_popi_popr8:
328                         case StackBehaviour.Popref_popi_popref:
329                                 cur_stack -= 3;
330                                 break;
331                         }
332                 }
333
334                 private static int target_len (OpCode opcode)
335                 {
336                         if (opcode.OperandType == OperandType.InlineBrTarget)
337                                 return 4;
338                         return 1;
339                 }
340
341                 private void InternalEndClause ()
342                 {
343                         switch (ex_handlers [cur_block].LastClauseType ()) {
344                         case ILExceptionBlock.CATCH:
345                         case ILExceptionBlock.FILTER:
346                                 // how could we optimize code size here?
347                                 Emit (OpCodes.Leave, ex_handlers [cur_block].end);
348                                 break;
349                         case ILExceptionBlock.FAULT:
350                         case ILExceptionBlock.FINALLY:
351                                 Emit (OpCodes.Endfinally);
352                                 break;
353                         }
354                 }
355
356                 public virtual void BeginCatchBlock (Type exceptionType)
357                 {
358                         if (open_blocks == null)
359                                 open_blocks = new Stack (defaultExceptionStackSize);
360
361                         if (open_blocks.Count <= 0)
362                                 throw new NotSupportedException ("Not in an exception block");
363
364                         if (ex_handlers [cur_block].LastClauseType () == ILExceptionBlock.FILTER) {
365                                 if (exceptionType != null)
366                                         throw new ArgumentException ("Do not supply an exception type for filter clause");
367                                 Emit (OpCodes.Endfilter);
368                                 ex_handlers [cur_block].PatchLastClauseStart (code_len);
369                         } else {
370                                 InternalEndClause ();
371                                 ex_handlers [cur_block].AddCatch (exceptionType, code_len);
372                         }
373                         
374                         cur_stack = 1; // the exception object is on the stack by default
375                         if (max_stack < cur_stack)
376                                 max_stack = cur_stack;
377
378                         //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
379                 }
380
381                 public virtual void BeginExceptFilterBlock ()
382                 {
383                         if (open_blocks == null)
384                                 open_blocks = new Stack (defaultExceptionStackSize);
385                         
386                         if (open_blocks.Count <= 0)
387                                 throw new NotSupportedException ("Not in an exception block");
388                         InternalEndClause ();
389
390                         ex_handlers [cur_block].AddFilter (code_len);
391                 }
392
393                 public virtual Label BeginExceptionBlock ()
394                 {
395                         //System.Console.WriteLine ("Begin Block");
396                         if (open_blocks == null)
397                                 open_blocks = new Stack (defaultExceptionStackSize);
398                         
399                         if (ex_handlers != null) {
400                                 cur_block = ex_handlers.Length;
401                                 ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
402                                 System.Array.Copy (ex_handlers, new_ex, cur_block);
403                                 ex_handlers = new_ex;
404                         } else {
405                                 ex_handlers = new ILExceptionInfo [1];
406                                 cur_block = 0;
407                         }
408                         open_blocks.Push (cur_block);
409                         ex_handlers [cur_block].start = code_len;
410                         return ex_handlers [cur_block].end = DefineLabel ();
411                 }
412
413                 public virtual void BeginFaultBlock()
414                 {
415                         if (open_blocks == null)
416                                 open_blocks = new Stack (defaultExceptionStackSize);
417                         
418                         if (open_blocks.Count <= 0)
419                                 throw new NotSupportedException ("Not in an exception block");
420                         InternalEndClause ();
421                         //System.Console.WriteLine ("Begin fault Block");
422                         ex_handlers [cur_block].AddFault (code_len);
423                 }
424                 
425                 public virtual void BeginFinallyBlock()
426                 {
427                         if (open_blocks == null)
428                                 open_blocks = new Stack (defaultExceptionStackSize);
429                         
430                         if (open_blocks.Count <= 0)
431                                 throw new NotSupportedException ("Not in an exception block");
432                         InternalEndClause ();
433                         //System.Console.WriteLine ("Begin finally Block");
434                         ex_handlers [cur_block].AddFinally (code_len);
435                 }
436                 
437                 public virtual void BeginScope ()
438                 { }
439                 
440                 public LocalBuilder DeclareLocal (Type localType)
441                 {
442                         return DeclareLocal (localType, false);
443                 }
444
445
446 #if NET_2_0
447                 public
448 #else
449                 internal
450 #endif
451                 LocalBuilder DeclareLocal (Type localType, bool pinned)
452                 {
453                         if (localType == null)
454                                 throw new ArgumentNullException ("localType");
455
456                         LocalBuilder res = new LocalBuilder (localType, this);
457                         res.is_pinned = pinned;
458                         
459                         if (locals != null) {
460                                 LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
461                                 System.Array.Copy (locals, new_l, locals.Length);
462                                 new_l [locals.Length] = res;
463                                 locals = new_l;
464                         } else {
465                                 locals = new LocalBuilder [1];
466                                 locals [0] = res;
467                         }
468                         res.position = (ushort)(locals.Length - 1);
469                         return res;
470                 }
471                 
472                 public virtual Label DefineLabel ()
473                 {
474                         if (labels == null)
475                                 labels = new LabelData [defaultLabelsSize];
476                         else if (num_labels >= labels.Length) {
477                                 LabelData [] t = new LabelData [labels.Length * 2];
478                                 Array.Copy (labels, t, labels.Length);
479                                 labels = t;
480                         }
481                         
482                         labels [num_labels] = new LabelData (-1, 0);
483                         
484                         return new Label (num_labels++);
485                 }
486                 
487                 public virtual void Emit (OpCode opcode)
488                 {
489                         make_room (2);
490                         ll_emit (opcode);
491                 }
492                 
493                 public virtual void Emit (OpCode opcode, Byte val)
494                 {
495                         make_room (3);
496                         ll_emit (opcode);
497                         code [code_len++] = val;
498                 }
499                 
500 #if NET_2_0
501                 [ComVisible (true)]
502 #endif
503                 public virtual void Emit (OpCode opcode, ConstructorInfo constructor)
504                 {
505                         int token = token_gen.GetToken (constructor);
506                         make_room (6);
507                         ll_emit (opcode);
508                         if (constructor.DeclaringType.Module == module)
509                                 add_token_fixup (constructor);
510                         emit_int (token);
511                         
512                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
513                                 cur_stack -= constructor.GetParameterCount ();
514                 }
515                 
516                 public virtual void Emit (OpCode opcode, double val)
517                 {
518                         byte[] s = System.BitConverter.GetBytes (val);
519                         make_room (10);
520                         ll_emit (opcode);
521                         if (BitConverter.IsLittleEndian){
522                                 System.Array.Copy (s, 0, code, code_len, 8);
523                                 code_len += 8;
524                         } else {
525                                 code [code_len++] = s [7];
526                                 code [code_len++] = s [6];
527                                 code [code_len++] = s [5];
528                                 code [code_len++] = s [4];
529                                 code [code_len++] = s [3];
530                                 code [code_len++] = s [2];
531                                 code [code_len++] = s [1];
532                                 code [code_len++] = s [0];                              
533                         }
534                 }
535                 
536                 public virtual void Emit (OpCode opcode, FieldInfo field)
537                 {
538                         int token = token_gen.GetToken (field);
539                         make_room (6);
540                         ll_emit (opcode);
541                         if (field.DeclaringType.Module == module)
542                                 add_token_fixup (field);
543                         emit_int (token);
544                 }
545                 
546                 public virtual void Emit (OpCode opcode, Int16 val)
547                 {
548                         make_room (4);
549                         ll_emit (opcode);
550                         code [code_len++] = (byte) (val & 0xFF);
551                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
552                 }
553                 
554                 public virtual void Emit (OpCode opcode, int val)
555                 {
556                         make_room (6);
557                         ll_emit (opcode);
558                         emit_int (val);
559                 }
560                 
561                 public virtual void Emit (OpCode opcode, long val)
562                 {
563                         make_room (10);
564                         ll_emit (opcode);
565                         code [code_len++] = (byte) (val & 0xFF);
566                         code [code_len++] = (byte) ((val >> 8) & 0xFF);
567                         code [code_len++] = (byte) ((val >> 16) & 0xFF);
568                         code [code_len++] = (byte) ((val >> 24) & 0xFF);
569                         code [code_len++] = (byte) ((val >> 32) & 0xFF);
570                         code [code_len++] = (byte) ((val >> 40) & 0xFF);
571                         code [code_len++] = (byte) ((val >> 48) & 0xFF);
572                         code [code_len++] = (byte) ((val >> 56) & 0xFF);
573                 }
574                 
575                 public virtual void Emit (OpCode opcode, Label label)
576                 {
577                         int tlen = target_len (opcode);
578                         make_room (6);
579                         ll_emit (opcode);
580                         if (cur_stack > labels [label.label].maxStack)
581                                 labels [label.label].maxStack = cur_stack;
582                         
583                         if (fixups == null)
584                                 fixups = new LabelFixup [defaultFixupSize]; 
585                         else if (num_fixups >= fixups.Length) {
586                                 LabelFixup[] newf = new LabelFixup [fixups.Length * 2];
587                                 System.Array.Copy (fixups, newf, fixups.Length);
588                                 fixups = newf;
589                         }
590                         fixups [num_fixups].offset = tlen;
591                         fixups [num_fixups].pos = code_len;
592                         fixups [num_fixups].label_idx = label.label;
593                         num_fixups++;
594                         code_len += tlen;
595
596                 }
597                 
598                 public virtual void Emit (OpCode opcode, Label[] labels)
599                 {
600                         /* opcode needs to be switch. */
601                         int count = labels.Length;
602                         make_room (6 + count * 4);
603                         ll_emit (opcode);
604
605                         for (int i = 0; i < count; ++i)
606                                 if (cur_stack > this.labels [labels [i].label].maxStack)
607                                         this.labels [labels [i].label].maxStack = cur_stack;
608
609                         emit_int (count);
610                         if (fixups == null)
611                                 fixups = new LabelFixup [defaultFixupSize + count]; 
612                         else if (num_fixups + count >= fixups.Length) {
613                                 LabelFixup[] newf = new LabelFixup [count + fixups.Length * 2];
614                                 System.Array.Copy (fixups, newf, fixups.Length);
615                                 fixups = newf;
616                         }
617                         
618                         // ECMA 335, Partition III, p94 (7-10)
619                         //
620                         // The switch instruction implements a jump table. The format of 
621                         // the instruction is an unsigned int32 representing the number of targets N,
622                         // followed by N int32 values specifying jump targets: these targets are
623                         // represented as offsets (positive or negative) from the beginning of the 
624                         // instruction following this switch instruction.
625                         //
626                         // We must make sure it gets an offset from the *end* of the last label
627                         // (eg, the beginning of the instruction following this).
628                         //
629                         // remaining is the number of bytes from the current instruction to the
630                         // instruction that will be emitted.
631                         
632                         for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
633                                 fixups [num_fixups].offset = remaining;
634                                 fixups [num_fixups].pos = code_len;
635                                 fixups [num_fixups].label_idx = labels [i].label;
636                                 num_fixups++;
637                                 code_len += 4;
638                         }
639                 }
640
641                 public virtual void Emit (OpCode opcode, LocalBuilder lbuilder)
642                 {
643                         uint pos = lbuilder.position;
644                         bool load_addr = false;
645                         bool is_store = false;
646                         make_room (6);
647
648                         if (lbuilder.ilgen != this)
649                                 throw new Exception ("Trying to emit a local from a different ILGenerator.");
650
651                         /* inline the code from ll_emit () to optimize il code size */
652                         if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
653                                 cur_stack --;
654                                 is_store = true;
655                         } else {
656                                 cur_stack++;
657                                 if (cur_stack > max_stack)
658                                         max_stack = cur_stack;
659                                 load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
660                         }
661                         if (load_addr) {
662                                 if (pos < 256) {
663                                         code [code_len++] = (byte)0x12;
664                                         code [code_len++] = (byte)pos;
665                                 } else {
666                                         code [code_len++] = (byte)0xfe;
667                                         code [code_len++] = (byte)0x0d;
668                                         code [code_len++] = (byte)(pos & 0xff);
669                                         code [code_len++] = (byte)((pos >> 8) & 0xff);
670                                 }
671                         } else {
672                                 if (is_store) {
673                                         if (pos < 4) {
674                                                 code [code_len++] = (byte)(0x0a + pos);
675                                         } else if (pos < 256) {
676                                                 code [code_len++] = (byte)0x13;
677                                                 code [code_len++] = (byte)pos;
678                                         } else {
679                                                 code [code_len++] = (byte)0xfe;
680                                                 code [code_len++] = (byte)0x0e;
681                                                 code [code_len++] = (byte)(pos & 0xff);
682                                                 code [code_len++] = (byte)((pos >> 8) & 0xff);
683                                         }
684                                 } else {
685                                         if (pos < 4) {
686                                                 code [code_len++] = (byte)(0x06 + pos);
687                                         } else if (pos < 256) {
688                                                 code [code_len++] = (byte)0x11;
689                                                 code [code_len++] = (byte)pos;
690                                         } else {
691                                                 code [code_len++] = (byte)0xfe;
692                                                 code [code_len++] = (byte)0x0c;
693                                                 code [code_len++] = (byte)(pos & 0xff);
694                                                 code [code_len++] = (byte)((pos >> 8) & 0xff);
695                                         }
696                                 }
697                         }
698                 }
699
700                 public virtual void Emit (OpCode opcode, MethodInfo method)
701                 {
702                         if (method == null)
703                                 throw new ArgumentNullException ("method");
704
705                         int token = token_gen.GetToken (method);
706                         make_room (6);
707                         ll_emit (opcode);
708                         Type declaringType = method.DeclaringType;
709                         // Might be a DynamicMethod with no declaring type
710                         if (declaringType != null) {
711                                 if (declaringType.Module == module)
712                                         add_token_fixup (method);
713                         }
714                         emit_int (token);
715                         if (method.ReturnType != void_type)
716                                 cur_stack ++;
717
718                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
719                                 cur_stack -= method.GetParameterCount ();
720                 }
721
722                 private void Emit (OpCode opcode, MethodInfo method, int token)
723                 {
724                         make_room (6);
725                         ll_emit (opcode);
726                         // Might be a DynamicMethod with no declaring type
727                         Type declaringType = method.DeclaringType;
728                         if (declaringType != null) {
729                                 if (declaringType.Module == module)
730                                         add_token_fixup (method);
731                         }
732                         emit_int (token);
733                         if (method.ReturnType != void_type)
734                                 cur_stack ++;
735
736                         if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
737                                 cur_stack -= method.GetParameterCount ();
738                 }
739
740                 [CLSCompliant(false)]
741                 public void Emit (OpCode opcode, sbyte val)
742                 {
743                         make_room (3);
744                         ll_emit (opcode);
745                         code [code_len++] = (byte)val;
746                 }
747
748                 public virtual void Emit (OpCode opcode, SignatureHelper shelper)
749                 {
750                         int token = token_gen.GetToken (shelper);
751                         make_room (6);
752                         ll_emit (opcode);
753                         emit_int (token);
754                 }
755
756                 public virtual void Emit (OpCode opcode, float val)
757                 {
758                         byte[] s = System.BitConverter.GetBytes (val);
759                         make_room (6);
760                         ll_emit (opcode);
761                         if (BitConverter.IsLittleEndian){
762                                 System.Array.Copy (s, 0, code, code_len, 4);
763                                 code_len += 4;
764                         } else {
765                                 code [code_len++] = s [3];
766                                 code [code_len++] = s [2];
767                                 code [code_len++] = s [1];
768                                 code [code_len++] = s [0];                              
769                         }
770                 }
771
772                 public virtual void Emit (OpCode opcode, string val)
773                 {
774                         int token = token_gen.GetToken (val);
775                         make_room (6);
776                         ll_emit (opcode);
777                         emit_int (token);
778                 }
779
780                 public virtual void Emit (OpCode opcode, Type type)
781                 {
782                         make_room (6);
783                         ll_emit (opcode);
784                         emit_int (token_gen.GetToken (type));
785                 }
786
787                 [MonoTODO ("Do something about varargs method")]
788                 public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes)
789                 {
790                         if (methodinfo == null)
791                                 throw new ArgumentNullException ("methodinfo can not be null");
792                         short value = opcode.Value;
793                         if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
794                                 throw new NotSupportedException ("Only Call and CallVirt are allowed");
795                         if (optionalParamTypes != null){
796                                 if ((methodinfo.CallingConvention & CallingConventions.VarArgs)  == 0){
797                                         throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
798                                 }
799
800                                 int token = token_gen.GetToken (methodinfo, optionalParamTypes);
801                                 Emit (opcode, methodinfo, token);
802                                 return;
803                         }
804                         Emit (opcode, methodinfo);
805                 }
806
807                 public void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] paramTypes)
808                 {
809                         SignatureHelper helper 
810                                 = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, paramTypes);
811                         Emit (opcode, helper);
812                 }
813
814                 public void EmitCalli (OpCode opcode, CallingConventions callConv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes)
815                 {
816                         if (optionalParamTypes != null)
817                                 throw new NotImplementedException ();
818
819                         SignatureHelper helper 
820                                 = SignatureHelper.GetMethodSigHelper (module, callConv, 0, returnType, paramTypes);
821                         Emit (opcode, helper);
822                 }
823                 
824                 public virtual void EmitWriteLine (FieldInfo field)
825                 {
826                         if (field == null)
827                                 throw new ArgumentNullException ("field");
828                         
829                         // The MS implementation does not check for valuetypes here but it
830                         // should. Also, it should check that if the field is not static,
831                         // then it is a member of this type.
832                         if (field.IsStatic)
833                                 Emit (OpCodes.Ldsfld, field);
834                         else {
835                                 Emit (OpCodes.Ldarg_0);
836                                 Emit (OpCodes.Ldfld, field);
837                         }
838                         Emit (OpCodes.Call, 
839                               typeof (Console).GetMethod ("WriteLine",
840                                                           new Type[1] { field.FieldType }));
841                 }
842
843                 public virtual void EmitWriteLine (LocalBuilder lbuilder)
844                 {
845                         if (lbuilder == null)
846                                 throw new ArgumentNullException ("lbuilder");
847                         if (lbuilder.LocalType is TypeBuilder)
848                                 throw new  ArgumentException ("Output streams do not support TypeBuilders.");
849                         // The MS implementation does not check for valuetypes here but it
850                         // should.
851                         Emit (OpCodes.Ldloc, lbuilder);
852                         Emit (OpCodes.Call, 
853                               typeof (Console).GetMethod ("WriteLine",
854                                                           new Type[1] { lbuilder.LocalType }));
855                 }
856                 
857                 public virtual void EmitWriteLine (string val)
858                 {
859                         Emit (OpCodes.Ldstr, val);
860                         Emit (OpCodes.Call, 
861                               typeof (Console).GetMethod ("WriteLine",
862                                                           new Type[1] { typeof(string)}));
863                 }
864
865                 public virtual void EndExceptionBlock ()
866                 {
867                         if (open_blocks == null)
868                                 open_blocks = new Stack (defaultExceptionStackSize);
869                         
870                         if (open_blocks.Count <= 0)
871                                 throw new NotSupportedException ("Not in an exception block");
872                         InternalEndClause ();
873                         MarkLabel (ex_handlers [cur_block].end);
874                         ex_handlers [cur_block].End (code_len);
875                         ex_handlers [cur_block].Debug (cur_block);
876                         //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
877                         open_blocks.Pop ();
878                         if (open_blocks.Count > 0)
879                                 cur_block = (int)open_blocks.Peek ();
880                         //Console.WriteLine ("curblock restored to {0}", cur_block);
881                         //throw new NotImplementedException ();
882                 }
883
884                 public virtual void EndScope ()
885                 { }
886
887                 public virtual void MarkLabel (Label loc)
888                 {
889                         if (loc.label < 0 || loc.label >= num_labels)
890                                 throw new System.ArgumentException ("The label is not valid");
891                         if (labels [loc.label].addr >= 0)
892                                 throw new System.ArgumentException ("The label was already defined");
893                         labels [loc.label].addr = code_len;
894                         if (labels [loc.label].maxStack > cur_stack)
895                                 cur_stack = labels [loc.label].maxStack;
896                 }
897
898                 public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
899                                                        int startColumn, int endLine, int endColumn)
900                 {
901                         if (currentSequence == null || currentSequence.Document != document) {
902                                 if (sequencePointLists == null)
903                                         sequencePointLists = new ArrayList ();
904                                 currentSequence = new SequencePointList (document);
905                                 sequencePointLists.Add (currentSequence);
906                         }
907                         
908                         currentSequence.AddSequencePoint (code_len, startLine, startColumn, endLine, endColumn);
909                 }
910                 
911                 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
912                 {
913                         if (sequencePointLists != null) {
914                                 SequencePointList first = (SequencePointList) sequencePointLists [0];
915                                 SequencePointList last = (SequencePointList) sequencePointLists [sequencePointLists.Count - 1];
916                                 symbolWriter.SetMethodSourceRange (first.Document, first.StartLine, first.StartColumn, last.Document, last.EndLine, last.EndColumn);
917                                 
918                                 foreach (SequencePointList list in sequencePointLists)
919                                         symbolWriter.DefineSequencePoints (list.Document, list.GetOffsets(), list.GetLines(), list.GetColumns(), list.GetEndLines(), list.GetEndColumns());
920                                 
921                                 if (locals != null) {
922                                         foreach (LocalBuilder local in locals) {
923                                                 if (local.Name != null && local.Name.Length > 0) {
924                                                         SignatureHelper sighelper = SignatureHelper.GetLocalVarSigHelper (module);
925                                                         sighelper.AddArgument (local.LocalType);
926                                                         byte[] signature = sighelper.GetSignature ();
927                                                         symbolWriter.DefineLocalVariable (local.Name, FieldAttributes.Public, signature, SymAddressKind.ILOffset, local.position, 0, 0, local.StartOffset, local.EndOffset);
928                                                 }
929                                         }
930                                 }
931                                 sequencePointLists = null;
932                         }
933                 }
934                 
935                 internal bool HasDebugInfo
936                 {
937                         get { return sequencePointLists != null; }
938                 }
939
940                 public virtual void ThrowException (Type exceptionType)
941                 {
942                         if (exceptionType == null)
943                                 throw new ArgumentNullException ("exceptionType");
944                         if (! ((exceptionType == typeof (Exception)) || 
945                                    exceptionType.IsSubclassOf (typeof (Exception))))
946                                 throw new ArgumentException ("Type should be an exception type", "exceptionType");
947                         ConstructorInfo ctor = exceptionType.GetConstructor (new Type[0]);
948                         if (ctor == null)
949                                 throw new ArgumentException ("Type should have a default constructor", "exceptionType");
950                         Emit (OpCodes.Newobj, ctor);
951                         Emit (OpCodes.Throw);
952                 }
953
954                 [MonoTODO]
955                 public void UsingNamespace (String usingNamespace)
956                 {
957                         throw new NotImplementedException ();
958                 }
959
960                 internal void label_fixup ()
961                 {
962                         for (int i = 0; i < num_fixups; ++i) {
963                                 
964                                 // Diff is the offset from the end of the jump instruction to the address of the label
965                                 int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
966                                 if (fixups [i].offset == 1) {
967                                         code [fixups [i].pos] = (byte)((sbyte) diff);
968                                 } else {
969                                         int old_cl = code_len;
970                                         code_len = fixups [i].pos;
971                                         emit_int (diff);
972                                         code_len = old_cl;
973                                 }
974                         }
975                 }
976
977                 internal static int Mono_GetCurrentOffset (ILGenerator ig)
978                 {
979                         return ig.code_len;
980                 }
981
982                 void _ILGenerator.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
983                 {
984                         throw new NotImplementedException ();
985                 }
986
987                 void _ILGenerator.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
988                 {
989                         throw new NotImplementedException ();
990                 }
991
992                 void _ILGenerator.GetTypeInfoCount (out uint pcTInfo)
993                 {
994                         throw new NotImplementedException ();
995                 }
996
997                 void _ILGenerator.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
998                 {
999                         throw new NotImplementedException ();
1000                 }
1001         }
1002         
1003         internal class SequencePointList
1004         {
1005                 ISymbolDocumentWriter doc;
1006                 SequencePoint[] points;
1007                 int count;
1008                 const int arrayGrow = 10;
1009                 
1010                 public SequencePointList (ISymbolDocumentWriter doc)
1011                 {
1012                         this.doc = doc;
1013                 }
1014                 
1015                 public ISymbolDocumentWriter Document {
1016                         get { return doc; }
1017                 }
1018                 
1019                 public int[] GetOffsets()
1020                 {
1021                         int[] data = new int [count];
1022                         for (int n=0; n<count; n++) data [n] = points[n].Offset;
1023                         return data; 
1024                 }
1025                 public int[] GetLines()
1026                 {
1027                         int[] data = new int [count];
1028                         for (int n=0; n<count; n++) data [n] = points[n].Line;
1029                         return data; 
1030                 }
1031                 public int[] GetColumns()
1032                 {
1033                         int[] data = new int [count];
1034                         for (int n=0; n<count; n++) data [n] = points[n].Col;
1035                         return data; 
1036                 }
1037                 public int[] GetEndLines()
1038                 {
1039                         int[] data = new int [count];
1040                         for (int n=0; n<count; n++) data [n] = points[n].EndLine;
1041                         return data; 
1042                 }
1043                 public int[] GetEndColumns()
1044                 {
1045                         int[] data = new int [count];
1046                         for (int n=0; n<count; n++) data [n] = points[n].EndCol;
1047                         return data; 
1048                 }
1049                 public int StartLine {
1050                         get { return points[0].Line; }
1051                 }
1052                 public int EndLine {
1053                         get { return points[count - 1].Line; }
1054                 }
1055                 public int StartColumn {
1056                         get { return points[0].Col; }
1057                 }
1058                 public int EndColumn {
1059                         get { return points[count - 1].Col; }
1060                 }
1061                 
1062                 public void AddSequencePoint (int offset, int line, int col, int endLine, int endCol)
1063                 {
1064                         SequencePoint s = new SequencePoint ();
1065                         s.Offset = offset;
1066                         s.Line = line;
1067                         s.Col = col;
1068                         s.EndLine = endLine;
1069                         s.EndCol = endCol;
1070                         
1071                         if (points == null) {
1072                                 points = new SequencePoint [arrayGrow];
1073                         } else if (count >= points.Length) {
1074                                 SequencePoint[] temp = new SequencePoint [count + arrayGrow];
1075                                 Array.Copy (points, temp, points.Length);
1076                                 points = temp;
1077                         }
1078                         
1079                         points [count] = s;
1080                         count++;
1081                 }
1082         }
1083         
1084         struct SequencePoint {
1085                 public int Offset;
1086                 public int Line;
1087                 public int Col;
1088                 public int EndLine;
1089                 public int EndCol;
1090         }
1091 }