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 readonly uint Offset;
25 public PEAPI.CILLabel Label;
26 public bool UseOffset;
28 public LabelInfo (string name, int pos, uint offset)
37 public LabelInfo (string name, int pos)
45 public void Define (PEAPI.CILLabel label)
50 public int CompareTo (object obj)
52 LabelInfo other = obj as LabelInfo;
55 return Pos.CompareTo(other.Pos);
57 throw new ArgumentException ("object is not a LabelInfo");
61 private PEAPI.MethAttr meth_attr;
62 private PEAPI.CallConv call_conv;
63 private PEAPI.ImplAttr impl_attr;
65 private string signature;
66 private ITypeRef ret_type;
67 private ArrayList param_list;
68 private Hashtable named_param_table;
69 private ArrayList inst_list;
70 private ArrayList customattr_list;
71 private Hashtable label_table;
72 private ArrayList label_list;
73 private ArrayList offset_list;
74 private PEAPI.MethodDef methoddef;
75 private bool entry_point;
76 private bool is_resolved;
77 private bool is_defined;
78 private ArrayList local_list;
79 private Hashtable named_local_table;
80 private bool init_locals;
81 private int max_stack;
82 private Random label_random;
84 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
85 PEAPI.ImplAttr impl_attr, string name,
86 ITypeRef ret_type, ArrayList param_list)
88 this.meth_attr = meth_attr;
89 this.call_conv = call_conv;
90 this.impl_attr = impl_attr;
92 this.ret_type = ret_type;
93 this.param_list = param_list;
95 inst_list = new ArrayList ();
96 customattr_list = new ArrayList ();
97 label_table = new Hashtable ();
98 label_list = new ArrayList ();
99 offset_list = new ArrayList ();
100 local_list = new ArrayList ();
101 named_local_table = new Hashtable ();
102 named_param_table = new Hashtable ();
103 label_random = new Random ();
111 CreateNamedParamTable ();
118 public string Signature {
119 get { return signature; }
122 public PEAPI.MethodDef PeapiMethodDef {
123 get { return methoddef; }
126 public bool IsVararg {
127 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
130 public void AddLocals (ArrayList local_list)
132 int slot_pos = this.local_list.Count;
134 foreach (Local local in local_list) {
135 if (local.Slot == -1) {
136 local.Slot = slot_pos;
139 if (local.Name == null)
141 named_local_table.Add (local.Name, local);
144 this.local_list.AddRange (local_list);
147 public Local GetNamedLocal (string name)
149 return (Local) named_local_table[name];
152 public int GetNamedLocalSlot (string name)
154 Local local = (Local) named_local_table[name];
159 public int GetNamedParamPos (string name)
161 int pos = (int) named_param_table[name];
166 public void InitLocals ()
171 public void EntryPoint ()
176 public void SetMaxStack (int max_stack)
178 this.max_stack = max_stack;
181 public void AddCustomAttr (CustomAttr customattr)
183 customattr_list.Add (customattr);
186 public PEAPI.MethodDef Resolve (CodeGen code_gen)
191 PEAPI.Param[] param_array;
193 if (param_list != null) {
194 int param_count = param_list.Count;
195 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
197 param_array = new PEAPI.Param[param_count];
200 foreach (ParamDef paramdef in param_list) {
201 if (paramdef == ParamDef.Ellipsis)
203 paramdef.Define (code_gen);
204 param_array[count++] = paramdef.PeapiParam;
207 param_array = new PEAPI.Param[0];
211 ret_type.Resolve (code_gen);
213 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
214 name, ret_type.PeapiType, param_array);
216 methoddef.AddCallConv (call_conv);
222 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
227 PEAPI.Param[] param_array;
229 if (param_list != null) {
230 int param_count = param_list.Count;
231 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
233 param_array = new PEAPI.Param[param_count];
236 foreach (ParamDef paramdef in param_list) {
237 if (paramdef == ParamDef.Ellipsis)
239 paramdef.Define (code_gen);
240 param_array[count++] = paramdef.PeapiParam;
243 param_array = new PEAPI.Param[0];
247 ret_type.Resolve (code_gen);
249 methoddef = classdef.AddMethod (meth_attr, impl_attr,
250 name, ret_type.PeapiType, param_array);
252 methoddef.AddCallConv (call_conv);
258 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
261 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
263 return methoddef.MakeVarArgSignature (opt);
267 /// Define a global method
269 public void Define (CodeGen code_gen)
276 WriteCode (code_gen, methoddef);
282 /// Define a member method
284 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
289 Resolve (code_gen, classdef);
290 WriteCode (code_gen, methoddef);
295 public void AddInstr (IInstr instr)
297 inst_list.Add (instr);
300 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
303 methoddef.DeclareEntryPoint ();
305 if (local_list != null) {
306 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
309 foreach (Local local in local_list)
310 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
312 methoddef.AddLocals (local_array, init_locals);
315 /// Nothing seems to work if maxstack is not set,
316 /// i need to find out if this NEEDs to be set
317 /// and what its default value should be
320 methoddef.SetMaxStack (max_stack);
322 /// Add the custrom attributes to this method
323 foreach (CustomAttr customattr in customattr_list)
324 customattr.AddTo (code_gen, methoddef);
326 if (inst_list.Count < 1)
329 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
330 /// Create all the labels
331 /// TODO: Most labels don't actually need to be created so we could
332 /// probably only create the ones that need to be
333 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
334 label_table.Values.CopyTo (label_info, 0);
335 label_list.CopyTo (label_info, label_table.Count);
336 int previous_pos = -1;
337 LabelInfo previous_label = null;
338 Array.Sort (label_info);
340 foreach (LabelInfo label in label_info) {
341 if (label.Pos == previous_pos)
342 label.Label = previous_label.Label;
344 label.Define (cil.NewLabel ());
346 previous_label = label;
347 previous_pos = label.Pos;
350 foreach (LabelInfo label in offset_list) {
351 label.Define (new PEAPI.CILLabel (label.Offset));
355 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
357 for (int i=0; i<inst_list.Count; i++) {
358 IInstr instr = (IInstr) inst_list[i];
359 if (next_label_pos == i) {
360 cil.CodeLabel (label_info[label_pos].Label);
361 if (label_pos < label_info.Length) {
362 while (next_label_pos == i && ++label_pos < label_info.Length)
363 next_label_pos = label_info[label_pos].Pos;
365 if (label_pos >= label_info.Length)
368 instr.Emit (code_gen, this, cil);
373 public void AddLabel (string name)
375 LabelInfo label_info = new LabelInfo (name, inst_list.Count);
376 label_table.Add (name, label_info);
379 public void AddLabel (uint offset)
381 LabelInfo label_info = new LabelInfo (null, -1, offset);
382 offset_list.Add (label_info);
385 public int AddLabel ()
387 int pos = inst_list.Count;
388 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
389 label_list.Add (label_info);
393 /// TODO: This whole process is kinda a hack.
394 public string RandomLabel ()
397 int rand = label_random.Next ();
398 string name = rand.ToString ();
399 LabelInfo label_info = new LabelInfo (name, inst_list.Count);
401 label_table.Add (name, label_info);
407 public PEAPI.CILLabel GetLabelDef (string name)
409 LabelInfo label_info = (LabelInfo) label_table[name];
411 return label_info.Label;
414 public PEAPI.CILLabel GetLabelDef (int pos)
416 foreach (LabelInfo li in label_list) {
423 public PEAPI.CILLabel GetLabelDef (uint offset)
425 foreach (LabelInfo li in offset_list) {
426 if (li.Offset == offset)
432 private void CreateSignature ()
434 signature = CreateSignature (name, param_list);
437 public static string CreateSignature (string name, IList param_list)
439 StringBuilder builder = new StringBuilder ();
441 builder.Append (name);
442 builder.Append ('(');
444 if (param_list != null) {
446 foreach (ParamDef paramdef in param_list) {
447 if (ParamDef.Ellipsis == paramdef)
450 builder.Append (',');
451 builder.Append (paramdef.TypeName);
455 builder.Append (')');
457 return builder.ToString ();
460 public static string CreateSignature (string name, ITypeRef[] param_list)
462 StringBuilder builder = new StringBuilder ();
464 builder.Append (name);
465 builder.Append ('(');
467 if (param_list != null) {
469 foreach (ITypeRef param in param_list) {
470 if (param == TypeRef.Ellipsis)
473 builder.Append (',');
474 builder.Append (param.FullName);
478 builder.Append (')');
480 return builder.ToString ();
483 private void CreateNamedParamTable ()
485 if (param_list == null)
489 foreach (ParamDef param in param_list) {
490 if (param.Name != null)
491 named_param_table.Add (param.Name, count);
496 private void FixAttributes ()
498 if (name == ".ctor" || name == ".cctor")
499 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
500 // If methods aren't flagged as static they are instance
501 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
502 call_conv |= PEAPI.CallConv.Instance;