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 private PEAPI.MethAttr meth_attr;
21 private PEAPI.CallConv call_conv;
22 private PEAPI.ImplAttr impl_attr;
24 private string signature;
25 private ITypeRef ret_type;
26 private ArrayList param_list;
27 private Hashtable named_param_table;
28 private ArrayList inst_list;
29 private ArrayList customattr_list;
30 private Hashtable label_table;
31 private Hashtable labelref_table;
32 private ArrayList label_list;
33 private PEAPI.MethodDef methoddef;
34 private bool entry_point;
35 private bool is_resolved;
36 private bool is_defined;
37 private ArrayList local_list;
38 private Hashtable named_local_table;
39 private bool init_locals;
40 private int max_stack;
43 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
44 PEAPI.ImplAttr impl_attr, string name,
45 ITypeRef ret_type, ArrayList param_list)
47 this.meth_attr = meth_attr;
48 this.call_conv = call_conv;
49 this.impl_attr = impl_attr;
51 this.ret_type = ret_type;
52 this.param_list = param_list;
54 inst_list = new ArrayList ();
55 customattr_list = new ArrayList ();
56 label_table = new Hashtable ();
57 labelref_table = new Hashtable ();
58 label_list = new ArrayList ();
59 local_list = new ArrayList ();
60 named_local_table = new Hashtable ();
61 named_param_table = new Hashtable ();
70 CreateNamedParamTable ();
77 public string Signature {
78 get { return signature; }
81 public ITypeRef RetType {
82 get { return ret_type; }
85 public PEAPI.CallConv CallConv {
86 get { return call_conv; }
89 public PEAPI.MethodDef PeapiMethodDef {
90 get { return methoddef; }
93 public bool IsVararg {
94 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
97 public ITypeRef[] ParamTypeList () {
99 if (param_list == null)
100 return new ITypeRef[0];
102 ITypeRef[] type_list = new ITypeRef[param_list.Count];
103 foreach (ParamDef param in param_list) {
104 type_list[count++] = param.Type;
109 public void AddLocals (ArrayList local_list)
111 int slot_pos = this.local_list.Count;
113 foreach (Local local in local_list) {
114 if (local.Slot == -1) {
115 local.Slot = slot_pos;
118 if (local.Name == null)
120 named_local_table.Add (local.Name, local);
123 this.local_list.AddRange (local_list);
126 public Local GetNamedLocal (string name)
128 return (Local) named_local_table[name];
131 public int GetNamedLocalSlot (string name)
133 Local local = (Local) named_local_table[name];
138 public int GetNamedParamPos (string name)
140 int pos = (int) named_param_table[name];
145 public void InitLocals ()
150 public void EntryPoint ()
155 public void SetMaxStack (int max_stack)
157 this.max_stack = max_stack;
160 public void AddCustomAttr (CustomAttr customattr)
162 customattr_list.Add (customattr);
165 public PEAPI.MethodDef Resolve (CodeGen code_gen)
170 PEAPI.Param[] param_array;
172 if (param_list != null) {
173 int param_count = param_list.Count;
174 param_array = new PEAPI.Param[param_count];
177 foreach (ParamDef paramdef in param_list) {
178 paramdef.Define (code_gen);
179 param_array[count++] = paramdef.PeapiParam;
182 param_array = new PEAPI.Param[0];
186 ret_type.Resolve (code_gen);
188 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
189 name, ret_type.PeapiType, param_array);
191 methoddef.AddCallConv (call_conv);
197 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
202 PEAPI.Param[] param_array;
204 if (param_list != null) {
205 int param_count = param_list.Count;
206 param_array = new PEAPI.Param[param_count];
209 foreach (ParamDef paramdef in param_list) {
210 paramdef.Define (code_gen);
211 param_array[count++] = paramdef.PeapiParam;
214 param_array = new PEAPI.Param[0];
218 ret_type.Resolve (code_gen);
220 methoddef = classdef.AddMethod (meth_attr, impl_attr,
221 name, ret_type.PeapiType, param_array);
223 methoddef.AddCallConv (call_conv);
229 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
232 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
234 return methoddef.MakeVarArgSignature (opt);
238 /// Define a global method
240 public void Define (CodeGen code_gen)
247 WriteCode (code_gen, methoddef);
253 /// Define a member method
255 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
260 Resolve (code_gen, classdef);
261 WriteCode (code_gen, methoddef);
266 public void AddInstr (IInstr instr)
268 inst_list.Add (instr);
271 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
274 methoddef.DeclareEntryPoint ();
276 if (local_list != null) {
277 int ec = code_gen.Report.ErrorCount;
278 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
281 foreach (Local local in local_list)
282 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
284 if (code_gen.Report.ErrorCount > ec)
287 methoddef.AddLocals (local_array, init_locals);
290 /// Nothing seems to work if maxstack is not set,
291 /// i need to find out if this NEEDs to be set
292 /// and what its default value should be
295 methoddef.SetMaxStack (max_stack);
297 /// Add the custrom attributes to this method
298 foreach (CustomAttr customattr in customattr_list)
299 customattr.AddTo (code_gen, methoddef);
301 if (inst_list.Count < 1)
304 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
305 /// Create all the labels
306 /// TODO: Most labels don't actually need to be created so we could
307 /// probably only create the ones that need to be
308 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
309 label_table.Values.CopyTo (label_info, 0);
310 label_list.CopyTo (label_info, label_table.Count);
311 int previous_pos = -1;
312 LabelInfo previous_label = null;
313 Array.Sort (label_info);
315 foreach (LabelInfo label in label_info) {
316 if (label.UseOffset) {
317 label.Define (new PEAPI.CILLabel (label.Offset));
320 if (label.Pos == previous_pos)
321 label.Label = previous_label.Label;
323 label.Define (cil.NewLabel ());
325 previous_label = label;
326 previous_pos = label.Pos;
329 // Set all the label refs
330 foreach (LabelInfo label in labelref_table.Values) {
331 LabelInfo def = (LabelInfo) label_table[label.Name];
333 Console.WriteLine ("Undefined Label: " + label);
336 label.Label = def.Label;
340 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
342 for (int i=0; i<inst_list.Count; i++) {
343 IInstr instr = (IInstr) inst_list[i];
344 if (next_label_pos == i) {
345 cil.CodeLabel (label_info[label_pos].Label);
346 if (label_pos < label_info.Length) {
347 while (next_label_pos == i && ++label_pos < label_info.Length) {
348 if (label_info[label_pos].UseOffset)
349 cil.CodeLabel (label_info[label_pos].Label);
350 next_label_pos = label_info[label_pos].Pos;
353 if (label_pos >= label_info.Length)
356 instr.Emit (code_gen, this, cil);
361 public LabelInfo AddLabel (string name)
363 LabelInfo label_info = (LabelInfo) label_table[name];
364 if (label_info != null)
366 label_info = new LabelInfo (name, inst_list.Count);
367 label_table.Add (name, label_info);
371 public LabelInfo AddLabelRef (string name)
373 LabelInfo label_info = (LabelInfo) label_table[name];
374 if (label_info != null)
376 label_info = (LabelInfo) labelref_table[name];
377 if (label_info != null)
379 label_info = new LabelInfo (name, -1);
380 labelref_table.Add (name, label_info);
384 public LabelInfo AddLabel (int offset)
386 // We go pos + 1 so this line is not counted
387 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
388 label_list.Add (label_info);
392 public LabelInfo AddLabel ()
394 int pos = inst_list.Count;
395 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
396 label_list.Add (label_info);
400 public PEAPI.CILLabel GetLabelDef (string name)
402 LabelInfo label_info = (LabelInfo) label_table[name];
404 return label_info.Label;
407 public PEAPI.CILLabel GetLabelDef (int pos)
409 foreach (LabelInfo li in label_list) {
416 private void CreateSignature ()
419 signature = CreateVarargSignature (name, param_list);
421 signature = CreateSignature (name, param_list);
424 public static string CreateSignature (string name, IList param_list)
426 StringBuilder builder = new StringBuilder ();
428 builder.Append (name);
429 builder.Append ('(');
431 if (param_list != null) {
433 foreach (ParamDef paramdef in param_list) {
435 builder.Append (',');
436 builder.Append (paramdef.TypeName);
440 builder.Append (')');
442 return builder.ToString ();
445 public static string CreateVarargSignature (string name, IList param_list)
447 StringBuilder builder = new StringBuilder ();
449 builder.Append (name);
450 builder.Append ('(');
453 if (param_list != null) {
454 foreach (ParamDef paramdef in param_list) {
456 builder.Append (',');
457 builder.Append (paramdef.TypeName);
461 ParamDef last = (ParamDef) param_list[param_list.Count - 1];
462 if (!last.IsSentinel ()) {
464 builder.Append (',');
465 builder.Append ("...");
467 builder.Append (')');
469 return builder.ToString ();
472 public static string CreateSignature (string name, ITypeRef[] param_list)
474 StringBuilder builder = new StringBuilder ();
476 builder.Append (name);
477 builder.Append ('(');
479 if (param_list != null) {
481 foreach (ITypeRef param in param_list) {
483 builder.Append (',');
484 builder.Append (param.FullName);
486 if (param is SentinelTypeRef)
490 builder.Append (')');
492 return builder.ToString ();
495 private void CreateNamedParamTable ()
497 if (param_list == null)
501 foreach (ParamDef param in param_list) {
502 if (param.Name != null)
503 named_param_table.Add (param.Name, count);
508 private void FixAttributes ()
510 if (name == ".ctor" || name == ".cctor")
511 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
512 // If methods aren't flagged as static they are instance
513 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
514 call_conv |= PEAPI.CallConv.Instance;