2 // Mono.ILASM.MethodDef
5 // Jackson Harper (Jackson@LatitudeGeo.com)
7 // (C) 2003 Jackson Harper, All rights reserved
13 using System.Collections;
14 using System.Security;
16 namespace Mono.ILASM {
18 public class MethodDef : ICustomAttrTarget, IDeclSecurityTarget {
20 private PEAPI.MethAttr meth_attr;
21 private PEAPI.CallConv call_conv;
22 private PEAPI.ImplAttr impl_attr;
24 private string signature;
25 private Hashtable vararg_sig_table;
26 private ParamDef ret_param;
27 private ArrayList param_list;
28 private ArrayList inst_list;
29 private ArrayList customattr_list;
30 private DeclSecurity decl_sec;
31 private Hashtable label_table;
32 private Hashtable labelref_table;
33 private ArrayList label_list;
34 private PEAPI.MethodDef methoddef;
35 private bool entry_point;
36 private bool zero_init;
37 private bool is_resolved;
38 private bool is_defined;
39 private ArrayList local_list;
40 private Hashtable named_local_table;
41 private bool init_locals;
42 private int max_stack;
43 private bool pinvoke_info;
44 private ExternModule pinvoke_mod;
45 private string pinvoke_name;
46 private PEAPI.PInvokeAttr pinvoke_attr;
47 private SourceMethod source;
48 private TypeDef type_def;
49 private GenericParameters gen_params;
50 private Location start;
52 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
53 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
54 string name, BaseTypeRef ret_type, ArrayList param_list,
55 Location start, GenericParameters gen_params, TypeDef type_def)
57 this.meth_attr = meth_attr;
58 this.call_conv = call_conv;
59 this.impl_attr = impl_attr;
61 this.param_list = param_list;
62 this.type_def = type_def;
63 this.gen_params = gen_params;
64 this.ret_param = new ParamDef (PEAPI.ParamAttr.Default, "", ret_type);
65 this.start = (Location) start.Clone ();
67 inst_list = new ArrayList ();
68 label_table = new Hashtable ();
69 labelref_table = new Hashtable ();
70 label_list = new ArrayList ();
71 local_list = new ArrayList ();
72 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 BaseTypeRef RetType {
100 get { return ret_param.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 Location StartLocation {
133 get { return start; }
136 public DeclSecurity DeclSecurity {
138 if (decl_sec == null)
139 decl_sec = new DeclSecurity ();
144 public string FullName {
146 if (type_def == null)
148 return type_def.FullName + "." + Name;
152 public BaseTypeRef[] ParamTypeList () {
154 if (param_list == null)
155 return new BaseTypeRef[0];
157 BaseTypeRef[] type_list = new BaseTypeRef[param_list.Count];
158 foreach (ParamDef param in param_list) {
159 type_list[count++] = param.Type;
164 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
167 this.pinvoke_attr = pinvoke_attr;
168 this.pinvoke_mod = pinvoke_mod;
169 this.pinvoke_name = pinvoke_name;
173 public int GenParamCount {
174 get { return (gen_params != null ? gen_params.Count : 0); }
177 public GenericParameter GetGenericParam (string id)
179 if (gen_params == null)
182 return gen_params.GetGenericParam (id);
185 public GenericParameter GetGenericParam (int index)
187 if (gen_params == null || index < 0 || index >= gen_params.Count)
190 return gen_params [index];
193 public int GetGenericParamNum (string id)
195 if (gen_params == null)
198 return gen_params.GetGenericParamNum (id);
201 public void AddCustomAttribute (CustomAttr customattr)
203 if (customattr_list == null)
204 customattr_list = new ArrayList ();
206 customattr_list.Add (customattr);
209 public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
211 this.ret_param.AddMarshalInfo (native_type);
214 public void AddLocals (ArrayList local_list)
216 int slot_pos = this.local_list.Count;
218 foreach (Local local in local_list) {
219 if (local.Slot == -1) {
220 local.Slot = slot_pos;
223 if (local.Name == null)
225 if(!named_local_table.Contains(local.Name))
226 named_local_table.Add (local.Name, local);
229 this.local_list.AddRange (local_list);
232 public Local GetNamedLocal (string name)
234 return (Local) named_local_table[name];
237 public int GetNamedLocalSlot (string name)
239 Local local = (Local) named_local_table[name];
244 public int GetNamedParamPos (string name)
247 if (param_list == null)
252 foreach (ParamDef param in param_list) {
254 if (param.Name.CompareTo (name) == 0)
261 /* index - 0: return type
262 * 1: params start from this
264 public ParamDef GetParam (int index)
269 if ((param_list == null) || (index < 0) || (index > param_list.Count))
272 index --; /* param_list has params zero-based */
274 if (param_list [index] != null)
275 return (ParamDef)param_list [index];
280 public void InitLocals ()
285 public void EntryPoint ()
288 Report.Error ("Non-static method as entrypoint.");
292 public void ZeroInit ()
297 public void SetMaxStack (int max_stack)
299 this.max_stack = max_stack;
302 public void ResolveGenParam (PEAPI.GenParam gpar)
304 if (gpar.Index != -1)
307 if (gpar.Type == PEAPI.GenParamType.MVar)
308 gpar.Index = GetGenericParamNum (gpar.Name);
310 gpar.Index = type_def.GetGenericParamNum (gpar.Name);
313 Report.Error (String.Format ("Invalid {0}type parameter '{1}'",
314 (gpar.Type == PEAPI.GenParamType.MVar ? "method " : ""),
318 public void ResolveGenParams ()
320 GenericParameters type_params = (type_def != null) ? type_def.TypeParameters : null;
322 if (gen_params == null && type_params == null)
325 if (gen_params != null)
326 gen_params.ResolveConstraints (type_params, gen_params);
328 BaseGenericTypeRef gtr = RetType as BaseGenericTypeRef;
330 gtr.Resolve (type_params, gen_params);
332 if (param_list == null)
335 foreach (ParamDef param in param_list) {
336 gtr = param.Type as BaseGenericTypeRef;
338 gtr.Resolve (type_params, gen_params);
342 public PEAPI.MethodDef Resolve (CodeGen code_gen)
344 return Resolve (code_gen, null);
347 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
352 PEAPI.Param [] param_array = GenerateParams (code_gen);
354 ret_param.Define (code_gen);
356 if (classdef == null)
357 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
358 name, ret_param.PeapiParam, param_array);
360 methoddef = classdef.AddMethod (meth_attr, impl_attr,
361 name, ret_param.PeapiParam, param_array);
363 methoddef.AddCallConv (call_conv);
370 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
372 PEAPI.Param[] param_array;
374 if (param_list != null && param_list.Count > 0) {
375 int param_count = param_list.Count;
377 // Remove the last param if its the sentinel, not sure what
378 // should happen with more then one sentinel
379 ParamDef last = (ParamDef) param_list [param_count-1];
380 if (last.IsSentinel ())
383 param_array = new PEAPI.Param [param_count];
384 for (int i = 0; i < param_count; i++) {
385 ParamDef paramdef = (ParamDef) param_list [i];
386 paramdef.Define (code_gen);
387 param_array [i] = paramdef.PeapiParam;
391 param_array = new PEAPI.Param [0];
397 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
400 throw new InternalErrorException ("Methods must be resolved before a vararg sig can be created.");
402 PEAPI.MethodRef methref = null;
403 StringBuilder sigbuilder = new StringBuilder ();
405 foreach (PEAPI.Type t in opt)
406 sigbuilder.Append (opt + ", ");
407 sig = sigbuilder.ToString ();
409 if (vararg_sig_table == null) {
410 vararg_sig_table = new Hashtable ();
412 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
415 if (methref == null) {
416 methref = methoddef.MakeVarArgSignature (opt);
417 vararg_sig_table [sig] = methref;
424 /// Define a member method
426 public void Define (CodeGen code_gen)
431 if (type_def == null)
433 Resolve (code_gen, null);
435 Resolve (code_gen, (PEAPI.ClassDef) type_def.ClassDef);
437 WriteCode (code_gen, methoddef);
439 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name));
443 public void AddInstr (IInstr instr)
445 inst_list.Add (instr);
448 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
450 /// Add the custrom attributes to this method
451 if (customattr_list != null)
452 foreach (CustomAttr customattr in customattr_list) {
453 customattr.AddTo (code_gen, methoddef);
454 if (customattr.IsSuppressUnmanaged (code_gen))
455 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
458 /// Add declarative security to this method
459 if (decl_sec != null) {
460 decl_sec.AddTo (code_gen, methoddef);
461 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
464 // Generic type parameters
465 if (gen_params != null)
466 gen_params.Resolve (code_gen, methoddef);
468 if (type_def == null) {
470 meth_attr &= ~PEAPI.MethAttr.Abstract;
471 meth_attr |= PEAPI.MethAttr.Static;
473 if ((inst_list.Count > 0) && type_def.IsInterface && !IsStatic)
474 Report.Error (start, "Method cannot have body if it is non-static declared in an interface");
477 if (!type_def.IsAbstract)
478 Report.Error (start, String.Format ("Abstract method '{0}' in non-abstract class '{1}'",
479 Name, type_def.FullName));
480 if (inst_list.Count > 0)
481 Report.Error (start, "Method cannot have body if it is abstract.");
487 methoddef.DeclareEntryPoint ();
489 if (local_list.Count > 0) {
490 int ec = Report.ErrorCount;
491 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
493 foreach (Local local in local_list)
494 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
496 if (Report.ErrorCount > ec)
502 methoddef.AddLocals (local_array, init_locals);
505 /// Nothing seems to work if maxstack is not set,
506 /// i need to find out if this NEEDs to be set
507 /// and what its default value should be
510 methoddef.SetMaxStack (max_stack);
513 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
514 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
517 if ((impl_attr & PEAPI.ImplAttr.Runtime) == PEAPI.ImplAttr.Runtime) {
518 if (inst_list.Count > 0)
519 Report.Error (start, String.Format ("Method cannot have body if it is non-IL runtime-supplied, '{0}'",
522 if (((impl_attr & PEAPI.ImplAttr.Native) != 0) ||
523 ((impl_attr & PEAPI.ImplAttr.Unmanaged) != 0))
524 Report.Error (start, String.Format ("Cannot compile native/unmanaged method, '{0}'",
528 if (inst_list.Count > 0) {
530 if ((impl_attr & PEAPI.ImplAttr.InternalCall) != 0)
531 Report.Error (start, String.Format ("Method cannot have body if it is an internal call, '{0}'",
535 Report.Error (start, String.Format ("Method cannot have body if it is pinvoke, '{0}'",
539 ((impl_attr & PEAPI.ImplAttr.Runtime) != 0) ||
540 ((impl_attr & PEAPI.ImplAttr.InternalCall) != 0))
541 /* No body required */
544 Report.Warning (start, "Method has no body, 'ret' emitted.");
545 AddInstr (new SimpInstr (PEAPI.Op.ret, start));
548 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
549 /// Create all the labels
550 /// TODO: Most labels don't actually need to be created so we could
551 /// probably only create the ones that need to be
552 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
553 label_table.Values.CopyTo (label_info, 0);
554 label_list.CopyTo (label_info, label_table.Count);
555 int previous_pos = -1;
556 LabelInfo previous_label = null;
557 Array.Sort (label_info);
559 foreach (LabelInfo label in label_info) {
560 if (label.UseOffset) {
561 label.Define (new PEAPI.CILLabel (label.Offset));
564 if (label.Pos == previous_pos)
565 label.Label = previous_label.Label;
567 label.Define (cil.NewLabel ());
569 previous_label = label;
570 previous_pos = label.Pos;
573 // Set all the label refs
574 foreach (LabelInfo label in labelref_table.Values) {
575 LabelInfo def = (LabelInfo) label_table[label.Name];
577 Report.Error ("Undefined Label: " + label);
580 label.Label = def.Label;
584 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
586 for (int i=0; i<inst_list.Count; i++) {
587 IInstr instr = (IInstr) inst_list[i];
588 if (next_label_pos == i) {
589 cil.CodeLabel (label_info[label_pos].Label);
590 if (label_pos < label_info.Length) {
591 while (next_label_pos == i && ++label_pos < label_info.Length) {
592 if (label_info[label_pos].UseOffset)
593 cil.CodeLabel (label_info[label_pos].Label);
594 next_label_pos = label_info[label_pos].Pos;
597 if (label_pos >= label_info.Length)
601 source.MarkLocation (instr.Location.line, cil.Offset);
602 instr.Emit (code_gen, this, cil);
606 source.MarkLocation (source.EndLine, cil.Offset);
609 public LabelInfo AddLabel (string name)
611 LabelInfo label_info = (LabelInfo) label_table[name];
612 if (label_info != null)
613 Report.Error ("Duplicate label '" + name + "'");
615 label_info = new LabelInfo (name, inst_list.Count);
616 label_table [name] = label_info;
620 public LabelInfo AddLabelRef (string name)
622 LabelInfo label_info = (LabelInfo) label_table[name];
623 if (label_info != null)
625 label_info = (LabelInfo) labelref_table[name];
626 if (label_info != null)
628 label_info = new LabelInfo (name, -1);
629 labelref_table.Add (name, label_info);
633 public LabelInfo AddLabel (int offset)
635 // We go pos + 1 so this line is not counted
636 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
637 label_list.Add (label_info);
641 public LabelInfo AddLabel ()
643 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
644 label_list.Add (label_info);
648 public PEAPI.CILLabel GetLabelDef (string name)
650 LabelInfo label_info = (LabelInfo) label_table[name];
652 return label_info.Label;
655 public PEAPI.CILLabel GetLabelDef (int pos)
657 foreach (LabelInfo li in label_list) {
664 private void CreateSignature ()
667 signature = CreateVarargSignature (RetType, name, param_list);
669 signature = CreateSignature (RetType, name, param_list, GenParamCount);
672 public static string CreateSignature (BaseTypeRef RetType, string name, IList param_list, int gen_param_count)
674 StringBuilder builder = new StringBuilder ();
676 builder.Append (RetType.FullName);
677 builder.Append (" ");
678 builder.Append (name);
679 if (gen_param_count > 0)
680 builder.AppendFormat ("`{0}", gen_param_count);
681 builder.Append ('(');
683 if (param_list != null) {
685 foreach (ParamDef paramdef in param_list) {
687 builder.Append (',');
688 builder.Append (paramdef.TypeName);
692 builder.Append (')');
694 return builder.ToString ();
697 public static string CreateVarargSignature (BaseTypeRef RetType, string name, IList param_list)
699 StringBuilder builder = new StringBuilder ();
700 ParamDef last = null;
702 builder.Append (RetType.FullName);
703 builder.Append (" ");
704 builder.Append (name);
705 builder.Append ('(');
708 if (param_list != null) {
709 foreach (ParamDef paramdef in param_list) {
711 builder.Append (',');
712 builder.Append (paramdef.TypeName);
715 last = (ParamDef) param_list[param_list.Count - 1];
719 if (last == null || !last.IsSentinel ()) {
721 builder.Append (',');
722 builder.Append ("...");
725 builder.Append (')');
727 return builder.ToString ();
730 public static string CreateVarargSignature (BaseTypeRef RetType, string name, BaseTypeRef [] param_list)
732 StringBuilder builder = new StringBuilder ();
733 BaseTypeRef last = null;
735 builder.Append (RetType.FullName);
736 builder.Append (" ");
737 builder.Append (name);
738 builder.Append ('(');
741 if (param_list != null && param_list.Length > 0) {
742 foreach (BaseTypeRef param in param_list) {
744 builder.Append (',');
745 builder.Append (param.FullName);
748 if (param is SentinelTypeRef)
754 if (last == null || !(last is SentinelTypeRef)) {
756 builder.Append (',');
757 builder.Append ("...");
760 builder.Append (')');
762 return builder.ToString ();
765 public static string CreateSignature (BaseTypeRef RetType, string name, BaseTypeRef[] param_list, int gen_param_count)
767 StringBuilder builder = new StringBuilder ();
769 builder.Append (RetType.FullName);
770 builder.Append (" ");
771 builder.Append (name);
772 if (gen_param_count > 0)
773 builder.AppendFormat ("`{0}", gen_param_count);
774 builder.Append ('(');
776 if (param_list != null) {
778 foreach (BaseTypeRef param in param_list) {
780 builder.Append (',');
781 builder.Append (param.FullName);
783 if (param is SentinelTypeRef)
787 builder.Append (')');
789 return builder.ToString ();
792 private void FixAttributes ()
794 if (name == ".ctor" || name == ".cctor")
795 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
796 // If methods aren't flagged as static they are instance
797 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
798 call_conv |= PEAPI.CallConv.Instance;