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