+//
+// 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.Collections;
using System.Diagnostics.SymbolStore;
using System.Runtime.InteropServices;
-using Mono.CSharp.Debugger;
namespace System.Reflection.Emit {
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)
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; // the location of the fixup
- public int label_base; // the base address for this fixup
- 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
};
- static Type void_type = typeof (void);
+
+ 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 ILExceptionInfo[] ex_handlers;
private int num_token_fixups;
private ILTokenInfo[] token_fixups;
- private int[] label_to_addr;
- private int[] label_to_max_stack;
+ #endregion
+
+ private LabelData [] labels;
private int num_labels;
private LabelFixup[] fixups;
private int num_fixups;
- private ModuleBuilder module;
- private AssemblyBuilder abuilder;
- private IMonoSymbolWriter sym_writer;
+ 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 = 128;
code_len = 0;
code = new byte [size];
- mbuilder = mb;
cur_stack = max_stack = 0;
num_fixups = num_labels = 0;
- label_to_addr = new int [8];
- label_to_max_stack = new int [8];
- fixups = new LabelFixup [8];
token_fixups = new ILTokenInfo [8];
num_token_fixups = 0;
- if (mb is MethodBuilder) {
- module = (ModuleBuilder)((MethodBuilder)mb).TypeBuilder.Module;
- } else if (mb is ConstructorBuilder) {
- module = (ModuleBuilder)((ConstructorBuilder)mb).TypeBuilder.Module;
- }
- abuilder = (AssemblyBuilder)module.Assembly;
- sym_writer = module.symbol_writer;
+ module = m;
open_blocks = new Stack ();
+ this.token_gen = token_gen;
}
private void add_token_fixup (MemberInfo mi)
if (open_blocks.Count <= 0)
throw new NotSupportedException ("Not in an exception block");
//System.Console.WriteLine ("Begin fault Block");
- //throw new NotImplementedException ();
+ ex_handlers [cur_block].AddFault (code_len);
}
public virtual void BeginFinallyBlock()
}
public virtual void BeginScope ()
- {
- if (sym_writer != null) {
- if (scopes == null)
- scopes = new Stack ();
- scopes.Push (sym_writer.OpenScope (code_len));
- }
- }
+ { }
public LocalBuilder DeclareLocal (Type localType)
{
- LocalBuilder res = new LocalBuilder (module, localType, this);
+ 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);
locals = new LocalBuilder [1];
locals [0] = res;
}
- res.position = (uint)(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 * 2];
- System.Array.Copy (label_to_addr, new_l, label_to_addr.Length);
- int[] new_s = new int [label_to_addr.Length * 2];
- System.Array.Copy (label_to_max_stack, new_s, label_to_addr.Length);
- label_to_addr = new_l;
- label_to_max_stack = new_s;
+ 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;
- label_to_max_stack [num_labels] = 0;
+
+ labels [num_labels] = new LabelData (-1, 0);
+
return new Label (num_labels++);
}
public virtual void Emit (OpCode opcode, ConstructorInfo constructor)
{
- int token = abuilder.GetToken (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);
- ParameterInfo[] mparams = constructor.GetParameters();
- if ((opcode.StackBehaviourPop == StackBehaviour.Varpop) && (mparams != null))
- cur_stack -= mparams.Length;
+
+ if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
+ cur_stack -= constructor.GetParameterCount ();
}
public virtual void Emit (OpCode opcode, double val)
public virtual void Emit (OpCode opcode, FieldInfo field)
{
- int token = abuilder.GetToken (field);
+ int token = token_gen.GetToken (field);
make_room (6);
ll_emit (opcode);
if (field.DeclaringType.Module == module)
int tlen = target_len (opcode);
make_room (6);
ll_emit (opcode);
- if (cur_stack > label_to_max_stack [label.label])
- label_to_max_stack [label.label] = cur_stack;
- 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_base = code_len;
fixups [num_fixups].label_idx = label.label;
num_fixups++;
code_len += tlen;
ll_emit (opcode);
for (int i = 0; i < count; ++i)
- if (cur_stack > label_to_max_stack [labels [i].label])
- label_to_max_stack [labels [i].label] = cur_stack;
+ if (cur_stack > this.labels [labels [i].label].maxStack)
+ this.labels [labels [i].label].maxStack = cur_stack;
- int switch_base = code_len + count*4;
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_base = switch_base;
fixups [num_fixups].label_idx = labels [i].label;
num_fixups++;
code_len += 4;
if (method == null)
throw new ArgumentNullException ("method");
- int token = abuilder.GetToken (method);
+ int token = token_gen.GetToken (method);
make_room (6);
ll_emit (opcode);
if (method.DeclaringType.Module == module)
emit_int (token);
if (method.ReturnType != void_type)
cur_stack ++;
- ParameterInfo[] mparams = method.GetParameters();
- if ((opcode.StackBehaviourPop == StackBehaviour.Varpop) && (mparams != null))
- cur_stack -= mparams.Length;
+
+ 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 virtual void Emit (OpCode opcode, SignatureHelper shelper)
{
- int token = abuilder.GetToken (shelper);
+ int token = token_gen.GetToken (shelper);
make_room (6);
ll_emit (opcode);
emit_int (token);
public virtual void Emit (OpCode opcode, string val)
{
- int token = abuilder.GetToken (val);
+ int token = token_gen.GetToken (val);
make_room (6);
ll_emit (opcode);
emit_int (token);
{
make_room (6);
ll_emit (opcode);
- emit_int (abuilder.GetToken (type));
+ emit_int (token_gen.GetToken (type));
}
[MonoTODO ("Do something about varargs method")]
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);
}
Emit (OpCodes.Ldfld, field);
}
Emit (OpCodes.Call,
- typeof (Console).GetMethod ("WriteLine",
- new Type[1] { field.FieldType }));
+ typeof (Console).GetMethod ("WriteLine",
+ new Type[1] { field.FieldType }));
}
public virtual void EmitWriteLine (LocalBuilder lbuilder)
// should.
Emit (OpCodes.Ldloc, lbuilder);
Emit (OpCodes.Call,
- typeof (Console).GetMethod ("WriteLine",
- new Type[1] { lbuilder.LocalType }));
+ 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)}));
+ typeof (Console).GetMethod ("WriteLine",
+ new Type[1] { typeof(string)}));
}
public virtual void EndExceptionBlock ()
}
public virtual void EndScope ()
- {
- if (sym_writer != null) {
- sym_writer.CloseScope (code_len);
- if (scopes == null)
- throw new InvalidOperationException ();
- scopes.Pop ();
- }
- }
+ { }
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;
- if (label_to_max_stack [loc.label] > cur_stack)
- cur_stack = label_to_max_stack [loc.label];
+ 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)
- {
- if (sym_writer == null)
- return;
-
- sym_writer.MarkSequencePoint (code_len, startLine, startColumn);
- }
+ { }
public virtual void ThrowException (Type exceptionType)
{
internal void label_fixup ()
{
- int i;
- for (i = 0; i < num_fixups; ++i) {
- int diff = label_to_addr [fixups [i].label_idx] - fixups [i].label_base;
- if (fixups [i].size == 1) {
- code [fixups [i].pos] = (byte)((sbyte) diff - 1);
+ 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;
+ }
}
}