+//
+// 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 int filter_offset;
internal void Debug () {
- System.Console.Write ("\ttype="+type.ToString()+" start="+start.ToString());
- System.Console.WriteLine (" len="+len.ToString()+" extype="+extype.ToString());
+#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 {
int len;
internal Label end;
- internal void AddCatch (Type extype, int offset) {
+ 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].extype = extype;
}
- internal void End (int offset) {
+ 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;
- handlers [i].len = offset - handlers [i].start;
+ if (i >= 0)
+ handlers [i].len = offset - handlers [i].start;
}
- internal void Debug () {
- System.Console.WriteLine ("Handler at "+start.ToString()+ " len: "+len.ToString());
+ 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) {
+ void add_block (int offset)
+ {
if (handlers != null) {
int i = handlers.Length;
ILExceptionBlock[] new_b = new ILExceptionBlock [i + 1];
}
}
+ 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 size;
- public int pos;
- public int label_idx;
+ 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 MethodBase mbuilder; /* a MethodBuilder or ConstructorBuilder */
private int code_len;
private int max_stack;
private int cur_stack;
private LocalBuilder[] locals;
private ILExceptionInfo[] ex_handlers;
- private int[] label_to_addr;
+ private int num_token_fixups;
+ private ILTokenInfo[] token_fixups;
+ #endregion
+
+ private LabelData [] labels;
private int num_labels;
private LabelFixup[] fixups;
private int num_fixups;
- private AssemblyBuilder abuilder;
+ 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 (MethodBase mb, int size) {
+ internal ILGenerator (Module m, TokenGenerator token_gen, int size)
+ {
if (size < 0)
- size = 256;
+ size = 128;
code_len = 0;
code = new byte [size];
- mbuilder = mb;
cur_stack = max_stack = 0;
num_fixups = num_labels = 0;
- cur_block = -1;
- label_to_addr = new int [16];
- fixups = new LabelFixup [16];
- if (mb is MethodBuilder) {
- abuilder = (AssemblyBuilder)((MethodBuilder)mb).TypeBuilder.Module.Assembly;
- } else if (mb is ConstructorBuilder) {
- abuilder = (AssemblyBuilder)((ConstructorBuilder)mb).TypeBuilder.Module.Assembly;
+ 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) {
+ private void make_room (int nbytes)
+ {
if (code_len + nbytes < code.Length)
return;
- byte[] new_code = new byte [code.Length + 128];
- System.Array.Copy (code, new_code, code.Length);
+ 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) {
+
+ 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) {
+ private void ll_emit (OpCode opcode)
+ {
/*
* there is already enough room allocated in code.
*/
}
if (max_stack < cur_stack)
max_stack = cur_stack;
+
/*
* Note that we adjust for the pop behaviour _after_ setting max_stack.
*/
}
}
- private static int target_len (OpCode opcode) {
- if (opcode.operandType == OperandType.InlineBrTarget)
+ private static int target_len (OpCode opcode)
+ {
+ if (opcode.OperandType == OperandType.InlineBrTarget)
return 4;
return 1;
}
- public virtual void BeginCatchBlock (Type exceptionType) {
- if (cur_block < 0)
+ 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");
- // how could we optimize code size here?
- Emit (OpCodes.Leave, ex_handlers [cur_block].end);
+ InternalEndClause ();
ex_handlers [cur_block].AddCatch (exceptionType, code_len);
- System.Console.WriteLine ("Begin catch Block: "+exceptionType.ToString());
+ 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 ();
}
- public virtual void BeginExceptFilterBlock () {
+
+ [MonoTODO]
+ public virtual void BeginExceptFilterBlock ()
+ {
throw new NotImplementedException ();
}
- public virtual Label BeginExceptionBlock () {
- System.Console.WriteLine ("Begin Block");
+
+ public virtual Label BeginExceptionBlock ()
+ {
+ //System.Console.WriteLine ("Begin Block");
- ++ cur_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 (cur_block < 0)
+
+ public virtual void BeginFaultBlock()
+ {
+ if (open_blocks.Count <= 0)
throw new NotSupportedException ("Not in an exception block");
- System.Console.WriteLine ("Begin fault Block");
- //throw new NotImplementedException ();
+ //System.Console.WriteLine ("Begin fault Block");
+ ex_handlers [cur_block].AddFault (code_len);
}
- public virtual void BeginFinallyBlock() {
- if (cur_block < 0)
+
+ public virtual void BeginFinallyBlock()
+ {
+ if (open_blocks.Count <= 0)
throw new NotSupportedException ("Not in an exception block");
- System.Console.WriteLine ("Begin finally Block");
- //throw new NotImplementedException ();
+ InternalEndClause ();
+ //System.Console.WriteLine ("Begin finally Block");
+ ex_handlers [cur_block].AddFinally (code_len);
}
- public virtual void BeginScope () {
- throw new NotImplementedException ();
+
+ public virtual void BeginScope ()
+ { }
+
+ public LocalBuilder DeclareLocal (Type localType)
+ {
+ return DeclareLocal (localType, false);
}
- public virtual LocalBuilder DeclareLocal (Type localType) {
- LocalBuilder res = new LocalBuilder (localType);
+
+
+#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);
locals = new LocalBuilder [1];
locals [0] = res;
}
- res.position = locals.Length - 1;
+ res.position = (ushort)(locals.Length - 1);
return res;
}
- public virtual Label DefineLabel () {
- if (num_labels >= label_to_addr.Length) {
- int[] new_l = new int [label_to_addr.Length + 16];
- System.Array.Copy (label_to_addr, new_l, label_to_addr.Length);
- label_to_addr = new_l;
+
+ 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;
}
- label_to_addr [num_labels] = -1;
+
+ labels [num_labels] = new LabelData (-1, 0);
+
return new Label (num_labels++);
}
- public virtual void Emit (OpCode opcode) {
+
+ public virtual void Emit (OpCode opcode)
+ {
make_room (2);
ll_emit (opcode);
}
- public virtual void Emit (OpCode opcode, Byte val) {
+
+ 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 = abuilder.GetToken (constructor);
+
+ 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) {
+
+ public virtual void Emit (OpCode opcode, double val)
+ {
+ Double.AssertEndianity (out val);
+
byte[] s = System.BitConverter.GetBytes (val);
make_room (10);
ll_emit (opcode);
- System.Array.Copy (s, 0, code, code_len, 8);
- code_len += 8;
+ 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 = abuilder.GetToken (field);
+
+ 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) {
+
+ 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, Int32 val) {
+
+ public virtual void Emit (OpCode opcode, int val)
+ {
make_room (6);
ll_emit (opcode);
emit_int (val);
}
- public virtual void Emit (OpCode opcode, Int64 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 >> 48) & 0xFF);
code [code_len++] = (byte) ((val >> 56) & 0xFF);
}
- public virtual void Emit (OpCode opcode, Label label) {
+
+ public virtual void Emit (OpCode opcode, Label label)
+ {
int tlen = target_len (opcode);
make_room (6);
ll_emit (opcode);
- if (num_fixups >= fixups.Length) {
+ 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].size = tlen;
+ 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) {
+
+ 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 (num_fixups + count >= fixups.Length) {
+ 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;
}
- for (int i = 0; i < count; ++i) {
- fixups [num_fixups].size = 4;
+
+ // 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) {
+
+ public virtual void Emit (OpCode opcode, LocalBuilder lbuilder)
+ {
+ uint pos = lbuilder.position;
+ bool load_addr = false;
+ bool is_store = false;
make_room (6);
- ll_emit (opcode);
- code [code_len++] = (byte) (lbuilder.position & 0xFF);
- if (opcode.operandType == OperandType.InlineVar) {
- code [code_len++] = (byte) ((lbuilder.position >> 8) & 0xFF);
+
+ 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 ();
}
- public virtual void Emit (OpCode opcode, MethodInfo method) {
- int token = abuilder.GetToken (method);
+
+ 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 virtual void Emit (OpCode opcode, sbyte val) {
+ public void Emit (OpCode opcode, sbyte val)
+ {
make_room (3);
ll_emit (opcode);
code [code_len++] = (byte)val;
}
- [MonoTODO]
- public virtual void Emit (OpCode opcode, SignatureHelper shelper) {
- int token = 0; // FIXME: request a token from the modulebuilder
+ 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) {
+
+ public virtual void Emit (OpCode opcode, float val)
+ {
byte[] s = System.BitConverter.GetBytes (val);
make_room (6);
ll_emit (opcode);
- System.Array.Copy (s, 0, code, code_len, 4);
- code_len += 4;
+ 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 = abuilder.GetToken (val);
- make_room (3);
+
+ 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) {
+
+ public virtual void Emit (OpCode opcode, Type type)
+ {
make_room (6);
ll_emit (opcode);
- emit_int (abuilder.GetToken (type));
+ emit_int (token_gen.GetToken (type));
}
- public void EmitCall (OpCode opcode, MethodInfo methodinfo, Type[] optionalParamTypes) {
- throw new NotImplementedException ();
+ [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, CallingConventions call_conv, Type returnType, Type[] paramTypes, Type[] optionalParamTypes) {
- throw new NotImplementedException ();
+
+ public void EmitCalli (OpCode opcode, CallingConvention unmanagedCallConv, Type returnType, Type[] paramTypes)
+ {
+ SignatureHelper helper
+ = SignatureHelper.GetMethodSigHelper (module, 0, unmanagedCallConv, returnType, paramTypes);
+ Emit (opcode, helper);
}
- public virtual void EmitWriteLine (FieldInfo field) {
- throw new NotImplementedException ();
+ 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 (LocalBuilder lbuilder) {
- throw new NotImplementedException ();
+
+ 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 (string val) {
- throw new NotImplementedException ();
+
+ 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 (cur_block < 0)
+ public virtual void EndExceptionBlock ()
+ {
+ if (open_blocks.Count <= 0)
throw new NotSupportedException ("Not in an exception block");
- // how could we optimize code size here?
- Emit (OpCodes.Leave, ex_handlers [cur_block].end);
+ InternalEndClause ();
MarkLabel (ex_handlers [cur_block].end);
ex_handlers [cur_block].End (code_len);
- ex_handlers [cur_block].Debug ();
- System.Console.WriteLine ("End Block");
+ 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 () {
- throw new NotImplementedException ();
- }
- public virtual void MarkLabel (Label loc) {
+
+ 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 (label_to_addr [loc.label] >= 0)
+ if (labels [loc.label].addr >= 0)
throw new System.ArgumentException ("The label was already defined");
- label_to_addr [loc.label] = code_len;
- }
- public virtual void MarkSequencePoint (ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int EndColumn) {
- throw new NotImplementedException ();
+ labels [loc.label].addr = code_len;
+ if (labels [loc.label].maxStack > cur_stack)
+ cur_stack = labels [loc.label].maxStack;
}
- public virtual void ThrowException (Type exceptionType) {
- throw new NotImplementedException ();
+
+ 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);
}
- public virtual void UsingNamespace (String usingNamespace) {
+
+ [MonoTODO]
+ public void UsingNamespace (String usingNamespace)
+ {
throw new NotImplementedException ();
}
- internal void label_fixup () {
- int i;
- for (i = 0; i < num_fixups; ++i) {
- int diff = label_to_addr [fixups [i].label_idx] - fixups [i].pos;
- if (fixups [i].size == 1) {
- code [fixups [i].pos] = (byte)((sbyte) diff - 1);
+ 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 - 4);
+ emit_int (diff);
code_len = old_cl;
}
}
}
+
+ internal static int Mono_GetCurrentOffset (ILGenerator ig)
+ {
+ return ig.code_len;
+ }
}
}