2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Reflection.Emit / ILGenerator.cs
index 0956a8bd1b8606e9d1833652947ea17923326a78..b99186888fde6e57f31ef2f1b953d679ecf54171 100644 (file)
@@ -1,4 +1,27 @@
 
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 //
 // System.Reflection.Emit/ILGenerator.cs
 //
 //
 
 using System;
+using System.Collections;
 using System.Diagnostics.SymbolStore;
+using System.Runtime.InteropServices;
 
 namespace System.Reflection.Emit {
+
+       internal struct ILExceptionBlock {
+               public const int CATCH = 0;
+               public const int FILTER = 1;
+               public const int FINALLY = 2;
+               public const int FAULT = 4;
+
+               internal Type extype;
+               internal int type;
+               internal int start;
+               internal int len;
+               internal int filter_offset;
+               
+               internal void Debug () {
+#if NO
+                       System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString()+" len="+len.ToString());
+                       if (extype != null)
+                               System.Console.WriteLine (" extype="+extype.ToString());
+                       else
+                               System.Console.WriteLine ("");
+#endif
+               }
+       }
+       internal struct ILExceptionInfo {
+               ILExceptionBlock[] handlers;
+               internal int start;
+               int len;
+               internal Label end;
+
+               internal int NumHandlers ()
+               {
+                       return handlers.Length;
+               }
+               
+               internal void AddCatch (Type extype, int offset)
+               {
+                       int i;
+                       End (offset);
+                       add_block (offset);
+                       i = handlers.Length - 1;
+                       handlers [i].type = ILExceptionBlock.CATCH;
+                       handlers [i].start = offset;
+                       handlers [i].extype = extype;
+               }
+
+               internal void AddFinally (int offset)
+               {
+                       int i;
+                       End (offset);
+                       add_block (offset);
+                       i = handlers.Length - 1;
+                       handlers [i].type = ILExceptionBlock.FINALLY;
+                       handlers [i].start = offset;
+                       handlers [i].extype = null;
+               }
+
+               internal void AddFault (int offset)
+               {
+                       int i;
+                       End (offset);
+                       add_block (offset);
+                       i = handlers.Length - 1;
+                       handlers [i].type = ILExceptionBlock.FAULT;
+                       handlers [i].start = offset;
+                       handlers [i].extype = null;
+               }
+
+               internal void End (int offset)
+               {
+                       if (handlers == null)
+                               return;
+                       int i = handlers.Length - 1;
+                       if (i >= 0)
+                               handlers [i].len = offset - handlers [i].start;
+               }
+
+               internal int LastClauseType ()
+               {
+                       if (handlers != null)
+                               return handlers [handlers.Length-1].type;
+                       else
+                               return ILExceptionBlock.CATCH;
+               }
+
+               internal void Debug (int b)
+               {
+#if NO
+                       System.Console.WriteLine ("Handler {0} at {1}, len: {2}", b, start, len);
+                       for (int i = 0; i < handlers.Length; ++i)
+                               handlers [i].Debug ();
+#endif
+               }
+
+               void add_block (int offset)
+               {
+                       if (handlers != null) {
+                               int i = handlers.Length;
+                               ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
+                               System.Array.Copy (handlers, new_b, i);
+                               handlers = new_b;
+                               handlers [i].len = offset - handlers [i].start;
+                       } else {
+                               handlers = new ILExceptionBlock [1];
+                               len = offset - start;
+                       }
+               }
+       }
+       
+       internal struct ILTokenInfo {
+               public MemberInfo member;
+               public int code_pos;
+       }
+
+       internal interface TokenGenerator {
+               int GetToken (string str);
+
+               int GetToken (MemberInfo member);
+
+               int GetToken (MethodInfo method, Type[] opt_param_types);
+
+               int GetToken (SignatureHelper helper);
+       }               
+
        public class ILGenerator: Object {
+               private struct LabelFixup {
+                       public int offset;    // The number of bytes between pos and the
+                                                             // offset of the jump
+                       public int pos;       // Where offset of the label is placed
+                       public int label_idx; // The label to jump to
+               };
+               
+               struct LabelData {
+                       public LabelData (int addr, int maxStack)
+                       {
+                               this.addr = addr;
+                               this.maxStack = maxStack;
+                       }
+                       
+                       public int addr;
+                       public int maxStack; 
+               }
+               
+               static readonly Type void_type = typeof (void);
+               #region Sync with reflection.h
+               private byte[] code;
+               private int code_len;
+               private int max_stack;
+               private int cur_stack;
+               private LocalBuilder[] locals;
+               private ILExceptionInfo[] ex_handlers;
+               private int num_token_fixups;
+               private ILTokenInfo[] token_fixups;
+               #endregion
+               
+               private LabelData [] labels;
+               private int num_labels;
+               private LabelFixup[] fixups;
+               private int num_fixups;
+               internal Module module;
+               private Stack scopes;
+               private int cur_block;
+               private Stack open_blocks;
+               private TokenGenerator token_gen;
+               
+               const int defaultFixupSize = 8;
+               const int defaultLabelsSize = 8;
+
+               internal ILGenerator (Module m, TokenGenerator token_gen, int size)
+               {
+                       if (size < 0)
+                               size = 128;
+                       code_len = 0;
+                       code = new byte [size];
+                       cur_stack = max_stack = 0;
+                       num_fixups = num_labels = 0;
+                       token_fixups = new ILTokenInfo [8];
+                       num_token_fixups = 0;
+                       module = m;
+                       open_blocks = new Stack ();
+                       this.token_gen = token_gen;
+               }
+
+               private void add_token_fixup (MemberInfo mi)
+               {
+                       if (num_token_fixups == token_fixups.Length) {
+                               ILTokenInfo[] ntf = new ILTokenInfo [num_token_fixups * 2];
+                               token_fixups.CopyTo (ntf, 0);
+                               token_fixups = ntf;
+                       }
+                       token_fixups [num_token_fixups].member = mi;
+                       token_fixups [num_token_fixups++].code_pos = code_len;
+               }
+
+               private void make_room (int nbytes)
+               {
+                       if (code_len + nbytes < code.Length)
+                               return;
+                       byte[] new_code = new byte [(code_len + nbytes) * 2 + 128];
+                       System.Array.Copy (code, 0, new_code, 0, code.Length);
+                       code = new_code;
+               }
+
+               private void emit_int (int val)
+               {
+                       code [code_len++] = (byte) (val & 0xFF);
+                       code [code_len++] = (byte) ((val >> 8) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 16) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 24) & 0xFF);
+               }
+
+               /* change to pass by ref to avoid copy */
+               private void ll_emit (OpCode opcode)
+               {
+                       /* 
+                        * there is already enough room allocated in code.
+                        */
+                       // access op1 and op2 directly since the Value property is useless
+                       if (opcode.Size == 2)
+                               code [code_len++] = opcode.op1;
+                       code [code_len++] = opcode.op2;
+                       /*
+                        * We should probably keep track of stack needs here.
+                        * Or we may want to run the verifier on the code before saving it
+                        * (this may be needed anyway when the ILGenerator is not used...).
+                        */
+                       switch (opcode.StackBehaviourPush) {
+                       case StackBehaviour.Push1:
+                       case StackBehaviour.Pushi:
+                       case StackBehaviour.Pushi8:
+                       case StackBehaviour.Pushr4:
+                       case StackBehaviour.Pushr8:
+                       case StackBehaviour.Pushref:
+                       case StackBehaviour.Varpush: /* again we are conservative and assume it pushes 1 */
+                               cur_stack ++;
+                               break;
+                       case StackBehaviour.Push1_push1:
+                               cur_stack += 2;
+                               break;
+                       }
+                       if (max_stack < cur_stack)
+                               max_stack = cur_stack;
+
+                       /* 
+                        * Note that we adjust for the pop behaviour _after_ setting max_stack.
+                        */
+                       switch (opcode.StackBehaviourPop) {
+                       case StackBehaviour.Varpop:
+                               break; /* we are conservative and assume it doesn't decrease the stack needs */
+                       case StackBehaviour.Pop1:
+                       case StackBehaviour.Popi:
+                       case StackBehaviour.Popref:
+                               cur_stack --;
+                               break;
+                       case StackBehaviour.Pop1_pop1:
+                       case StackBehaviour.Popi_pop1:
+                       case StackBehaviour.Popi_popi:
+                       case StackBehaviour.Popi_popi8:
+                       case StackBehaviour.Popi_popr4:
+                       case StackBehaviour.Popi_popr8:
+                       case StackBehaviour.Popref_pop1:
+                       case StackBehaviour.Popref_popi:
+                               cur_stack -= 2;
+                               break;
+                       case StackBehaviour.Popi_popi_popi:
+                       case StackBehaviour.Popref_popi_popi:
+                       case StackBehaviour.Popref_popi_popi8:
+                       case StackBehaviour.Popref_popi_popr4:
+                       case StackBehaviour.Popref_popi_popr8:
+                       case StackBehaviour.Popref_popi_popref:
+                               cur_stack -= 3;
+                               break;
+                       }
+               }
+
+               private static int target_len (OpCode opcode)
+               {
+                       if (opcode.OperandType == OperandType.InlineBrTarget)
+                               return 4;
+                       return 1;
+               }
+
+               private void InternalEndClause ()
+               {
+                       switch (ex_handlers [cur_block].LastClauseType ()) {
+                       case ILExceptionBlock.CATCH:
+                               // how could we optimize code size here?
+                               Emit (OpCodes.Leave, ex_handlers [cur_block].end);
+                               break;
+                       case ILExceptionBlock.FAULT:
+                       case ILExceptionBlock.FINALLY:
+                               Emit (OpCodes.Endfinally);
+                               break;
+                       case ILExceptionBlock.FILTER:
+                               Emit (OpCodes.Endfilter);
+                               break;
+                       }
+               }
+
+               public virtual void BeginCatchBlock (Type exceptionType)
+               {
+                       if (open_blocks.Count <= 0)
+                               throw new NotSupportedException ("Not in an exception block");
+                       InternalEndClause ();
+                       ex_handlers [cur_block].AddCatch (exceptionType, code_len);
+                       cur_stack = 1; // the exception object is on the stack by default
+                       if (max_stack < cur_stack)
+                               max_stack = cur_stack;
+                       //System.Console.WriteLine ("Begin catch Block: {0} {1}",exceptionType.ToString(), max_stack);
+                       //throw new NotImplementedException ();
+               }
+
+               [MonoTODO]
+               public virtual void BeginExceptFilterBlock ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public virtual Label BeginExceptionBlock ()
+               {
+                       //System.Console.WriteLine ("Begin Block");
+                       
+                       if (ex_handlers != null) {
+                               cur_block = ex_handlers.Length;
+                               ILExceptionInfo[] new_ex = new ILExceptionInfo [cur_block + 1];
+                               System.Array.Copy (ex_handlers, new_ex, cur_block);
+                               ex_handlers = new_ex;
+                       } else {
+                               ex_handlers = new ILExceptionInfo [1];
+                               cur_block = 0;
+                       }
+                       open_blocks.Push (cur_block);
+                       ex_handlers [cur_block].start = code_len;
+                       return ex_handlers [cur_block].end = DefineLabel ();
+               }
+
+               public virtual void BeginFaultBlock()
+               {
+                       if (open_blocks.Count <= 0)
+                               throw new NotSupportedException ("Not in an exception block");
+                       //System.Console.WriteLine ("Begin fault Block");
+                       ex_handlers [cur_block].AddFault (code_len);
+               }
+               
+               public virtual void BeginFinallyBlock()
+               {
+                       if (open_blocks.Count <= 0)
+                               throw new NotSupportedException ("Not in an exception block");
+                       InternalEndClause ();
+                       //System.Console.WriteLine ("Begin finally Block");
+                       ex_handlers [cur_block].AddFinally (code_len);
+               }
+               
+               public virtual void BeginScope ()
+               { }
+               
+               public LocalBuilder DeclareLocal (Type localType)
+               {
+                       return DeclareLocal (localType, false);
+               }
+
+
+#if NET_2_0
+               public
+#else
+               internal
+#endif
+               LocalBuilder DeclareLocal (Type localType, bool pinned)
+               {
+                       LocalBuilder res = new LocalBuilder (localType, this);
+                       res.is_pinned = pinned;
+                       
+                       if (locals != null) {
+                               LocalBuilder[] new_l = new LocalBuilder [locals.Length + 1];
+                               System.Array.Copy (locals, new_l, locals.Length);
+                               new_l [locals.Length] = res;
+                               locals = new_l;
+                       } else {
+                               locals = new LocalBuilder [1];
+                               locals [0] = res;
+                       }
+                       res.position = (ushort)(locals.Length - 1);
+                       return res;
+               }
+               
+               public virtual Label DefineLabel ()
+               {
+                       if (labels == null)
+                               labels = new LabelData [defaultLabelsSize];
+                       else if (num_labels >= labels.Length) {
+                               LabelData [] t = new LabelData [labels.Length * 2];
+                               Array.Copy (labels, t, labels.Length);
+                               labels = t;
+                       }
+                       
+                       labels [num_labels] = new LabelData (-1, 0);
+                       
+                       return new Label (num_labels++);
+               }
+               
+               public virtual void Emit (OpCode opcode)
+               {
+                       make_room (2);
+                       ll_emit (opcode);
+               }
+               
+               public virtual void Emit (OpCode opcode, Byte val)
+               {
+                       make_room (3);
+                       ll_emit (opcode);
+                       code [code_len++] = val;
+               }
+               
+               public virtual void Emit (OpCode opcode, ConstructorInfo constructor)
+               {
+                       int token = token_gen.GetToken (constructor);
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (constructor.DeclaringType.Module == module)
+                               add_token_fixup (constructor);
+                       emit_int (token);
+                       
+                       if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
+                               cur_stack -= constructor.GetParameterCount ();
+               }
+               
+               public virtual void Emit (OpCode opcode, double val)
+               {
+                       Double.AssertEndianity (out val);
+
+                       byte[] s = System.BitConverter.GetBytes (val);
+                       make_room (10);
+                       ll_emit (opcode);
+                       if (BitConverter.IsLittleEndian){
+                               System.Array.Copy (s, 0, code, code_len, 8);
+                               code_len += 8;
+                       } else {
+                               code [code_len++] = s [7];
+                               code [code_len++] = s [6];
+                               code [code_len++] = s [5];
+                               code [code_len++] = s [4];
+                               code [code_len++] = s [3];
+                               code [code_len++] = s [2];
+                               code [code_len++] = s [1];
+                               code [code_len++] = s [0];                              
+                       }
+               }
+               
+               public virtual void Emit (OpCode opcode, FieldInfo field)
+               {
+                       int token = token_gen.GetToken (field);
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (field.DeclaringType.Module == module)
+                               add_token_fixup (field);
+                       emit_int (token);
+               }
+               
+               public virtual void Emit (OpCode opcode, Int16 val)
+               {
+                       make_room (4);
+                       ll_emit (opcode);
+                       code [code_len++] = (byte) (val & 0xFF);
+                       code [code_len++] = (byte) ((val >> 8) & 0xFF);
+               }
+               
+               public virtual void Emit (OpCode opcode, int val)
+               {
+                       make_room (6);
+                       ll_emit (opcode);
+                       emit_int (val);
+               }
+               
+               public virtual void Emit (OpCode opcode, long val)
+               {
+                       make_room (10);
+                       ll_emit (opcode);
+                       code [code_len++] = (byte) (val & 0xFF);
+                       code [code_len++] = (byte) ((val >> 8) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 16) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 24) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 32) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 40) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 48) & 0xFF);
+                       code [code_len++] = (byte) ((val >> 56) & 0xFF);
+               }
+               
+               public virtual void Emit (OpCode opcode, Label label)
+               {
+                       int tlen = target_len (opcode);
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (cur_stack > labels [label.label].maxStack)
+                               labels [label.label].maxStack = cur_stack;
+                       
+                       if (fixups == null)
+                               fixups = new LabelFixup [defaultFixupSize]; 
+                       else if (num_fixups >= fixups.Length) {
+                               LabelFixup[] newf = new LabelFixup [fixups.Length + 16];
+                               System.Array.Copy (fixups, newf, fixups.Length);
+                               fixups = newf;
+                       }
+                       fixups [num_fixups].offset = tlen;
+                       fixups [num_fixups].pos = code_len;
+                       fixups [num_fixups].label_idx = label.label;
+                       num_fixups++;
+                       code_len += tlen;
+
+               }
+               
+               public virtual void Emit (OpCode opcode, Label[] labels)
+               {
+                       /* opcode needs to be switch. */
+                       int count = labels.Length;
+                       make_room (6 + count * 4);
+                       ll_emit (opcode);
+
+                       for (int i = 0; i < count; ++i)
+                               if (cur_stack > this.labels [labels [i].label].maxStack)
+                                       this.labels [labels [i].label].maxStack = cur_stack;
+
+                       emit_int (count);
+                       if (fixups == null)
+                               fixups = new LabelFixup [defaultFixupSize + count]; 
+                       else if (num_fixups + count >= fixups.Length) {
+                               LabelFixup[] newf = new LabelFixup [fixups.Length + count + 16];
+                               System.Array.Copy (fixups, newf, fixups.Length);
+                               fixups = newf;
+                       }
+                       
+                       // ECMA 335, Partition III, p94 (7-10)
+                       //
+                       // The switch instruction implements a jump table. The format of 
+                       // the instruction is an unsigned int32 representing the number of targets N,
+                       // followed by N int32 values specifying jump targets: these targets are
+                       // represented as offsets (positive or negative) from the beginning of the 
+                       // instruction following this switch instruction.
+                       //
+                       // We must make sure it gets an offset from the *end* of the last label
+                       // (eg, the beginning of the instruction following this).
+                       //
+                       // remaining is the number of bytes from the current instruction to the
+                       // instruction that will be emitted.
+                       
+                       for (int i = 0, remaining = count * 4; i < count; ++i, remaining -= 4) {
+                               fixups [num_fixups].offset = remaining;
+                               fixups [num_fixups].pos = code_len;
+                               fixups [num_fixups].label_idx = labels [i].label;
+                               num_fixups++;
+                               code_len += 4;
+                       }
+               }
+
+               public virtual void Emit (OpCode opcode, LocalBuilder lbuilder)
+               {
+                       uint pos = lbuilder.position;
+                       bool load_addr = false;
+                       bool is_store = false;
+                       make_room (6);
+
+                       if (lbuilder.ilgen != this)
+                               throw new Exception ("Trying to emit a local from a different ILGenerator.");
+
+                       /* inline the code from ll_emit () to optimize il code size */
+                       if (opcode.StackBehaviourPop == StackBehaviour.Pop1) {
+                               cur_stack --;
+                               is_store = true;
+                       } else {
+                               cur_stack++;
+                               if (cur_stack > max_stack)
+                                       max_stack = cur_stack;
+                               load_addr = opcode.StackBehaviourPush == StackBehaviour.Pushi;
+                       }
+                       if (load_addr) {
+                               if (pos < 256) {
+                                       code [code_len++] = (byte)0x12;
+                                       code [code_len++] = (byte)pos;
+                               } else {
+                                       code [code_len++] = (byte)0xfe;
+                                       code [code_len++] = (byte)0x0d;
+                                       code [code_len++] = (byte)(pos & 0xff);
+                                       code [code_len++] = (byte)((pos >> 8) & 0xff);
+                               }
+                       } else {
+                               if (is_store) {
+                                       if (pos < 4) {
+                                               code [code_len++] = (byte)(0x0a + pos);
+                                       } else if (pos < 256) {
+                                               code [code_len++] = (byte)0x13;
+                                               code [code_len++] = (byte)pos;
+                                       } else {
+                                               code [code_len++] = (byte)0xfe;
+                                               code [code_len++] = (byte)0x0e;
+                                               code [code_len++] = (byte)(pos & 0xff);
+                                               code [code_len++] = (byte)((pos >> 8) & 0xff);
+                                       }
+                               } else {
+                                       if (pos < 4) {
+                                               code [code_len++] = (byte)(0x06 + pos);
+                                       } else if (pos < 256) {
+                                               code [code_len++] = (byte)0x11;
+                                               code [code_len++] = (byte)pos;
+                                       } else {
+                                               code [code_len++] = (byte)0xfe;
+                                               code [code_len++] = (byte)0x0c;
+                                               code [code_len++] = (byte)(pos & 0xff);
+                                               code [code_len++] = (byte)((pos >> 8) & 0xff);
+                                       }
+                               }
+                       }
+               }
+
+               public virtual void Emit (OpCode opcode, MethodInfo method)
+               {
+                       if (method == null)
+                               throw new ArgumentNullException ("method");
+
+                       int token = token_gen.GetToken (method);
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (method.DeclaringType.Module == module)
+                               add_token_fixup (method);
+                       emit_int (token);
+                       if (method.ReturnType != void_type)
+                               cur_stack ++;
+
+                       if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
+                               cur_stack -= method.GetParameterCount ();
+               }
+
+               private void Emit (OpCode opcode, MethodInfo method, int token)
+               {
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (method.DeclaringType.Module == module)
+                               add_token_fixup (method);
+                       emit_int (token);
+                       if (method.ReturnType != void_type)
+                               cur_stack ++;
+
+                       if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
+                               cur_stack -= method.GetParameterCount ();
+               }
+
+               [CLSCompliant(false)]
+               public void Emit (OpCode opcode, sbyte val)
+               {
+                       make_room (3);
+                       ll_emit (opcode);
+                       code [code_len++] = (byte)val;
+               }
+
+               public virtual void Emit (OpCode opcode, SignatureHelper shelper)
+               {
+                       int token = token_gen.GetToken (shelper);
+                       make_room (6);
+                       ll_emit (opcode);
+                       emit_int (token);
+               }
+
+               public virtual void Emit (OpCode opcode, float val)
+               {
+                       byte[] s = System.BitConverter.GetBytes (val);
+                       make_room (6);
+                       ll_emit (opcode);
+                       if (BitConverter.IsLittleEndian){
+                               System.Array.Copy (s, 0, code, code_len, 4);
+                               code_len += 4;
+                       } else {
+                               code [code_len++] = s [3];
+                               code [code_len++] = s [2];
+                               code [code_len++] = s [1];
+                               code [code_len++] = s [0];                              
+                       }
+               }
+
+               public virtual void Emit (OpCode opcode, string val)
+               {
+                       int token = token_gen.GetToken (val);
+                       make_room (6);
+                       ll_emit (opcode);
+                       emit_int (token);
+               }
+
+               public virtual void Emit (OpCode opcode, Type type)
+               {
+                       make_room (6);
+                       ll_emit (opcode);
+                       emit_int (token_gen.GetToken (type));
+               }
+
+               [MonoTODO ("Do something about varargs method")]
+               public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes)
+               {
+                       if (methodinfo == null)
+                               throw new ArgumentNullException ("methodinfo can not be null");
+                       short value = opcode.Value;
+                       if (!(value == OpCodes.Call.Value || value == OpCodes.Callvirt.Value))
+                               throw new NotSupportedException ("Only Call and CallVirt are allowed");
+                       if (optionalParamTypes != null){
+                               if ((methodinfo.CallingConvention & CallingConventions.VarArgs)  == 0){
+                                       throw new InvalidOperationException ("Method is not VarArgs method and optional types were passed");
+                               }
+
+                               int token = token_gen.GetToken (methodinfo, optionalParamTypes);
+                               Emit (opcode, methodinfo, token);
+                               return;
+                       }
+                       Emit (opcode, methodinfo);
+               }
+
+               public void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] paramTypes)
+               {
+                       SignatureHelper helper 
+                               = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, paramTypes);
+                       Emit (opcode, helper);
+               }
+
+               public void EmitCalli (OpCode opcode, CallingConventions callConv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes)
+               {
+                       if (optionalParamTypes != null)
+                               throw new NotImplementedException ();
+
+                       SignatureHelper helper 
+                               = SignatureHelper.GetMethodSigHelper (module, callConv, 0, returnType, paramTypes);
+                       Emit (opcode, helper);
+               }
+               
+               public virtual void EmitWriteLine (FieldInfo field)
+               {
+                       if (field == null)
+                               throw new ArgumentNullException ("field");
+                       
+                       // The MS implementation does not check for valuetypes here but it
+                       // should. Also, it should check that if the field is not static,
+                       // then it is a member of this type.
+                       if (field.IsStatic)
+                               Emit (OpCodes.Ldsfld, field);
+                       else {
+                               Emit (OpCodes.Ldarg_0);
+                               Emit (OpCodes.Ldfld, field);
+                       }
+                       Emit (OpCodes.Call, 
+                             typeof (Console).GetMethod ("WriteLine",
+                                                         new Type[1] { field.FieldType }));
+               }
+
+               public virtual void EmitWriteLine (LocalBuilder lbuilder)
+               {
+                       if (lbuilder == null)
+                               throw new ArgumentNullException ("lbuilder");
+                       if (lbuilder.LocalType is TypeBuilder)
+                               throw new  ArgumentException ("Output streams do not support TypeBuilders.");
+                       // The MS implementation does not check for valuetypes here but it
+                       // should.
+                       Emit (OpCodes.Ldloc, lbuilder);
+                       Emit (OpCodes.Call, 
+                             typeof (Console).GetMethod ("WriteLine",
+                                                         new Type[1] { lbuilder.LocalType }));
+               }
+               
+               public virtual void EmitWriteLine (string val)
+               {
+                       Emit (OpCodes.Ldstr, val);
+                       Emit (OpCodes.Call, 
+                             typeof (Console).GetMethod ("WriteLine",
+                                                         new Type[1] { typeof(string)}));
+               }
+
+               public virtual void EndExceptionBlock ()
+               {
+                       if (open_blocks.Count <= 0)
+                               throw new NotSupportedException ("Not in an exception block");
+                       InternalEndClause ();
+                       MarkLabel (ex_handlers [cur_block].end);
+                       ex_handlers [cur_block].End (code_len);
+                       ex_handlers [cur_block].Debug (cur_block);
+                       //System.Console.WriteLine ("End Block {0} (handlers: {1})", cur_block, ex_handlers [cur_block].NumHandlers ());
+                       open_blocks.Pop ();
+                       if (open_blocks.Count > 0)
+                               cur_block = (int)open_blocks.Peek ();
+                       //Console.WriteLine ("curblock restored to {0}", cur_block);
+                       //throw new NotImplementedException ();
+               }
+
+               public virtual void EndScope ()
+               { }
+
+               public virtual void MarkLabel (Label loc)
+               {
+                       if (loc.label < 0 || loc.label >= num_labels)
+                               throw new System.ArgumentException ("The label is not valid");
+                       if (labels [loc.label].addr >= 0)
+                               throw new System.ArgumentException ("The label was already defined");
+                       labels [loc.label].addr = code_len;
+                       if (labels [loc.label].maxStack > cur_stack)
+                               cur_stack = labels [loc.label].maxStack;
+               }
+
+               public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine,
+                                                      int startColumn, int endLine, int endColumn)
+               { }
+
+               public virtual void ThrowException (Type exceptionType)
+               {
+                       if (exceptionType == null)
+                               throw new ArgumentNullException ("exceptionType");
+                       if (! ((exceptionType == typeof (Exception)) || 
+                                  exceptionType.IsSubclassOf (typeof (Exception))))
+                               throw new ArgumentException ("Type should be an exception type", "exceptionType");
+                       ConstructorInfo ctor = exceptionType.GetConstructor (new Type[0]);
+                       if (ctor == null)
+                               throw new ArgumentException ("Type should have a default constructor", "exceptionType");
+                       Emit (OpCodes.Newobj, ctor);
+                       Emit (OpCodes.Throw);
+               }
+
+               [MonoTODO]
+               public void UsingNamespace (String usingNamespace)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               internal void label_fixup ()
+               {
+                       for (int i = 0; i < num_fixups; ++i) {
+                               
+                               // Diff is the offset from the end of the jump instruction to the address of the label
+                               int diff = labels [fixups [i].label_idx].addr - (fixups [i].pos + fixups [i].offset);
+                               if (fixups [i].offset == 1) {
+                                       code [fixups [i].pos] = (byte)((sbyte) diff);
+                               } else {
+                                       int old_cl = code_len;
+                                       code_len = fixups [i].pos;
+                                       emit_int (diff);
+                                       code_len = old_cl;
+                               }
+                       }
+               }
 
