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