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 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 Hashtable named_param_table;
35 private ArrayList inst_list;
36 private ArrayList customattr_list;
37 private Hashtable label_table;
38 private Hashtable labelref_table;
39 private ArrayList label_list;
40 private PEAPI.MethodDef methoddef;
41 private bool entry_point;
42 private bool zero_init;
43 private bool is_resolved;
44 private bool is_defined;
45 private ArrayList local_list;
46 private Hashtable named_local_table;
47 private bool init_locals;
48 private int max_stack;
49 private bool pinvoke_info;
50 private ExternModule pinvoke_mod;
51 private string pinvoke_name;
52 private PEAPI.PInvokeAttr pinvoke_attr;
53 private SourceMethod source;
55 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
56 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
57 string name, ITypeRef ret_type, ArrayList param_list,
60 this.meth_attr = meth_attr;
61 this.call_conv = call_conv;
62 this.impl_attr = impl_attr;
64 this.ret_type = ret_type;
65 this.param_list = param_list;
67 inst_list = new ArrayList ();
68 customattr_list = new ArrayList ();
69 label_table = new Hashtable ();
70 labelref_table = new Hashtable ();
71 label_list = new ArrayList ();
72 local_list = new ArrayList ();
73 named_local_table = new Hashtable ();
74 named_param_table = new Hashtable ();
85 CreateNamedParamTable ();
87 codegen.BeginMethodDef (this);
89 if (codegen.SymbolWriter != null)
90 source = codegen.SymbolWriter.BeginMethod (this, start);
97 public string Signature {
98 get { return signature; }
101 public ITypeRef RetType {
102 get { return ret_type; }
105 public PEAPI.CallConv CallConv {
106 get { return call_conv; }
109 public PEAPI.MethodDef PeapiMethodDef {
110 get { return methoddef; }
113 public PEAPI.MethAttr Attributes {
114 get { return meth_attr; }
115 set { meth_attr = value; }
118 public bool IsVararg {
119 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
122 public bool IsStatic {
123 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
126 public bool IsVirtual {
127 get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
130 public bool IsAbstract {
131 get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
134 public ITypeRef[] ParamTypeList () {
136 if (param_list == null)
137 return new ITypeRef[0];
139 ITypeRef[] type_list = new ITypeRef[param_list.Count];
140 foreach (ParamDef param in param_list) {
141 type_list[count++] = param.Type;
146 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
149 this.pinvoke_attr = pinvoke_attr;
150 this.pinvoke_mod = pinvoke_mod;
151 this.pinvoke_name = pinvoke_name;
155 public void AddGenericParam (string id)
157 if (typar_list == null)
158 typar_list = new ArrayList ();
160 GenericInfo gi = new GenericInfo ();
166 public void AddGenericConstraint (int index, ITypeRef constraint)
168 GenericInfo gi = (GenericInfo) typar_list[index];
170 if (gi.ConstraintList == null)
171 gi.ConstraintList = new ArrayList ();
172 gi.ConstraintList.Add (constraint);
175 public void AddLocals (ArrayList local_list)
177 int slot_pos = this.local_list.Count;
179 foreach (Local local in local_list) {
180 if (local.Slot == -1) {
181 local.Slot = slot_pos;
184 if (local.Name == null)
186 named_local_table.Add (local.Name, local);
189 this.local_list.AddRange (local_list);
192 public Local GetNamedLocal (string name)
194 return (Local) named_local_table[name];
197 public int GetNamedLocalSlot (string name)
199 Local local = (Local) named_local_table[name];
204 public int GetNamedParamPos (string name)
206 int pos = (int) named_param_table[name];
211 public void InitLocals ()
216 public void EntryPoint ()
221 public void ZeroInit ()
226 public void SetMaxStack (int max_stack)
228 this.max_stack = max_stack;
231 public void AddCustomAttr (CustomAttr customattr)
233 customattr_list.Add (customattr);
236 public PEAPI.MethodDef Resolve (CodeGen code_gen)
241 PEAPI.Param [] param_array = GenerateParams (code_gen);
243 ret_type.Resolve (code_gen);
245 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
246 name, ret_type.PeapiType, param_array);
248 methoddef.AddCallConv (call_conv);
254 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
259 PEAPI.Param [] param_array = GenerateParams (code_gen);
261 ret_type.Resolve (code_gen);
263 methoddef = classdef.AddMethod (meth_attr, impl_attr,
264 name, ret_type.PeapiType, param_array);
266 methoddef.AddCallConv (call_conv);
272 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
274 PEAPI.Param[] param_array;
276 if (param_list != null && param_list.Count > 0) {
277 int param_count = param_list.Count;
279 // Remove the last param if its the sentinel, not sure what
280 // should happen with more then one sentinel
281 ParamDef last = (ParamDef) param_list [param_count-1];
282 if (last.IsSentinel ())
285 param_array = new PEAPI.Param [param_count];
286 for (int i = 0; i < param_count; i++) {
287 ParamDef paramdef = (ParamDef) param_list [i];
288 paramdef.Define (code_gen);
289 param_array [i] = paramdef.PeapiParam;
293 param_array = new PEAPI.Param [0];
299 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
302 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
304 PEAPI.MethodRef methref = null;
305 StringBuilder sigbuilder = new StringBuilder ();
307 foreach (PEAPI.Type t in opt)
308 sigbuilder.Append (opt + ", ");
309 sig = sigbuilder.ToString ();
311 if (vararg_sig_table == null) {
312 vararg_sig_table = new Hashtable ();
314 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
317 if (methref == null) {
318 methref = methoddef.MakeVarArgSignature (opt);
319 vararg_sig_table [sig] = methref;
326 /// Define a global method
328 public void Define (CodeGen code_gen)
335 WriteCode (code_gen, methoddef);
337 //code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
342 /// Define a member method
344 public void Define (CodeGen code_gen, TypeDef typedef)
349 Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
350 WriteCode (code_gen, methoddef);
352 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
355 public void AddInstr (IInstr instr)
357 inst_list.Add (instr);
360 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
363 methoddef.DeclareEntryPoint ();
365 if (local_list.Count > 0) {
366 int ec = code_gen.Report.ErrorCount;
367 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
370 foreach (Local local in local_list)
371 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
373 if (code_gen.Report.ErrorCount > ec)
379 methoddef.AddLocals (local_array, init_locals);
382 /// Nothing seems to work if maxstack is not set,
383 /// i need to find out if this NEEDs to be set
384 /// and what its default value should be
387 methoddef.SetMaxStack (max_stack);
389 /// Add the custrom attributes to this method
390 foreach (CustomAttr customattr in customattr_list)
391 customattr.AddTo (code_gen, methoddef);
394 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
395 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
399 if (inst_list.Count < 1)
402 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
403 /// Create all the labels
404 /// TODO: Most labels don't actually need to be created so we could
405 /// probably only create the ones that need to be
406 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
407 label_table.Values.CopyTo (label_info, 0);
408 label_list.CopyTo (label_info, label_table.Count);
409 int previous_pos = -1;
410 LabelInfo previous_label = null;
411 Array.Sort (label_info);
413 foreach (LabelInfo label in label_info) {
414 if (label.UseOffset) {
415 label.Define (new PEAPI.CILLabel (label.Offset));
418 if (label.Pos == previous_pos)
419 label.Label = previous_label.Label;
421 label.Define (cil.NewLabel ());
423 previous_label = label;
424 previous_pos = label.Pos;
427 // Set all the label refs
428 foreach (LabelInfo label in labelref_table.Values) {
429 LabelInfo def = (LabelInfo) label_table[label.Name];
431 code_gen.Report.Error ("Undefined Label: " + label);
434 label.Label = def.Label;
438 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
440 for (int i=0; i<inst_list.Count; i++) {
441 IInstr instr = (IInstr) inst_list[i];
442 if (next_label_pos == i) {
443 cil.CodeLabel (label_info[label_pos].Label);
444 if (label_pos < label_info.Length) {
445 while (next_label_pos == i && ++label_pos < label_info.Length) {
446 if (label_info[label_pos].UseOffset)
447 cil.CodeLabel (label_info[label_pos].Label);
448 next_label_pos = label_info[label_pos].Pos;
451 if (label_pos >= label_info.Length)
455 source.MarkLocation (instr.Location.line, cil.Offset);
456 instr.Emit (code_gen, this, cil);
460 source.MarkLocation (source.EndLine, cil.Offset);
462 // Generic type parameters
463 if (typar_list != null) {
465 foreach (GenericInfo gi in typar_list) {
466 PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
467 if (gi.ConstraintList != null) {
468 foreach (ITypeRef cnst in gi.ConstraintList) {
469 cnst.Resolve (code_gen);
470 gp.AddConstraint (cnst.PeapiType);
477 public LabelInfo AddLabel (string name)
479 LabelInfo label_info = (LabelInfo) label_table[name];
480 if (label_info != null)
482 label_info = new LabelInfo (name, inst_list.Count);
483 label_table.Add (name, label_info);
487 public LabelInfo AddLabelRef (string name)
489 LabelInfo label_info = (LabelInfo) label_table[name];
490 if (label_info != null)
492 label_info = (LabelInfo) labelref_table[name];
493 if (label_info != null)
495 label_info = new LabelInfo (name, -1);
496 labelref_table.Add (name, label_info);
500 public LabelInfo AddLabel (int offset)
502 // We go pos + 1 so this line is not counted
503 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
504 label_list.Add (label_info);
508 public LabelInfo AddLabel ()
510 int pos = inst_list.Count;
511 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
512 label_list.Add (label_info);
516 public PEAPI.CILLabel GetLabelDef (string name)
518 LabelInfo label_info = (LabelInfo) label_table[name];
520 return label_info.Label;
523 public PEAPI.CILLabel GetLabelDef (int pos)
525 foreach (LabelInfo li in label_list) {
532 private void CreateSignature ()
535 signature = CreateVarargSignature (name, param_list);
537 signature = CreateSignature (name, param_list);
540 public static string CreateSignature (string name, IList param_list)
542 StringBuilder builder = new StringBuilder ();
544 builder.Append (name);
545 builder.Append ('(');
547 if (param_list != null) {
549 foreach (ParamDef paramdef in param_list) {
551 builder.Append (',');
552 builder.Append (paramdef.TypeName);
556 builder.Append (')');
558 return builder.ToString ();
561 public static string CreateVarargSignature (string name, IList param_list)
563 StringBuilder builder = new StringBuilder ();
564 ParamDef last = null;
566 builder.Append (name);
567 builder.Append ('(');
570 if (param_list != null) {
571 foreach (ParamDef paramdef in param_list) {
573 builder.Append (',');
574 builder.Append (paramdef.TypeName);
577 last = (ParamDef) param_list[param_list.Count - 1];
581 if (last == null || !last.IsSentinel ()) {
583 builder.Append (',');
584 builder.Append ("...");
587 builder.Append (')');
589 return builder.ToString ();
592 public static string CreateVarargSignature (string name, ITypeRef [] param_list)
594 StringBuilder builder = new StringBuilder ();
595 ITypeRef last = null;
597 builder.Append (name);
598 builder.Append ('(');
601 if (param_list != null && param_list.Length > 0) {
602 foreach (ITypeRef param in param_list) {
604 builder.Append (',');
605 builder.Append (param.FullName);
608 if (param is SentinelTypeRef)
614 if (last == null || !(last is SentinelTypeRef)) {
616 builder.Append (',');
617 builder.Append ("...");
620 builder.Append (')');
622 return builder.ToString ();
625 public static string CreateSignature (string name, ITypeRef[] param_list)
627 StringBuilder builder = new StringBuilder ();
629 builder.Append (name);
630 builder.Append ('(');
632 if (param_list != null) {
634 foreach (ITypeRef param in param_list) {
636 builder.Append (',');
637 builder.Append (param.FullName);
639 if (param is SentinelTypeRef)
643 builder.Append (')');
645 return builder.ToString ();
648 private void CreateNamedParamTable ()
650 if (param_list == null)
653 int count = (IsStatic ? 0 : 1);
655 foreach (ParamDef param in param_list) {
656 if (param.Name != null)
657 named_param_table.Add (param.Name, count);
662 private void FixAttributes ()
664 if (name == ".ctor" || name == ".cctor")
665 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
666 // If methods aren't flagged as static they are instance
667 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
668 call_conv |= PEAPI.CallConv.Instance;