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;
54 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
55 PEAPI.ImplAttr impl_attr, string name,
56 ITypeRef ret_type, ArrayList param_list)
58 this.meth_attr = meth_attr;
59 this.call_conv = call_conv;
60 this.impl_attr = impl_attr;
62 this.ret_type = ret_type;
63 this.param_list = param_list;
65 inst_list = new ArrayList ();
66 customattr_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 ();
72 named_param_table = new Hashtable ();
83 CreateNamedParamTable ();
90 public string Signature {
91 get { return signature; }
94 public ITypeRef RetType {
95 get { return ret_type; }
98 public PEAPI.CallConv CallConv {
99 get { return call_conv; }
102 public PEAPI.MethodDef PeapiMethodDef {
103 get { return methoddef; }
106 public bool IsVararg {
107 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
110 public ITypeRef[] ParamTypeList () {
112 if (param_list == null)
113 return new ITypeRef[0];
115 ITypeRef[] type_list = new ITypeRef[param_list.Count];
116 foreach (ParamDef param in param_list) {
117 type_list[count++] = param.Type;
122 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
125 this.pinvoke_attr = pinvoke_attr;
126 this.pinvoke_mod = pinvoke_mod;
127 this.pinvoke_name = pinvoke_name;
131 public void AddGenericParam (string id)
133 if (typar_list == null)
134 typar_list = new ArrayList ();
136 GenericInfo gi = new GenericInfo ();
142 public void AddGenericConstraint (int index, ITypeRef constraint)
144 GenericInfo gi = (GenericInfo) typar_list[index];
146 if (gi.ConstraintList == null)
147 gi.ConstraintList = new ArrayList ();
148 gi.ConstraintList.Add (constraint);
151 public void AddLocals (ArrayList local_list)
153 int slot_pos = this.local_list.Count;
155 foreach (Local local in local_list) {
156 if (local.Slot == -1) {
157 local.Slot = slot_pos;
160 if (local.Name == null)
162 named_local_table.Add (local.Name, local);
165 this.local_list.AddRange (local_list);
168 public Local GetNamedLocal (string name)
170 return (Local) named_local_table[name];
173 public int GetNamedLocalSlot (string name)
175 Local local = (Local) named_local_table[name];
180 public int GetNamedParamPos (string name)
182 int pos = (int) named_param_table[name];
187 public void InitLocals ()
192 public void EntryPoint ()
197 public void ZeroInit ()
202 public void SetMaxStack (int max_stack)
204 this.max_stack = max_stack;
207 public void AddCustomAttr (CustomAttr customattr)
209 customattr_list.Add (customattr);
212 public PEAPI.MethodDef Resolve (CodeGen code_gen)
217 PEAPI.Param [] param_array = GenerateParams (code_gen);
219 ret_type.Resolve (code_gen);
221 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
222 name, ret_type.PeapiType, param_array);
224 methoddef.AddCallConv (call_conv);
230 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
235 PEAPI.Param [] param_array = GenerateParams (code_gen);
237 ret_type.Resolve (code_gen);
239 methoddef = classdef.AddMethod (meth_attr, impl_attr,
240 name, ret_type.PeapiType, param_array);
242 methoddef.AddCallConv (call_conv);
248 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
250 PEAPI.Param[] param_array;
252 if (param_list != null && param_list.Count > 0) {
253 int param_count = param_list.Count;
255 // Remove the last param if its the sentinel, not sure what
256 // should happen with more then one sentinel
257 ParamDef last = (ParamDef) param_list [param_count-1];
258 if (last.IsSentinel ())
261 param_array = new PEAPI.Param [param_count];
262 for (int i = 0; i < param_count; i++) {
263 ParamDef paramdef = (ParamDef) param_list [i];
264 paramdef.Define (code_gen);
265 param_array [i] = paramdef.PeapiParam;
269 param_array = new PEAPI.Param [0];
275 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
278 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
280 PEAPI.MethodRef methref = null;
281 StringBuilder sigbuilder = new StringBuilder ();
283 foreach (PEAPI.Type t in opt)
284 sigbuilder.Append (opt + ", ");
285 sig = sigbuilder.ToString ();
287 if (vararg_sig_table == null) {
288 vararg_sig_table = new Hashtable ();
290 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
293 if (methref == null) {
294 methref = methoddef.MakeVarArgSignature (opt);
295 vararg_sig_table [sig] = methref;
302 /// Define a global method
304 public void Define (CodeGen code_gen)
311 WriteCode (code_gen, methoddef);
313 code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
318 /// Define a member method
320 public void Define (CodeGen code_gen, TypeDef typedef)
325 Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
326 WriteCode (code_gen, methoddef);
328 code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
331 public void AddInstr (IInstr instr)
333 inst_list.Add (instr);
336 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
339 methoddef.DeclareEntryPoint ();
341 if (local_list != null) {
342 int ec = code_gen.Report.ErrorCount;
343 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
346 foreach (Local local in local_list)
347 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
349 if (code_gen.Report.ErrorCount > ec)
355 methoddef.AddLocals (local_array, init_locals);
358 /// Nothing seems to work if maxstack is not set,
359 /// i need to find out if this NEEDs to be set
360 /// and what its default value should be
363 methoddef.SetMaxStack (max_stack);
365 /// Add the custrom attributes to this method
366 foreach (CustomAttr customattr in customattr_list)
367 customattr.AddTo (code_gen, methoddef);
370 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
371 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
375 if (inst_list.Count < 1)
378 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
379 /// Create all the labels
380 /// TODO: Most labels don't actually need to be created so we could
381 /// probably only create the ones that need to be
382 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
383 label_table.Values.CopyTo (label_info, 0);
384 label_list.CopyTo (label_info, label_table.Count);
385 int previous_pos = -1;
386 LabelInfo previous_label = null;
387 Array.Sort (label_info);
389 foreach (LabelInfo label in label_info) {
390 if (label.UseOffset) {
391 label.Define (new PEAPI.CILLabel (label.Offset));
394 if (label.Pos == previous_pos)
395 label.Label = previous_label.Label;
397 label.Define (cil.NewLabel ());
399 previous_label = label;
400 previous_pos = label.Pos;
403 // Set all the label refs
404 foreach (LabelInfo label in labelref_table.Values) {
405 LabelInfo def = (LabelInfo) label_table[label.Name];
407 code_gen.Report.Error ("Undefined Label: " + label);
410 label.Label = def.Label;
414 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
416 for (int i=0; i<inst_list.Count; i++) {
417 IInstr instr = (IInstr) inst_list[i];
418 if (next_label_pos == i) {
419 cil.CodeLabel (label_info[label_pos].Label);
420 if (label_pos < label_info.Length) {
421 while (next_label_pos == i && ++label_pos < label_info.Length) {
422 if (label_info[label_pos].UseOffset)
423 cil.CodeLabel (label_info[label_pos].Label);
424 next_label_pos = label_info[label_pos].Pos;
427 if (label_pos >= label_info.Length)
430 instr.Emit (code_gen, this, cil);
433 // Generic type parameters
434 if (typar_list != null) {
436 foreach (GenericInfo gi in typar_list) {
437 PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
438 if (gi.ConstraintList != null) {
439 foreach (ITypeRef cnst in gi.ConstraintList) {
440 cnst.Resolve (code_gen);
441 gp.AddConstraint (cnst.PeapiType);
448 public LabelInfo AddLabel (string name)
450 LabelInfo label_info = (LabelInfo) label_table[name];
451 if (label_info != null)
453 label_info = new LabelInfo (name, inst_list.Count);
454 label_table.Add (name, label_info);
458 public LabelInfo AddLabelRef (string name)
460 LabelInfo label_info = (LabelInfo) label_table[name];
461 if (label_info != null)
463 label_info = (LabelInfo) labelref_table[name];
464 if (label_info != null)
466 label_info = new LabelInfo (name, -1);
467 labelref_table.Add (name, label_info);
471 public LabelInfo AddLabel (int offset)
473 // We go pos + 1 so this line is not counted
474 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
475 label_list.Add (label_info);
479 public LabelInfo AddLabel ()
481 int pos = inst_list.Count;
482 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
483 label_list.Add (label_info);
487 public PEAPI.CILLabel GetLabelDef (string name)
489 LabelInfo label_info = (LabelInfo) label_table[name];
491 return label_info.Label;
494 public PEAPI.CILLabel GetLabelDef (int pos)
496 foreach (LabelInfo li in label_list) {
503 private void CreateSignature ()
506 signature = CreateVarargSignature (name, param_list);
508 signature = CreateSignature (name, param_list);
511 public static string CreateSignature (string name, IList param_list)
513 StringBuilder builder = new StringBuilder ();
515 builder.Append (name);
516 builder.Append ('(');
518 if (param_list != null) {
520 foreach (ParamDef paramdef in param_list) {
522 builder.Append (',');
523 builder.Append (paramdef.TypeName);
527 builder.Append (')');
529 return builder.ToString ();
532 public static string CreateVarargSignature (string name, IList param_list)
534 StringBuilder builder = new StringBuilder ();
535 ParamDef last = null;
537 builder.Append (name);
538 builder.Append ('(');
541 if (param_list != null) {
542 foreach (ParamDef paramdef in param_list) {
544 builder.Append (',');
545 builder.Append (paramdef.TypeName);
548 last = (ParamDef) param_list[param_list.Count - 1];
552 if (last == null || !last.IsSentinel ()) {
554 builder.Append (',');
555 builder.Append ("...");
558 builder.Append (')');
560 return builder.ToString ();
563 public static string CreateVarargSignature (string name, ITypeRef [] param_list)
565 StringBuilder builder = new StringBuilder ();
566 ITypeRef last = null;
568 builder.Append (name);
569 builder.Append ('(');
572 if (param_list != null && param_list.Length > 0) {
573 foreach (ITypeRef param in param_list) {
575 builder.Append (',');
576 builder.Append (param.FullName);
579 if (param is SentinelTypeRef)
585 if (last == null || !(last is SentinelTypeRef)) {
587 builder.Append (',');
588 builder.Append ("...");
591 builder.Append (')');
593 return builder.ToString ();
596 public static string CreateSignature (string name, ITypeRef[] param_list)
598 StringBuilder builder = new StringBuilder ();
600 builder.Append (name);
601 builder.Append ('(');
603 if (param_list != null) {
605 foreach (ITypeRef param in param_list) {
607 builder.Append (',');
608 builder.Append (param.FullName);
610 if (param is SentinelTypeRef)
614 builder.Append (')');
616 return builder.ToString ();
619 private void CreateNamedParamTable ()
621 if (param_list == null)
625 foreach (ParamDef param in param_list) {
626 if (param.Name != null)
627 named_param_table.Add (param.Name, count);
632 private void FixAttributes ()
634 if (name == ".ctor" || name == ".cctor")
635 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
636 // If methods aren't flagged as static they are instance
637 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
638 call_conv |= PEAPI.CallConv.Instance;