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