2 // Mono.ILASM.MethodDef
5 // Jackson Harper (Jackson@LatitudeGeo.com)
7 // (C) 2003 Jackson Harper, All rights reserved
13 using System.Collections;
16 namespace Mono.ILASM {
18 public class MethodDef {
20 protected class LabelInfo : IComparable {
22 public readonly string Name;
23 public readonly int Pos;
24 public PEAPI.CILLabel Label;
26 public LabelInfo (string name, int pos)
33 public void Define (PEAPI.CILLabel label)
38 public int CompareTo (object obj)
40 LabelInfo other = obj as LabelInfo;
43 return Pos.CompareTo(other.Pos);
45 throw new ArgumentException ("object is not a LabelInfo");
49 private PEAPI.MethAttr meth_attr;
50 private PEAPI.CallConv call_conv;
51 private PEAPI.ImplAttr impl_attr;
53 private string signature;
54 private ITypeRef ret_type;
55 private ArrayList param_list;
56 private Hashtable named_param_table;
57 private ArrayList inst_list;
58 private ArrayList customattr_list;
59 private Hashtable label_table;
60 private PEAPI.MethodDef methoddef;
61 private bool entry_point;
62 private bool is_resolved;
63 private bool is_defined;
64 private ArrayList local_list;
65 private Hashtable named_local_table;
66 private bool init_locals;
67 private int max_stack;
68 private Random label_random;
70 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
71 PEAPI.ImplAttr impl_attr, string name,
72 ITypeRef ret_type, ArrayList param_list)
74 this.meth_attr = meth_attr;
75 this.call_conv = call_conv;
76 this.impl_attr = impl_attr;
78 this.ret_type = ret_type;
79 this.param_list = param_list;
81 inst_list = new ArrayList ();
82 customattr_list = new ArrayList ();
83 label_table = new Hashtable ();
84 local_list = new ArrayList ();
85 named_local_table = new Hashtable ();
86 named_param_table = new Hashtable ();
87 label_random = new Random ();
95 CreateNamedParamTable ();
102 public string Signature {
103 get { return signature; }
106 public PEAPI.MethodDef PeapiMethodDef {
107 get { return methoddef; }
110 public bool IsVararg {
111 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
114 public void AddLocals (ArrayList local_list)
116 int slot_pos = this.local_list.Count;
118 foreach (Local local in local_list) {
119 if (local.Slot == -1) {
120 local.Slot = slot_pos;
123 if (local.Name == null)
125 named_local_table.Add (local.Name, local);
128 this.local_list.AddRange (local_list);
131 public Local GetNamedLocal (string name)
133 return (Local) named_local_table[name];
136 public int GetNamedLocalSlot (string name)
138 Local local = (Local) named_local_table[name];
143 public int GetNamedParamPos (string name)
145 int pos = (int) named_param_table[name];
150 public void InitLocals ()
155 public void EntryPoint ()
160 public void SetMaxStack (int max_stack)
162 this.max_stack = max_stack;
165 public void AddCustomAttr (CustomAttr customattr)
167 customattr_list.Add (customattr);
170 public PEAPI.MethodDef Resolve (CodeGen code_gen)
175 PEAPI.Param[] param_array;
177 if (param_list != null) {
178 int param_count = param_list.Count;
179 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
181 param_array = new PEAPI.Param[param_count];
184 foreach (ParamDef paramdef in param_list) {
185 if (paramdef == ParamDef.Ellipsis)
187 paramdef.Define (code_gen);
188 param_array[count++] = paramdef.PeapiParam;
191 param_array = new PEAPI.Param[0];
195 ret_type.Resolve (code_gen);
197 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
198 name, ret_type.PeapiType, param_array);
200 methoddef.AddCallConv (call_conv);
206 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
211 PEAPI.Param[] param_array;
213 if (param_list != null) {
214 int param_count = param_list.Count;
215 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
217 param_array = new PEAPI.Param[param_count];
220 foreach (ParamDef paramdef in param_list) {
221 if (paramdef == ParamDef.Ellipsis)
223 paramdef.Define (code_gen);
224 param_array[count++] = paramdef.PeapiParam;
227 param_array = new PEAPI.Param[0];
231 ret_type.Resolve (code_gen);
233 methoddef = classdef.AddMethod (meth_attr, impl_attr,
234 name, ret_type.PeapiType, param_array);
236 methoddef.AddCallConv (call_conv);
242 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
245 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
247 return methoddef.MakeVarArgSignature (opt);
251 /// Define a global method
253 public void Define (CodeGen code_gen)
260 WriteCode (code_gen, methoddef);
266 /// Define a member method
268 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
273 Resolve (code_gen, classdef);
275 WriteCode (code_gen, methoddef);
280 public void AddInstr (IInstr instr)
282 inst_list.Add (instr);
285 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
288 methoddef.DeclareEntryPoint ();
290 if (local_list != null) {
291 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
294 foreach (Local local in local_list)
295 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
297 methoddef.AddLocals (local_array, init_locals);
300 /// Nothing seems to work if maxstack is not set,
301 /// i need to find out if this NEEDs to be set
302 /// and what its default value should be
305 methoddef.SetMaxStack (max_stack);
307 /// Add the custrom attributes to this method
308 foreach (CustomAttr customattr in customattr_list)
309 customattr.AddTo (code_gen, methoddef);
311 if (inst_list.Count < 1)
314 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
315 /// Create all the labels
316 /// TODO: Most labels don't actually need to be created so we could
317 /// probably only create the ones that need to be
318 LabelInfo[] label_info = new LabelInfo[label_table.Count];
319 label_table.Values.CopyTo (label_info, 0);
320 int previous_pos = -1;
321 LabelInfo previous_label = null;
322 Array.Sort (label_info);
324 foreach (LabelInfo label in label_info) {
325 if (label.Pos == previous_pos)
326 label.Label = previous_label.Label;
328 label.Define (cil.NewLabel ());
329 previous_label = label;
330 previous_pos = label.Pos;
334 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
336 for (int i=0; i<inst_list.Count; i++) {
337 IInstr instr = (IInstr) inst_list[i];
338 if (next_label_pos == i) {
339 cil.CodeLabel (label_info[label_pos].Label);
340 if (label_pos < label_info.Length) {
341 while (next_label_pos == i && ++label_pos < label_info.Length)
342 next_label_pos = label_info[label_pos].Pos;
344 if (label_pos >= label_info.Length)
347 instr.Emit (code_gen, this, cil);
352 public void AddLabel (string name)
354 LabelInfo label_info = new LabelInfo (name, inst_list.Count);
356 label_table.Add (name, label_info);
359 /// TODO: This whole process is kinda a hack.
360 public string RandomLabel ()
362 int rand = label_random.Next ();
363 string name = rand.ToString ();
364 LabelInfo label_info = new LabelInfo (name, inst_list.Count);
366 label_table.Add (name, label_info);
370 public PEAPI.CILLabel GetLabelDef (string name)
372 LabelInfo label_info = (LabelInfo) label_table[name];
374 return label_info.Label;
377 private void CreateSignature ()
379 signature = CreateSignature (name, param_list);
382 public static string CreateSignature (string name, IList param_list)
384 StringBuilder builder = new StringBuilder ();
386 builder.Append (name);
387 builder.Append ('(');
389 if (param_list != null) {
391 foreach (ParamDef paramdef in param_list) {
392 if (ParamDef.Ellipsis == paramdef)
395 builder.Append (',');
396 builder.Append (paramdef.TypeName);
400 builder.Append (')');
402 return builder.ToString ();
405 public static string CreateSignature (string name, ITypeRef[] param_list)
407 StringBuilder builder = new StringBuilder ();
409 builder.Append (name);
410 builder.Append ('(');
412 if (param_list != null) {
414 foreach (ITypeRef param in param_list) {
415 if (param == TypeRef.Ellipsis)
418 builder.Append (',');
419 builder.Append (param.FullName);
423 builder.Append (')');
425 return builder.ToString ();
428 private void CreateNamedParamTable ()
430 if (param_list == null)
434 foreach (ParamDef param in param_list) {
435 if (param.Name != null)
436 named_param_table.Add (param.Name, count);
441 private void FixAttributes ()
443 if (name == ".ctor" || name == ".cctor")
444 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
445 // If methods aren't flagged as static they are instance
446 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
447 call_conv |= PEAPI.CallConv.Instance;