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 : ICustomAttrTarget {
20 protected class GenericInfo {
22 public ArrayList ConstraintList;
25 private PEAPI.MethAttr meth_attr;
26 private PEAPI.CallConv call_conv;
27 private PEAPI.ImplAttr impl_attr;
29 private string signature;
30 private Hashtable vararg_sig_table;
31 private ITypeRef ret_type;
32 private ArrayList typar_list;
33 private ArrayList param_list;
34 private ArrayList inst_list;
35 private ArrayList customattr_list;
36 private Hashtable label_table;
37 private Hashtable labelref_table;
38 private ArrayList label_list;
39 private PEAPI.MethodDef methoddef;
40 private bool entry_point;
41 private bool zero_init;
42 private bool is_resolved;
43 private bool is_defined;
44 private ArrayList local_list;
45 private Hashtable named_local_table;
46 private bool init_locals;
47 private int max_stack;
48 private bool pinvoke_info;
49 private ExternModule pinvoke_mod;
50 private string pinvoke_name;
51 private PEAPI.PInvokeAttr pinvoke_attr;
52 private SourceMethod source;
54 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
55 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
56 string name, ITypeRef ret_type, ArrayList param_list,
59 this.meth_attr = meth_attr;
60 this.call_conv = call_conv;
61 this.impl_attr = impl_attr;
63 this.ret_type = ret_type;
64 this.param_list = param_list;
66 inst_list = new ArrayList ();
67 label_table = new Hashtable ();
68 labelref_table = new Hashtable ();
69 label_list = new ArrayList ();
70 local_list = new ArrayList ();
71 named_local_table = new Hashtable ();
83 codegen.BeginMethodDef (this);
85 if (codegen.SymbolWriter != null)
86 source = codegen.SymbolWriter.BeginMethod (this, start);
93 public string Signature {
94 get { return signature; }
97 public ITypeRef RetType {
98 get { return ret_type; }
101 public PEAPI.CallConv CallConv {
102 get { return call_conv; }
105 public PEAPI.MethodDef PeapiMethodDef {
106 get { return methoddef; }
109 public PEAPI.MethAttr Attributes {
110 get { return meth_attr; }
111 set { meth_attr = value; }
114 public bool IsVararg {
115 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
118 public bool IsStatic {
119 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
122 public bool IsVirtual {
123 get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
126 public bool IsAbstract {
127 get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
130 public ITypeRef[] ParamTypeList () {
132 if (param_list == null)
133 return new ITypeRef[0];
135 ITypeRef[] type_list = new ITypeRef[param_list.Count];
136 foreach (ParamDef param in param_list) {
137 type_list[count++] = param.Type;
142 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
145 this.pinvoke_attr = pinvoke_attr;
146 this.pinvoke_mod = pinvoke_mod;
147 this.pinvoke_name = pinvoke_name;
151 public void AddGenericParam (string id)
153 if (typar_list == null)
154 typar_list = new ArrayList ();
156 GenericInfo gi = new GenericInfo ();
162 public void AddGenericConstraint (int index, ITypeRef constraint)
164 GenericInfo gi = (GenericInfo) typar_list[index];
166 if (gi.ConstraintList == null)
167 gi.ConstraintList = new ArrayList ();
168 gi.ConstraintList.Add (constraint);
171 public void AddParamDefaultValue (int index, PEAPI.Constant defval)
173 if (param_list [index] != null) {
174 ((ParamDef)param_list [index]).AddDefaultValue (defval);
178 public void AddCustomAttribute (CustomAttr customattr)
180 if (customattr_list == null)
181 customattr_list = new ArrayList ();
183 customattr_list.Add (customattr);
187 public void AddLocals (ArrayList local_list)
189 int slot_pos = this.local_list.Count;
191 foreach (Local local in local_list) {
192 if (local.Slot == -1) {
193 local.Slot = slot_pos;
196 if (local.Name == null)
198 if(!named_local_table.Contains(local.Name))
199 named_local_table.Add (local.Name, local);
202 this.local_list.AddRange (local_list);
205 public Local GetNamedLocal (string name)
207 return (Local) named_local_table[name];
210 public int GetNamedLocalSlot (string name)
212 Local local = (Local) named_local_table[name];
217 public int GetNamedParamPos (string name)
222 foreach (ParamDef param in param_list) {
224 if (param.Name.CompareTo (name) == 0)
231 public ParamDef GetParam (int index)
233 if (param_list [index] != null)
234 return (ParamDef)param_list [index];
239 public void InitLocals ()
244 public void EntryPoint ()
249 public void ZeroInit ()
254 public void SetMaxStack (int max_stack)
256 this.max_stack = max_stack;
259 public PEAPI.MethodDef Resolve (CodeGen code_gen)
264 PEAPI.Param [] param_array = GenerateParams (code_gen);
266 ret_type.Resolve (code_gen);
268 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
269 name, ret_type.PeapiType, param_array);
271 methoddef.AddCallConv (call_conv);
277 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
282 PEAPI.Param [] param_array = GenerateParams (code_gen);
284 ret_type.Resolve (code_gen);
286 methoddef = classdef.AddMethod (meth_attr, impl_attr,
287 name, ret_type.PeapiType, param_array);
289 methoddef.AddCallConv (call_conv);
295 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
297 PEAPI.Param[] param_array;
299 if (param_list != null && param_list.Count > 0) {
300 int param_count = param_list.Count;
302 // Remove the last param if its the sentinel, not sure what
303 // should happen with more then one sentinel
304 ParamDef last = (ParamDef) param_list [param_count-1];
305 if (last.IsSentinel ())
308 param_array = new PEAPI.Param [param_count];
309 for (int i = 0; i < param_count; i++) {
310 ParamDef paramdef = (ParamDef) param_list [i];
311 paramdef.Define (code_gen);
312 param_array [i] = paramdef.PeapiParam;
316 param_array = new PEAPI.Param [0];
322 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
325 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
327 PEAPI.MethodRef methref = null;
328 StringBuilder sigbuilder = new StringBuilder ();
330 foreach (PEAPI.Type t in opt)
331 sigbuilder.Append (opt + ", ");
332 sig = sigbuilder.ToString ();
334 if (vararg_sig_table == null) {
335 vararg_sig_table = new Hashtable ();
337 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
340 if (methref == null) {
341 methref = methoddef.MakeVarArgSignature (opt);
342 vararg_sig_table [sig] = methref;
349 /// Define a global method
351 public void Define (CodeGen code_gen)
358 WriteCode (code_gen, methoddef);
360 //code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
365 /// Define a member method
367 public void Define (CodeGen code_gen, TypeDef typedef)
372 Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
373 WriteCode (code_gen, methoddef);
375 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
378 public void AddInstr (IInstr instr)
380 inst_list.Add (instr);
383 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
389 methoddef.DeclareEntryPoint ();
391 if (local_list.Count > 0) {
392 int ec = code_gen.Report.ErrorCount;
393 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
396 foreach (Local local in local_list)
397 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
399 if (code_gen.Report.ErrorCount > ec)
405 methoddef.AddLocals (local_array, init_locals);
408 /// Nothing seems to work if maxstack is not set,
409 /// i need to find out if this NEEDs to be set
410 /// and what its default value should be
413 methoddef.SetMaxStack (max_stack);
415 /// Add the custrom attributes to this method
416 if (customattr_list != null)
417 foreach (CustomAttr customattr in customattr_list)
418 customattr.AddTo (code_gen, methoddef);
421 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
422 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
426 if (inst_list.Count < 1)
429 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
430 /// Create all the labels
431 /// TODO: Most labels don't actually need to be created so we could
432 /// probably only create the ones that need to be
433 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
434 label_table.Values.CopyTo (label_info, 0);
435 label_list.CopyTo (label_info, label_table.Count);
436 int previous_pos = -1;
437 LabelInfo previous_label = null;
438 Array.Sort (label_info);
440 foreach (LabelInfo label in label_info) {
441 if (label.UseOffset) {
442 label.Define (new PEAPI.CILLabel (label.Offset));
445 if (label.Pos == previous_pos)
446 label.Label = previous_label.Label;
448 label.Define (cil.NewLabel ());
450 previous_label = label;
451 previous_pos = label.Pos;
454 // Set all the label refs
455 foreach (LabelInfo label in labelref_table.Values) {
456 LabelInfo def = (LabelInfo) label_table[label.Name];
458 code_gen.Report.Error ("Undefined Label: " + label);
461 label.Label = def.Label;
465 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
467 for (int i=0; i<inst_list.Count; i++) {
468 IInstr instr = (IInstr) inst_list[i];
469 if (next_label_pos == i) {
470 cil.CodeLabel (label_info[label_pos].Label);
471 if (label_pos < label_info.Length) {
472 while (next_label_pos == i && ++label_pos < label_info.Length) {
473 if (label_info[label_pos].UseOffset)
474 cil.CodeLabel (label_info[label_pos].Label);
475 next_label_pos = label_info[label_pos].Pos;
478 if (label_pos >= label_info.Length)
482 source.MarkLocation (instr.Location.line, cil.Offset);
483 instr.Emit (code_gen, this, cil);
487 source.MarkLocation (source.EndLine, cil.Offset);
489 // Generic type parameters
490 if (typar_list != null) {
492 foreach (GenericInfo gi in typar_list) {
493 PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
494 if (gi.ConstraintList != null) {
495 foreach (ITypeRef cnst in gi.ConstraintList) {
496 cnst.Resolve (code_gen);
497 gp.AddConstraint (cnst.PeapiType);
504 public LabelInfo AddLabel (string name)
506 LabelInfo label_info = (LabelInfo) label_table[name];
507 if (label_info != null)
509 label_info = new LabelInfo (name, inst_list.Count);
510 label_table.Add (name, label_info);
514 public LabelInfo AddLabelRef (string name)
516 LabelInfo label_info = (LabelInfo) label_table[name];
517 if (label_info != null)
519 label_info = (LabelInfo) labelref_table[name];
520 if (label_info != null)
522 label_info = new LabelInfo (name, -1);
523 labelref_table.Add (name, label_info);
527 public LabelInfo AddLabel (int offset)
529 // We go pos + 1 so this line is not counted
530 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
531 label_list.Add (label_info);
535 public LabelInfo AddLabel ()
537 int pos = inst_list.Count;
538 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
539 label_list.Add (label_info);
543 public PEAPI.CILLabel GetLabelDef (string name)
545 LabelInfo label_info = (LabelInfo) label_table[name];
547 return label_info.Label;
550 public PEAPI.CILLabel GetLabelDef (int pos)
552 foreach (LabelInfo li in label_list) {
559 private void CreateSignature ()
562 signature = CreateVarargSignature (RetType, name, param_list);
564 signature = CreateSignature (RetType, name, param_list);
567 public static string CreateSignature (ITypeRef RetType, string name, IList param_list)
569 StringBuilder builder = new StringBuilder ();
571 builder.Append (RetType.FullName);
572 builder.Append (" ");
573 builder.Append (name);
574 builder.Append ('(');
576 if (param_list != null) {
578 foreach (ParamDef paramdef in param_list) {
580 builder.Append (',');
581 builder.Append (paramdef.TypeName);
585 builder.Append (')');
587 return builder.ToString ();
590 public static string CreateVarargSignature (ITypeRef RetType, string name, IList param_list)
592 StringBuilder builder = new StringBuilder ();
593 ParamDef last = null;
595 builder.Append (RetType.FullName);
596 builder.Append (" ");
597 builder.Append (name);
598 builder.Append ('(');
601 if (param_list != null) {
602 foreach (ParamDef paramdef in param_list) {
604 builder.Append (',');
605 builder.Append (paramdef.TypeName);
608 last = (ParamDef) param_list[param_list.Count - 1];
612 if (last == null || !last.IsSentinel ()) {
614 builder.Append (',');
615 builder.Append ("...");
618 builder.Append (')');
620 return builder.ToString ();
623 public static string CreateVarargSignature (ITypeRef RetType, string name, ITypeRef [] param_list)
625 StringBuilder builder = new StringBuilder ();
626 ITypeRef last = null;
628 builder.Append (RetType.FullName);
629 builder.Append (" ");
630 builder.Append (name);
631 builder.Append ('(');
634 if (param_list != null && param_list.Length > 0) {
635 foreach (ITypeRef param in param_list) {
637 builder.Append (',');
638 builder.Append (param.FullName);
641 if (param is SentinelTypeRef)
647 if (last == null || !(last is SentinelTypeRef)) {
649 builder.Append (',');
650 builder.Append ("...");
653 builder.Append (')');
655 return builder.ToString ();
658 public static string CreateSignature (ITypeRef RetType, string name, ITypeRef[] param_list)
660 StringBuilder builder = new StringBuilder ();
662 builder.Append (RetType.FullName);
663 builder.Append (" ");
664 builder.Append (name);
665 builder.Append ('(');
667 if (param_list != null) {
669 foreach (ITypeRef param in param_list) {
671 builder.Append (',');
672 builder.Append (param.FullName);
674 if (param is SentinelTypeRef)
678 builder.Append (')');
680 return builder.ToString ();
683 private void FixAttributes ()
685 if (name == ".ctor" || name == ".cctor")
686 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
687 // If methods aren't flagged as static they are instance
688 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
689 call_conv |= PEAPI.CallConv.Instance;