-               public virtual void BeginCatchBlock (Type exceptionType) {}
-               public virtual void BeginExceptFilterBlock () {}
-               public virtual void BeginExceptionBlock () {}
-               public virtual void BeginFaultBlock() {}
-               public virtual void BeginFinallyBlock() {}
-               public virtual void BeginScope () {}
-               public virtual void DeclareLocal (Type localType) {}
-               public virtual Label DefineLabel () {return new Label ();}
-               public virtual void Emit (OpCode opcode) {}
-               public virtual void Emit (OpCode opcode, Byte val) {}
-               public virtual void Emit (OpCode opcode, ConstructorInfo contructor) {}
-               public virtual void Emit (OpCode opcode, Double val) {}
-               public virtual void Emit (OpCode opcode, FieldInfo field) {}
-               public virtual void Emit (OpCode opcode, Int16 val) {}
-               public virtual void Emit (OpCode opcode, Int32 val) {}
-               public virtual void Emit (OpCode opcode, Int64 val) {}
-               public virtual void Emit (OpCode opcode, Label label) {}
-               public virtual void Emit (OpCode opcode, Label[] labels) {}
-               public virtual void Emit (OpCode opcode, LocalBuilder lbuilder) {}
-               public virtual void Emit (OpCode opcode, MethodInfo method) {}
-               public virtual void Emit (OpCode opcode, sbyte val) {}
-               public virtual void Emit (OpCode opcode, SignatureHelper shelper) {}
-               public virtual void Emit (OpCode opcode, float val) {}
-               public virtual void Emit (OpCode opcode, string val) {}
-               public virtual void Emit (OpCode opcode, Type type) {}
-
-               public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes) {}
-               public void EmitCalli (OpCode opcode, CallingConventions call_conv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes) {}
-
-               public virtual void EmitWriteLine (FieldInfo field) {}
-               public virtual void EmitWriteLine (LocalBuilder lbuilder) {}
-               public virtual void EmitWriteLine (string val) {}
-
-               public virtual void EndExceptionBlock () {}
-               public virtual void EndScope () {}
-               public virtual void MarkLabel (Label loc) {}
-               public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int EndColumn) {}
-               public virtual void ThrowException (Type exceptionType) {}
-               public virtual void UsingNamespace (String usingNamespace) {}
+               internal static int Mono_GetCurrentOffset (ILGenerator ig)
+               {
+                       return ig.code_len;
+               }
        }
 }