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;
27 public LabelInfo (string name, int pos, uint offset)
35 public void Define (PEAPI.CILLabel label)
40 public int CompareTo (object obj)
42 LabelInfo other = obj as LabelInfo;
45 return Pos.CompareTo(other.Pos);
47 throw new ArgumentException ("object is not a LabelInfo");
51 private PEAPI.MethAttr meth_attr;
52 private PEAPI.CallConv call_conv;
53 private PEAPI.ImplAttr impl_attr;
55 private string signature;
56 private ITypeRef ret_type;
57 private ArrayList param_list;
58 private Hashtable named_param_table;
59 private ArrayList inst_list;
60 private ArrayList customattr_list;
61 private Hashtable label_table;
62 private ArrayList label_list;
63 private PEAPI.MethodDef methoddef;
64 private bool entry_point;
65 private bool is_resolved;
66 private bool is_defined;
67 private ArrayList local_list;
68 private Hashtable named_local_table;
69 private bool init_locals;
70 private int max_stack;
71 private Random label_random;
73 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
74 PEAPI.ImplAttr impl_attr, string name,
75 ITypeRef ret_type, ArrayList param_list)
77 this.meth_attr = meth_attr;
78 this.call_conv = call_conv;
79 this.impl_attr = impl_attr;
81 this.ret_type = ret_type;
82 this.param_list = param_list;
84 inst_list = new ArrayList ();
85 customattr_list = new ArrayList ();
86 label_table = new Hashtable ();
87 label_list = new ArrayList ();
88 local_list = new ArrayList ();
89 named_local_table = new Hashtable ();
90 named_param_table = new Hashtable ();
91 label_random = new Random ();
99 CreateNamedParamTable ();
106 public string Signature {
107 get { return signature; }
110 public PEAPI.MethodDef PeapiMethodDef {
111 get { return methoddef; }
114 public bool IsVararg {
115 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
118 public void AddLocals (ArrayList local_list)
120 int slot_pos = this.local_list.Count;
122 foreach (Local local in local_list) {
123 if (local.Slot == -1) {
124 local.Slot = slot_pos;
127 if (local.Name == null)
129 named_local_table.Add (local.Name, local);
132 this.local_list.AddRange (local_list);
135 public Local GetNamedLocal (string name)
137 return (Local) named_local_table[name];
140 public int GetNamedLocalSlot (string name)
142 Local local = (Local) named_local_table[name];
147 public int GetNamedParamPos (string name)
149 int pos = (int) named_param_table[name];
154 public void InitLocals ()
159 public void EntryPoint ()
164 public void SetMaxStack (int max_stack)
166 this.max_stack = max_stack;
169 public void AddCustomAttr (CustomAttr customattr)
171 customattr_list.Add (customattr);
174 public PEAPI.MethodDef Resolve (CodeGen code_gen)
179 PEAPI.Param[] param_array;
181 if (param_list != null) {
182 int param_count = param_list.Count;
183 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
185 param_array = new PEAPI.Param[param_count];
188 foreach (ParamDef paramdef in param_list) {
189 if (paramdef == ParamDef.Ellipsis)
191 paramdef.Define (code_gen);
192 param_array[count++] = paramdef.PeapiParam;
195 param_array = new PEAPI.Param[0];
199 ret_type.Resolve (code_gen);
201 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
202 name, ret_type.PeapiType, param_array);
204 methoddef.AddCallConv (call_conv);
210 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
215 PEAPI.Param[] param_array;
217 if (param_list != null) {
218 int param_count = param_list.Count;
219 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
221 param_array = new PEAPI.Param[param_count];
224 foreach (ParamDef paramdef in param_list) {
225 if (paramdef == ParamDef.Ellipsis)
227 paramdef.Define (code_gen);
228 param_array[count++] = paramdef.PeapiParam;
231 param_array = new PEAPI.Param[0];
235 ret_type.Resolve (code_gen);
237 methoddef = classdef.AddMethod (meth_attr, impl_attr,
238 name, ret_type.PeapiType, param_array);
240 methoddef.AddCallConv (call_conv);
246 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
249 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
251 return methoddef.MakeVarArgSignature (opt);
255 /// Define a global method
257 public void Define (CodeGen code_gen)
264 WriteCode (code_gen, methoddef);
270 /// Define a member method
272 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
277 Resolve (code_gen, classdef);
279 WriteCode (code_gen, methoddef);
284 public void AddInstr (IInstr instr)
286 inst_list.Add (instr);
289 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
292 methoddef.DeclareEntryPoint ();
294 if (local_list != null) {
295 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
298 foreach (Local local in local_list)
299 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
301 methoddef.AddLocals (local_array, init_locals);
304 /// Nothing seems to work if maxstack is not set,
305 /// i need to find out if this NEEDs to be set
306 /// and what its default value should be
309 methoddef.SetMaxStack (max_stack);
311 /// Add the custrom attributes to this method
312 foreach (CustomAttr customattr in customattr_list)
313 customattr.AddTo (code_gen, methoddef);
315 if (inst_list.Count < 1)
318 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
319 /// Create all the labels
320 /// TODO: Most labels don't actually need to be created so we could
321 /// probably only create the ones that need to be
322 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
323 label_table.Values.CopyTo (label_info, 0);
324 label_list.CopyTo (label_info, label_table.Count);
325 int previous_pos = -1;
326 LabelInfo previous_label = null;
327 Array.Sort (label_info);
329 foreach (LabelInfo label in label_info) {
330 if (label.Offset > -1) {
331 label.Define (new PEAPI.CILLabel (label.Offset));
334 if (label.Pos == previous_pos)
335 label.Label = previous_label.Label;
337 label.Define (cil.NewLabel ());
338 previous_label = label;
339 previous_pos = label.Pos;
343 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
345 for (int i=0; i<inst_list.Count; i++) {
346 IInstr instr = (IInstr) inst_list[i];
347 if (next_label_pos == i) {
348 cil.CodeLabel (label_info[label_pos].Label);
349 if (label_pos < label_info.Length) {
350 while (next_label_pos == i && ++label_pos < label_info.Length)
351 next_label_pos = label_info[label_pos].Pos;
353 if (label_pos >= label_info.Length)
356 instr.Emit (code_gen, this, cil);
361 public void AddLabel (string name)
363 LabelInfo label_info = new LabelInfo (name, inst_list.Count, 0);
364 label_table.Add (name, label_info);
367 public void AddLabel (uint offset)
369 LabelInfo label_info = new LabelInfo (name, -1, offset);
370 label_list.Add (label_info);
373 public int AddLabel ()
375 int pos = inst_list.Count;
376 LabelInfo label_info = new LabelInfo (null, inst_list.Count, 0);
377 label_list.Add (label_info);
381 /// TODO: This whole process is kinda a hack.
382 public string RandomLabel ()
385 int rand = label_random.Next ();
386 string name = rand.ToString ();
387 LabelInfo label_info = new LabelInfo (name, inst_list.Count);
389 label_table.Add (name, label_info);
395 public PEAPI.CILLabel GetLabelDef (string name)
397 LabelInfo label_info = (LabelInfo) label_table[name];
399 return label_info.Label;
402 public PEAPI.CILLabel GetLabelDef (int pos)
404 foreach (LabelInfo li in label_list) {
411 public PEAPI.CILLabel GetLabelDef (uint offset)
413 foreach (LabelInfo li in label_list) {
414 if (li.Offset == offset)
420 private void CreateSignature ()
422 signature = CreateSignature (name, param_list);
425 public static string CreateSignature (string name, IList param_list)
427 StringBuilder builder = new StringBuilder ();
429 builder.Append (name);
430 builder.Append ('(');
432 if (param_list != null) {
434 foreach (ParamDef paramdef in param_list) {
435 if (ParamDef.Ellipsis == paramdef)
438 builder.Append (',');
439 builder.Append (paramdef.TypeName);
443 builder.Append (')');
445 return builder.ToString ();
448 public static string CreateSignature (string name, ITypeRef[] param_list)
450 StringBuilder builder = new StringBuilder ();
452 builder.Append (name);
453 builder.Append ('(');
455 if (param_list != null) {
457 foreach (ITypeRef param in param_list) {
458 if (param == TypeRef.Ellipsis)
461 builder.Append (',');
462 builder.Append (param.FullName);
466 builder.Append (')');
468 return builder.ToString ();
471 private void CreateNamedParamTable ()
473 if (param_list == null)
477 foreach (ParamDef param in param_list) {
478 if (param.Name != null)
479 named_param_table.Add (param.Name, count);
484 private void FixAttributes ()
486 if (name == ".ctor" || name == ".cctor")
487 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
488 // If methods aren't flagged as static they are instance
489 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
490 call_conv |= PEAPI.CallConv.Instance;