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, IDeclSecurityTarget {
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 ArrayList declsecurity_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;
54 private PEAPI.NativeType ret_native_type;
56 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
57 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
58 string name, ITypeRef ret_type, ArrayList param_list,
61 this.meth_attr = meth_attr;
62 this.call_conv = call_conv;
63 this.impl_attr = impl_attr;
65 this.ret_type = ret_type;
66 this.param_list = param_list;
68 inst_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 ();
85 codegen.BeginMethodDef (this);
87 if (codegen.SymbolWriter != null)
88 source = codegen.SymbolWriter.BeginMethod (this, start);
95 public string Signature {
96 get { return signature; }
99 public ITypeRef RetType {
100 get { return ret_type; }
103 public PEAPI.CallConv CallConv {
104 get { return call_conv; }
107 public PEAPI.MethodDef PeapiMethodDef {
108 get { return methoddef; }
111 public PEAPI.MethAttr Attributes {
112 get { return meth_attr; }
113 set { meth_attr = value; }
116 public bool IsVararg {
117 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
120 public bool IsStatic {
121 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
124 public bool IsVirtual {
125 get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
128 public bool IsAbstract {
129 get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
132 public ITypeRef[] ParamTypeList () {
134 if (param_list == null)
135 return new ITypeRef[0];
137 ITypeRef[] type_list = new ITypeRef[param_list.Count];
138 foreach (ParamDef param in param_list) {
139 type_list[count++] = param.Type;
144 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
147 this.pinvoke_attr = pinvoke_attr;
148 this.pinvoke_mod = pinvoke_mod;
149 this.pinvoke_name = pinvoke_name;
153 public void AddGenericParam (string id)
155 if (typar_list == null)
156 typar_list = new ArrayList ();
158 GenericInfo gi = new GenericInfo ();
164 public void AddGenericConstraint (int index, ITypeRef constraint)
166 GenericInfo gi = (GenericInfo) typar_list[index];
168 if (gi.ConstraintList == null)
169 gi.ConstraintList = new ArrayList ();
170 gi.ConstraintList.Add (constraint);
173 public void AddParamDefaultValue (int index, PEAPI.Constant defval)
175 if (param_list [index] != null) {
176 ((ParamDef)param_list [index]).AddDefaultValue (defval);
180 public void AddCustomAttribute (CustomAttr customattr)
182 if (customattr_list == null)
183 customattr_list = new ArrayList ();
185 customattr_list.Add (customattr);
188 public void AddDeclSecurity (DeclSecurity declsecurity)
190 if (declsecurity_list == null)
191 declsecurity_list = new ArrayList ();
193 declsecurity_list.Add (declsecurity);
196 public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
198 this.ret_native_type = native_type;
201 public void AddLocals (ArrayList local_list)
203 int slot_pos = this.local_list.Count;
205 foreach (Local local in local_list) {
206 if (local.Slot == -1) {
207 local.Slot = slot_pos;
210 if (local.Name == null)
212 if(!named_local_table.Contains(local.Name))
213 named_local_table.Add (local.Name, local);
216 this.local_list.AddRange (local_list);
219 public Local GetNamedLocal (string name)
221 return (Local) named_local_table[name];
224 public int GetNamedLocalSlot (string name)
226 Local local = (Local) named_local_table[name];
231 public int GetNamedParamPos (string name)
236 foreach (ParamDef param in param_list) {
238 if (param.Name.CompareTo (name) == 0)
245 public ParamDef GetParam (int index)
247 if (param_list [index] != null)
248 return (ParamDef)param_list [index];
253 public void InitLocals ()
258 public void EntryPoint ()
261 throw new Exception ("Non-static method as entrypoint.");
265 public void ZeroInit ()
270 public void SetMaxStack (int max_stack)
272 this.max_stack = max_stack;
275 public PEAPI.MethodDef Resolve (CodeGen code_gen)
277 return Resolve (code_gen, null);
280 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
285 PEAPI.Param [] param_array = GenerateParams (code_gen);
287 ret_type.Resolve (code_gen);
289 if (classdef == null)
290 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
291 name, ret_type.PeapiType, param_array);
293 methoddef = classdef.AddMethod (meth_attr, impl_attr,
294 name, ret_type.PeapiType, param_array);
296 methoddef.AddCallConv (call_conv);
298 if (ret_native_type != null)
299 methoddef.AddRetTypeMarshallInfo (ret_native_type);
306 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
308 PEAPI.Param[] param_array;
310 if (param_list != null && param_list.Count > 0) {
311 int param_count = param_list.Count;
313 // Remove the last param if its the sentinel, not sure what
314 // should happen with more then one sentinel
315 ParamDef last = (ParamDef) param_list [param_count-1];
316 if (last.IsSentinel ())
319 param_array = new PEAPI.Param [param_count];
320 for (int i = 0; i < param_count; i++) {
321 ParamDef paramdef = (ParamDef) param_list [i];
322 paramdef.Define (code_gen);
323 param_array [i] = paramdef.PeapiParam;
327 param_array = new PEAPI.Param [0];
333 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
336 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
338 PEAPI.MethodRef methref = null;
339 StringBuilder sigbuilder = new StringBuilder ();
341 foreach (PEAPI.Type t in opt)
342 sigbuilder.Append (opt + ", ");
343 sig = sigbuilder.ToString ();
345 if (vararg_sig_table == null) {
346 vararg_sig_table = new Hashtable ();
348 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
351 if (methref == null) {
352 methref = methoddef.MakeVarArgSignature (opt);
353 vararg_sig_table [sig] = methref;
360 /// Define a global method
362 public void Define (CodeGen code_gen)
369 WriteCode (code_gen, methoddef);
371 //code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
376 /// Define a member method
378 public void Define (CodeGen code_gen, TypeDef typedef)
383 Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
384 WriteCode (code_gen, methoddef);
386 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
389 public void AddInstr (IInstr instr)
391 inst_list.Add (instr);
394 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
396 /// Add the custrom attributes to this method
397 if (customattr_list != null)
398 foreach (CustomAttr customattr in customattr_list) {
399 customattr.AddTo (code_gen, methoddef);
400 if (customattr.IsSuppressUnmanaged (code_gen))
401 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
404 /// Add declarative security to this method
405 if (declsecurity_list != null) {
406 foreach (DeclSecurity declsecurity in declsecurity_list)
407 declsecurity.AddTo (code_gen, methoddef);
409 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
416 methoddef.DeclareEntryPoint ();
418 if (local_list.Count > 0) {
419 int ec = code_gen.Report.ErrorCount;
420 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
423 foreach (Local local in local_list)
424 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
426 if (code_gen.Report.ErrorCount > ec)
432 methoddef.AddLocals (local_array, init_locals);
435 /// Nothing seems to work if maxstack is not set,
436 /// i need to find out if this NEEDs to be set
437 /// and what its default value should be
440 methoddef.SetMaxStack (max_stack);
443 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
444 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
447 if (inst_list.Count < 1)
450 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
451 /// Create all the labels
452 /// TODO: Most labels don't actually need to be created so we could
453 /// probably only create the ones that need to be
454 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
455 label_table.Values.CopyTo (label_info, 0);
456 label_list.CopyTo (label_info, label_table.Count);
457 int previous_pos = -1;
458 LabelInfo previous_label = null;
459 Array.Sort (label_info);
461 foreach (LabelInfo label in label_info) {
462 if (label.UseOffset) {
463 label.Define (new PEAPI.CILLabel (label.Offset));
466 if (label.Pos == previous_pos)
467 label.Label = previous_label.Label;
469 label.Define (cil.NewLabel ());
471 previous_label = label;
472 previous_pos = label.Pos;
475 // Set all the label refs
476 foreach (LabelInfo label in labelref_table.Values) {
477 LabelInfo def = (LabelInfo) label_table[label.Name];
479 code_gen.Report.Error ("Undefined Label: " + label);
482 label.Label = def.Label;
486 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
488 for (int i=0; i<inst_list.Count; i++) {
489 IInstr instr = (IInstr) inst_list[i];
490 if (next_label_pos == i) {
491 cil.CodeLabel (label_info[label_pos].Label);
492 if (label_pos < label_info.Length) {
493 while (next_label_pos == i && ++label_pos < label_info.Length) {
494 if (label_info[label_pos].UseOffset)
495 cil.CodeLabel (label_info[label_pos].Label);
496 next_label_pos = label_info[label_pos].Pos;
499 if (label_pos >= label_info.Length)
503 source.MarkLocation (instr.Location.line, cil.Offset);
504 instr.Emit (code_gen, this, cil);
508 source.MarkLocation (source.EndLine, cil.Offset);
510 // Generic type parameters
511 if (typar_list != null) {
513 foreach (GenericInfo gi in typar_list) {
514 PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
515 if (gi.ConstraintList != null) {
516 foreach (ITypeRef cnst in gi.ConstraintList) {
517 cnst.Resolve (code_gen);
518 gp.AddConstraint (cnst.PeapiType);
525 public LabelInfo AddLabel (string name)
527 LabelInfo label_info = (LabelInfo) label_table[name];
528 if (label_info != null)
530 label_info = new LabelInfo (name, inst_list.Count);
531 label_table.Add (name, label_info);
535 public LabelInfo AddLabelRef (string name)
537 LabelInfo label_info = (LabelInfo) label_table[name];
538 if (label_info != null)
540 label_info = (LabelInfo) labelref_table[name];
541 if (label_info != null)
543 label_info = new LabelInfo (name, -1);
544 labelref_table.Add (name, label_info);
548 public LabelInfo AddLabel (int offset)
550 // We go pos + 1 so this line is not counted
551 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
552 label_list.Add (label_info);
556 public LabelInfo AddLabel ()
558 int pos = inst_list.Count;
559 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
560 label_list.Add (label_info);
564 public PEAPI.CILLabel GetLabelDef (string name)
566 LabelInfo label_info = (LabelInfo) label_table[name];
568 return label_info.Label;
571 public PEAPI.CILLabel GetLabelDef (int pos)
573 foreach (LabelInfo li in label_list) {
580 private void CreateSignature ()
583 signature = CreateVarargSignature (RetType, name, param_list);
585 signature = CreateSignature (RetType, name, param_list);
588 public static string CreateSignature (ITypeRef RetType, string name, IList param_list)
590 StringBuilder builder = new StringBuilder ();
592 builder.Append (RetType.FullName);
593 builder.Append (" ");
594 builder.Append (name);
595 builder.Append ('(');
597 if (param_list != null) {
599 foreach (ParamDef paramdef in param_list) {
601 builder.Append (',');
602 builder.Append (paramdef.TypeName);
606 builder.Append (')');
608 return builder.ToString ();
611 public static string CreateVarargSignature (ITypeRef RetType, string name, IList param_list)
613 StringBuilder builder = new StringBuilder ();
614 ParamDef last = null;
616 builder.Append (RetType.FullName);
617 builder.Append (" ");
618 builder.Append (name);
619 builder.Append ('(');
622 if (param_list != null) {
623 foreach (ParamDef paramdef in param_list) {
625 builder.Append (',');
626 builder.Append (paramdef.TypeName);
629 last = (ParamDef) param_list[param_list.Count - 1];
633 if (last == null || !last.IsSentinel ()) {
635 builder.Append (',');
636 builder.Append ("...");
639 builder.Append (')');
641 return builder.ToString ();
644 public static string CreateVarargSignature (ITypeRef RetType, string name, ITypeRef [] param_list)
646 StringBuilder builder = new StringBuilder ();
647 ITypeRef last = null;
649 builder.Append (RetType.FullName);
650 builder.Append (" ");
651 builder.Append (name);
652 builder.Append ('(');
655 if (param_list != null && param_list.Length > 0) {
656 foreach (ITypeRef param in param_list) {
658 builder.Append (',');
659 builder.Append (param.FullName);
662 if (param is SentinelTypeRef)
668 if (last == null || !(last is SentinelTypeRef)) {
670 builder.Append (',');
671 builder.Append ("...");
674 builder.Append (')');
676 return builder.ToString ();
679 public static string CreateSignature (ITypeRef RetType, string name, ITypeRef[] param_list)
681 StringBuilder builder = new StringBuilder ();
683 builder.Append (RetType.FullName);
684 builder.Append (" ");
685 builder.Append (name);
686 builder.Append ('(');
688 if (param_list != null) {
690 foreach (ITypeRef param in param_list) {
692 builder.Append (',');
693 builder.Append (param.FullName);
695 if (param is SentinelTypeRef)
699 builder.Append (')');
701 return builder.ToString ();
704 private void FixAttributes ()
706 if (name == ".ctor" || name == ".cctor")
707 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
708 // If methods aren't flagged as static they are instance
709 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
710 call_conv |= PEAPI.CallConv.Instance;