public class MethodDef {
- protected class LabelInfo : IComparable {
-
- public readonly string Name;
- public readonly int Pos;
- public PEAPI.CILLabel Label;
-
- public LabelInfo (string name, int pos)
- {
- Name = name;
- Pos = pos;
- Label = null;
- }
-
- public void Define (PEAPI.CILLabel label)
- {
- Label = label;
- }
-
- public int CompareTo (object obj)
- {
- LabelInfo other = obj as LabelInfo;
-
- if(other != null)
- return Pos.CompareTo(other.Pos);
-
- throw new ArgumentException ("object is not a LabelInfo");
- }
+ protected class GenericInfo {
+ public string Id;
+ public ArrayList ConstraintList;
}
private PEAPI.MethAttr meth_attr;
private PEAPI.ImplAttr impl_attr;
private string name;
private string signature;
+ private Hashtable vararg_sig_table;
private ITypeRef ret_type;
+ private ArrayList typar_list;
private ArrayList param_list;
private Hashtable named_param_table;
private ArrayList inst_list;
private ArrayList customattr_list;
private Hashtable label_table;
+ private Hashtable labelref_table;
+ private ArrayList label_list;
private PEAPI.MethodDef methoddef;
private bool entry_point;
+ private bool zero_init;
private bool is_resolved;
private bool is_defined;
private ArrayList local_list;
private Hashtable named_local_table;
private bool init_locals;
private int max_stack;
- private Random label_random;
-
- public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
- PEAPI.ImplAttr impl_attr, string name,
- ITypeRef ret_type, ArrayList param_list)
+ private bool pinvoke_info;
+ private ExternModule pinvoke_mod;
+ private string pinvoke_name;
+ private PEAPI.PInvokeAttr pinvoke_attr;
+ private SourceMethod source;
+
+ public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
+ PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
+ string name, ITypeRef ret_type, ArrayList param_list,
+ Location start)
{
this.meth_attr = meth_attr;
this.call_conv = call_conv;
inst_list = new ArrayList ();
customattr_list = new ArrayList ();
label_table = new Hashtable ();
+ labelref_table = new Hashtable ();
+ label_list = new ArrayList ();
local_list = new ArrayList ();
named_local_table = new Hashtable ();
named_param_table = new Hashtable ();
- label_random = new Random ();
+
entry_point = false;
+ zero_init = false;
init_locals = false;
max_stack = -1;
+ pinvoke_info = false;
is_defined = false;
is_resolved = false;
CreateSignature ();
CreateNamedParamTable ();
+
+ codegen.BeginMethodDef (this);
+
+ if (codegen.SymbolWriter != null)
+ source = codegen.SymbolWriter.BeginMethod (this, start);
}
public string Name {
get { return signature; }
}
+ public ITypeRef RetType {
+ get { return ret_type; }
+ }
+
+ public PEAPI.CallConv CallConv {
+ get { return call_conv; }
+ }
+
public PEAPI.MethodDef PeapiMethodDef {
get { return methoddef; }
}
+ public PEAPI.MethAttr Attributes {
+ get { return meth_attr; }
+ set { meth_attr = value; }
+ }
+
public bool IsVararg {
get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
}
+ public bool IsStatic {
+ get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
+ }
+
+ public bool IsVirtual {
+ get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
+ }
+
+ public bool IsAbstract {
+ get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
+ }
+
+ public ITypeRef[] ParamTypeList () {
+
+ if (param_list == null)
+ return new ITypeRef[0];
+ int count = 0;
+ ITypeRef[] type_list = new ITypeRef[param_list.Count];
+ foreach (ParamDef param in param_list) {
+ type_list[count++] = param.Type;
+ }
+ return type_list;
+ }
+
+ public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
+ string pinvoke_name)
+ {
+ this.pinvoke_attr = pinvoke_attr;
+ this.pinvoke_mod = pinvoke_mod;
+ this.pinvoke_name = pinvoke_name;
+ pinvoke_info = true;
+ }
+
+ public void AddGenericParam (string id)
+ {
+ if (typar_list == null)
+ typar_list = new ArrayList ();
+
+ GenericInfo gi = new GenericInfo ();
+ gi.Id = id;
+
+ typar_list.Add (gi);
+ }
+
+ public void AddGenericConstraint (int index, ITypeRef constraint)
+ {
+ GenericInfo gi = (GenericInfo) typar_list[index];
+
+ if (gi.ConstraintList == null)
+ gi.ConstraintList = new ArrayList ();
+ gi.ConstraintList.Add (constraint);
+ }
+
public void AddLocals (ArrayList local_list)
{
int slot_pos = this.local_list.Count;
entry_point = true;
}
+ public void ZeroInit ()
+ {
+ zero_init = true;
+ }
+
public void SetMaxStack (int max_stack)
{
this.max_stack = max_stack;
if (is_resolved)
return methoddef;
- PEAPI.Param[] param_array;
-
- if (param_list != null) {
- int param_count = param_list.Count;
- if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
- param_count--;
- param_array = new PEAPI.Param[param_count];
- int count = 0;
-
- foreach (ParamDef paramdef in param_list) {
- if (paramdef == ParamDef.Ellipsis)
- break;
- paramdef.Define (code_gen);
- param_array[count++] = paramdef.PeapiParam;
- }
- } else {
- param_array = new PEAPI.Param[0];
- }
-
+ PEAPI.Param [] param_array = GenerateParams (code_gen);
FixAttributes ();
ret_type.Resolve (code_gen);
if (is_resolved)
return methoddef;
- PEAPI.Param[] param_array;
-
- if (param_list != null) {
- int param_count = param_list.Count;
- if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
- param_count--;
- param_array = new PEAPI.Param[param_count];
- int count = 0;
-
- foreach (ParamDef paramdef in param_list) {
- if (paramdef == ParamDef.Ellipsis)
- break;
- paramdef.Define (code_gen);
- param_array[count++] = paramdef.PeapiParam;
- }
- } else {
- param_array = new PEAPI.Param[0];
- }
-
+ PEAPI.Param [] param_array = GenerateParams (code_gen);
FixAttributes ();
ret_type.Resolve (code_gen);
return methoddef;
}
+ private PEAPI.Param [] GenerateParams (CodeGen code_gen)
+ {
+ PEAPI.Param[] param_array;
+
+ if (param_list != null && param_list.Count > 0) {
+ int param_count = param_list.Count;
+
+ // Remove the last param if its the sentinel, not sure what
+ // should happen with more then one sentinel
+ ParamDef last = (ParamDef) param_list [param_count-1];
+ if (last.IsSentinel ())
+ param_count--;
+
+ param_array = new PEAPI.Param [param_count];
+ for (int i = 0; i < param_count; i++) {
+ ParamDef paramdef = (ParamDef) param_list [i];
+ paramdef.Define (code_gen);
+ param_array [i] = paramdef.PeapiParam;
+ }
+
+ } else {
+ param_array = new PEAPI.Param [0];
+ }
+
+ return param_array;
+ }
+
public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
{
if (!is_resolved)
throw new Exception ("Methods must be resolved before a vararg sig can be created.");
- return methoddef.MakeVarArgSignature (opt);
+ PEAPI.MethodRef methref = null;
+ StringBuilder sigbuilder = new StringBuilder ();
+ string sig;
+ foreach (PEAPI.Type t in opt)
+ sigbuilder.Append (opt + ", ");
+ sig = sigbuilder.ToString ();
+
+ if (vararg_sig_table == null) {
+ vararg_sig_table = new Hashtable ();
+ } else {
+ methref = vararg_sig_table [sig] as PEAPI.MethodRef;
+ }
+
+ if (methref == null) {
+ methref = methoddef.MakeVarArgSignature (opt);
+ vararg_sig_table [sig] = methref;
+ }
+
+ return methref;
}
/// <summary>
WriteCode (code_gen, methoddef);
+ //code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
is_defined = true;
}
/// <summary>
/// Define a member method
/// </summary>
- public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
+ public void Define (CodeGen code_gen, TypeDef typedef)
{
if (is_defined)
return;
- Resolve (code_gen, classdef);
-
+ Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
WriteCode (code_gen, methoddef);
- is_defined = true;
+ //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
}
public void AddInstr (IInstr instr)
protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
{
+ if (IsAbstract)
+ return;
+
if (entry_point)
methoddef.DeclareEntryPoint ();
- if (local_list != null) {
+ if (local_list.Count > 0) {
+ int ec = code_gen.Report.ErrorCount;
PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
int i = 0;
foreach (Local local in local_list)
local_array[local.Slot] = local.GetPeapiLocal (code_gen);
+ if (code_gen.Report.ErrorCount > ec)
+ return;
+
+ if (zero_init)
+ init_locals = true;
+
methoddef.AddLocals (local_array, init_locals);
}
foreach (CustomAttr customattr in customattr_list)
customattr.AddTo (code_gen, methoddef);
+ if (pinvoke_info) {
+ methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
+ (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
+
+ }
+
if (inst_list.Count < 1)
return;
/// Create all the labels
/// TODO: Most labels don't actually need to be created so we could
/// probably only create the ones that need to be
- LabelInfo[] label_info = new LabelInfo[label_table.Count];
+ LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
label_table.Values.CopyTo (label_info, 0);
+ label_list.CopyTo (label_info, label_table.Count);
int previous_pos = -1;
LabelInfo previous_label = null;
Array.Sort (label_info);
foreach (LabelInfo label in label_info) {
+ if (label.UseOffset) {
+ label.Define (new PEAPI.CILLabel (label.Offset));
+ continue;
+ }
if (label.Pos == previous_pos)
label.Label = previous_label.Label;
else
label.Define (cil.NewLabel ());
+
previous_label = label;
previous_pos = label.Pos;
}
+ // Set all the label refs
+ foreach (LabelInfo label in labelref_table.Values) {
+ LabelInfo def = (LabelInfo) label_table[label.Name];
+ if (def == null) {
+ code_gen.Report.Error ("Undefined Label: " + label);
+ return;
+ }
+ label.Label = def.Label;
+ }
+
int label_pos = 0;
int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
if (next_label_pos == i) {
cil.CodeLabel (label_info[label_pos].Label);
if (label_pos < label_info.Length) {
- while (next_label_pos == i && ++label_pos < label_info.Length)
- next_label_pos = label_info[label_pos].Pos;
+ while (next_label_pos == i && ++label_pos < label_info.Length) {
+ if (label_info[label_pos].UseOffset)
+ cil.CodeLabel (label_info[label_pos].Label);
+ next_label_pos = label_info[label_pos].Pos;
+ }
}
if (label_pos >= label_info.Length)
next_label_pos = -1;
}
- instr.Emit (code_gen, cil);
+ if (source != null)
+ source.MarkLocation (instr.Location.line, cil.Offset);
+ instr.Emit (code_gen, this, cil);
}
+ if (source != null)
+ source.MarkLocation (source.EndLine, cil.Offset);
+
+ // Generic type parameters
+ if (typar_list != null) {
+ short index = 0;
+ foreach (GenericInfo gi in typar_list) {
+ PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
+ if (gi.ConstraintList != null) {
+ foreach (ITypeRef cnst in gi.ConstraintList) {
+ cnst.Resolve (code_gen);
+ gp.AddConstraint (cnst.PeapiType);
+ }
+ }
+ }
+ }
}
- public void AddLabel (string name)
+ public LabelInfo AddLabel (string name)
{
- LabelInfo label_info = new LabelInfo (name, inst_list.Count);
-
+ LabelInfo label_info = (LabelInfo) label_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = new LabelInfo (name, inst_list.Count);
label_table.Add (name, label_info);
+ return label_info;
}
- /// TODO: This whole process is kinda a hack.
- public string RandomLabel ()
+ public LabelInfo AddLabelRef (string name)
{
- int rand = label_random.Next ();
- string name = rand.ToString ();
- LabelInfo label_info = new LabelInfo (name, inst_list.Count);
+ LabelInfo label_info = (LabelInfo) label_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = (LabelInfo) labelref_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = new LabelInfo (name, -1);
+ labelref_table.Add (name, label_info);
+ return label_info;
+ }
- label_table.Add (name, label_info);
- return name;
+ public LabelInfo AddLabel (int offset)
+ {
+ // We go pos + 1 so this line is not counted
+ LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
+ label_list.Add (label_info);
+ return label_info;
+ }
+
+ public LabelInfo AddLabel ()
+ {
+ int pos = inst_list.Count;
+ LabelInfo label_info = new LabelInfo (null, inst_list.Count);
+ label_list.Add (label_info);
+ return label_info;
}
public PEAPI.CILLabel GetLabelDef (string name)
return label_info.Label;
}
+ public PEAPI.CILLabel GetLabelDef (int pos)
+ {
+ foreach (LabelInfo li in label_list) {
+ if (li.Pos == pos)
+ return li.Label;
+ }
+ return null;
+ }
+
private void CreateSignature ()
{
- signature = CreateSignature (name, param_list);
+ if (IsVararg)
+ signature = CreateVarargSignature (RetType, name, param_list);
+ else
+ signature = CreateSignature (RetType, name, param_list);
}
- public static string CreateSignature (string name, IList param_list)
+ public static string CreateSignature (ITypeRef RetType, string name, IList param_list)
{
StringBuilder builder = new StringBuilder ();
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
builder.Append (name);
builder.Append ('(');
if (param_list != null) {
bool first = true;
foreach (ParamDef paramdef in param_list) {
- if (ParamDef.Ellipsis == paramdef)
- break;
if (!first)
builder.Append (',');
builder.Append (paramdef.TypeName);
return builder.ToString ();
}
- public static string CreateSignature (string name, ITypeRef[] param_list)
+ public static string CreateVarargSignature (ITypeRef RetType, string name, IList param_list)
{
StringBuilder builder = new StringBuilder ();
+ ParamDef last = null;
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
builder.Append (name);
builder.Append ('(');
+ bool first = true;
if (param_list != null) {
- bool first = true;
+ foreach (ParamDef paramdef in param_list) {
+ if (!first)
+ builder.Append (',');
+ builder.Append (paramdef.TypeName);
+ first = false;
+ }
+ last = (ParamDef) param_list[param_list.Count - 1];
+ }
+
+
+ if (last == null || !last.IsSentinel ()) {
+ if (!first)
+ builder.Append (',');
+ builder.Append ("...");
+ }
+
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ public static string CreateVarargSignature (ITypeRef RetType, string name, ITypeRef [] param_list)
+ {
+ StringBuilder builder = new StringBuilder ();
+ ITypeRef last = null;
+
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
+ builder.Append (name);
+ builder.Append ('(');
+
+ bool first = true;
+ if (param_list != null && param_list.Length > 0) {
foreach (ITypeRef param in param_list) {
- if (param == TypeRef.Ellipsis)
+ if (!first)
+ builder.Append (',');
+ builder.Append (param.FullName);
+ first = false;
+ last = param;
+ if (param is SentinelTypeRef)
break;
+ }
+
+ }
+
+ if (last == null || !(last is SentinelTypeRef)) {
+ if (!first)
+ builder.Append (',');
+ builder.Append ("...");
+ }
+
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ public static string CreateSignature (ITypeRef RetType, string name, ITypeRef[] param_list)
+ {
+ StringBuilder builder = new StringBuilder ();
+
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
+ builder.Append (name);
+ builder.Append ('(');
+
+ if (param_list != null) {
+ bool first = true;
+ foreach (ITypeRef param in param_list) {
if (!first)
builder.Append (',');
builder.Append (param.FullName);
first = false;
+ if (param is SentinelTypeRef)
+ break;
}
}
builder.Append (')');
if (param_list == null)
return;
- int count = 0;
+ int count = (IsStatic ? 0 : 1);
+
foreach (ParamDef param in param_list) {
if (param.Name != null)
named_param_table.Add (param.Name, count);