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 protected class GenericInfo {
23 public ArrayList ConstraintList;
26 private PEAPI.MethAttr meth_attr;
27 private PEAPI.CallConv call_conv;
28 private PEAPI.ImplAttr impl_attr;
30 private string signature;
31 private Hashtable vararg_sig_table;
32 private BaseTypeRef ret_type;
33 private ArrayList param_list;
34 private ArrayList inst_list;
35 private ArrayList customattr_list;
36 private DeclSecurity decl_sec;
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;
55 private TypeDef type_def;
56 private GenericParameters gen_params;
58 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
59 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
60 string name, BaseTypeRef ret_type, ArrayList param_list,
61 Location start, GenericParameters gen_params, TypeDef type_def)
63 this.meth_attr = meth_attr;
64 this.call_conv = call_conv;
65 this.impl_attr = impl_attr;
67 this.ret_type = ret_type;
68 this.param_list = param_list;
69 this.type_def = type_def;
70 this.gen_params = gen_params;
72 inst_list = new ArrayList ();
73 label_table = new Hashtable ();
74 labelref_table = new Hashtable ();
75 label_list = new ArrayList ();
76 local_list = new ArrayList ();
77 named_local_table = new Hashtable ();
90 codegen.BeginMethodDef (this);
92 if (codegen.SymbolWriter != null)
93 source = codegen.SymbolWriter.BeginMethod (this, start);
100 public string Signature {
101 get { return signature; }
104 public BaseTypeRef RetType {
105 get { return ret_type; }
108 public PEAPI.CallConv CallConv {
109 get { return call_conv; }
112 public PEAPI.MethodDef PeapiMethodDef {
113 get { return methoddef; }
116 public PEAPI.MethAttr Attributes {
117 get { return meth_attr; }
118 set { meth_attr = value; }
121 public bool IsVararg {
122 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
125 public bool IsStatic {
126 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
129 public bool IsVirtual {
130 get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
133 public bool IsAbstract {
134 get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
137 public BaseTypeRef[] ParamTypeList () {
139 if (param_list == null)
140 return new BaseTypeRef[0];
142 BaseTypeRef[] type_list = new BaseTypeRef[param_list.Count];
143 foreach (ParamDef param in param_list) {
144 type_list[count++] = param.Type;
149 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
152 this.pinvoke_attr = pinvoke_attr;
153 this.pinvoke_mod = pinvoke_mod;
154 this.pinvoke_name = pinvoke_name;
158 public int GenParamCount {
159 get { return (gen_params != null ? gen_params.Count : 0); }
162 public GenericParameter GetGenericParam (string id)
164 if (gen_params == null)
167 return gen_params.GetGenericParam (id);
170 public GenericParameter GetGenericParam (int index)
172 if (gen_params == null || index < 0 || index >= gen_params.Count)
175 return gen_params [index];
178 public int GetGenericParamNum (string id)
180 if (gen_params == null)
183 return gen_params.GetGenericParamNum (id);
186 public void AddParamDefaultValue (int index, PEAPI.Constant defval)
188 if (param_list [index] != null) {
189 ((ParamDef)param_list [index]).AddDefaultValue (defval);
193 public void AddCustomAttribute (CustomAttr customattr)
195 if (customattr_list == null)
196 customattr_list = new ArrayList ();
198 customattr_list.Add (customattr);
201 public void AddPermissionSet (PEAPI.SecurityAction sec_action, PermissionSet ps)
203 if (decl_sec == null)
204 decl_sec = new DeclSecurity ();
206 decl_sec.AddPermissionSet (sec_action, ps);
209 public void AddPermission (PEAPI.SecurityAction sec_action, IPermission iper)
211 if (decl_sec == null)
212 decl_sec = new DeclSecurity ();
214 decl_sec.AddPermission (sec_action, iper);
217 public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
219 this.ret_native_type = native_type;
222 public void AddLocals (ArrayList local_list)
224 int slot_pos = this.local_list.Count;
226 foreach (Local local in local_list) {
227 if (local.Slot == -1) {
228 local.Slot = slot_pos;
231 if (local.Name == null)
233 if(!named_local_table.Contains(local.Name))
234 named_local_table.Add (local.Name, local);
237 this.local_list.AddRange (local_list);
240 public Local GetNamedLocal (string name)
242 return (Local) named_local_table[name];
245 public int GetNamedLocalSlot (string name)
247 Local local = (Local) named_local_table[name];
252 public int GetNamedParamPos (string name)
257 foreach (ParamDef param in param_list) {
259 if (param.Name.CompareTo (name) == 0)
266 public ParamDef GetParam (int index)
268 if (param_list [index] != null)
269 return (ParamDef)param_list [index];
274 public void InitLocals ()
279 public void EntryPoint ()
282 throw new Exception ("Non-static method as entrypoint.");
286 public void ZeroInit ()
291 public void SetMaxStack (int max_stack)
293 this.max_stack = max_stack;
296 public void ResolveGenParam (PEAPI.GenParam gpar)
298 if (gpar.Index != -1)
301 if (gpar.Type == PEAPI.GenParamType.MVar)
302 gpar.Index = GetGenericParamNum (gpar.Name);
304 gpar.Index = type_def.GetGenericParamNum (gpar.Name);
307 /* TODO: Report error */
308 throw new Exception (String.Format ("Invalid {0}type parameter '{1}'",
309 (gpar.Type == PEAPI.GenParamType.MVar ? "method " : ""),
313 public void ResolveGenParams ()
315 GenericParameters type_params = (type_def != null) ? type_def.TypeParameters : null;
317 if (gen_params == null && type_params == null)
320 if (gen_params != null)
321 gen_params.ResolveConstraints (type_params, gen_params);
323 BaseGenericTypeRef gtr = ret_type as BaseGenericTypeRef;
325 gtr.Resolve (type_params, gen_params);
327 if (param_list == null)
330 foreach (ParamDef param in param_list) {
331 gtr = param.Type as BaseGenericTypeRef;
333 gtr.Resolve (type_params, gen_params);
337 public PEAPI.MethodDef Resolve (CodeGen code_gen)
339 return Resolve (code_gen, null);
342 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
347 PEAPI.Param [] param_array = GenerateParams (code_gen);
349 ret_type.Resolve (code_gen);
351 if (classdef == null)
352 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
353 name, ret_type.PeapiType, param_array);
355 methoddef = classdef.AddMethod (meth_attr, impl_attr,
356 name, ret_type.PeapiType, param_array);
358 methoddef.AddCallConv (call_conv);
360 if (ret_native_type != null)
361 methoddef.AddRetTypeMarshallInfo (ret_native_type);
368 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
370 PEAPI.Param[] param_array;
372 if (param_list != null && param_list.Count > 0) {
373 int param_count = param_list.Count;
375 // Remove the last param if its the sentinel, not sure what
376 // should happen with more then one sentinel
377 ParamDef last = (ParamDef) param_list [param_count-1];
378 if (last.IsSentinel ())
381 param_array = new PEAPI.Param [param_count];
382 for (int i = 0; i < param_count; i++) {
383 ParamDef paramdef = (ParamDef) param_list [i];
384 paramdef.Define (code_gen);
385 param_array [i] = paramdef.PeapiParam;
389 param_array = new PEAPI.Param [0];
395 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
398 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
400 PEAPI.MethodRef methref = null;
401 StringBuilder sigbuilder = new StringBuilder ();
403 foreach (PEAPI.Type t in opt)
404 sigbuilder.Append (opt + ", ");
405 sig = sigbuilder.ToString ();
407 if (vararg_sig_table == null) {
408 vararg_sig_table = new Hashtable ();
410 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
413 if (methref == null) {
414 methref = methoddef.MakeVarArgSignature (opt);
415 vararg_sig_table [sig] = methref;
422 /// Define a member method
424 public void Define (CodeGen code_gen)
429 if (type_def == null)
431 Resolve (code_gen, null);
433 Resolve (code_gen, (PEAPI.ClassDef) type_def.ClassDef);
435 WriteCode (code_gen, methoddef);
437 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name));
441 public void AddInstr (IInstr instr)
443 inst_list.Add (instr);
446 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
448 /// Add the custrom attributes to this method
449 if (customattr_list != null)
450 foreach (CustomAttr customattr in customattr_list) {
451 customattr.AddTo (code_gen, methoddef);
452 if (customattr.IsSuppressUnmanaged (code_gen))
453 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
456 /// Add declarative security to this method
457 if (decl_sec != null) {
458 decl_sec.AddTo (code_gen, methoddef);
459 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
462 // Generic type parameters
463 if (gen_params != null)
464 gen_params.Resolve (code_gen, methoddef);
470 methoddef.DeclareEntryPoint ();
472 if (local_list.Count > 0) {
473 int ec = code_gen.Report.ErrorCount;
474 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
477 foreach (Local local in local_list)
478 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
480 if (code_gen.Report.ErrorCount > ec)
486 methoddef.AddLocals (local_array, init_locals);
489 /// Nothing seems to work if maxstack is not set,
490 /// i need to find out if this NEEDs to be set
491 /// and what its default value should be
494 methoddef.SetMaxStack (max_stack);
497 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
498 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
501 if (inst_list.Count < 1)
504 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
505 /// Create all the labels
506 /// TODO: Most labels don't actually need to be created so we could
507 /// probably only create the ones that need to be
508 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
509 label_table.Values.CopyTo (label_info, 0);
510 label_list.CopyTo (label_info, label_table.Count);
511 int previous_pos = -1;
512 LabelInfo previous_label = null;
513 Array.Sort (label_info);
515 foreach (LabelInfo label in label_info) {
516 if (label.UseOffset) {
517 label.Define (new PEAPI.CILLabel (label.Offset));
520 if (label.Pos == previous_pos)
521 label.Label = previous_label.Label;
523 label.Define (cil.NewLabel ());
525 previous_label = label;
526 previous_pos = label.Pos;
529 // Set all the label refs
530 foreach (LabelInfo label in labelref_table.Values) {
531 LabelInfo def = (LabelInfo) label_table[label.Name];
533 code_gen.Report.Error ("Undefined Label: " + label);
536 label.Label = def.Label;
540 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
542 for (int i=0; i<inst_list.Count; i++) {
543 IInstr instr = (IInstr) inst_list[i];
544 if (next_label_pos == i) {
545 cil.CodeLabel (label_info[label_pos].Label);
546 if (label_pos < label_info.Length) {
547 while (next_label_pos == i && ++label_pos < label_info.Length) {
548 if (label_info[label_pos].UseOffset)
549 cil.CodeLabel (label_info[label_pos].Label);
550 next_label_pos = label_info[label_pos].Pos;
553 if (label_pos >= label_info.Length)
557 source.MarkLocation (instr.Location.line, cil.Offset);
558 instr.Emit (code_gen, this, cil);
562 source.MarkLocation (source.EndLine, cil.Offset);
565 public LabelInfo AddLabel (string name)
567 LabelInfo label_info = (LabelInfo) label_table[name];
568 if (label_info != null)
570 label_info = new LabelInfo (name, inst_list.Count);
571 label_table.Add (name, label_info);
575 public LabelInfo AddLabelRef (string name)
577 LabelInfo label_info = (LabelInfo) label_table[name];
578 if (label_info != null)
580 label_info = (LabelInfo) labelref_table[name];
581 if (label_info != null)
583 label_info = new LabelInfo (name, -1);
584 labelref_table.Add (name, label_info);
588 public LabelInfo AddLabel (int offset)
590 // We go pos + 1 so this line is not counted
591 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
592 label_list.Add (label_info);
596 public LabelInfo AddLabel ()
598 int pos = inst_list.Count;
599 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
600 label_list.Add (label_info);
604 public PEAPI.CILLabel GetLabelDef (string name)
606 LabelInfo label_info = (LabelInfo) label_table[name];
608 return label_info.Label;
611 public PEAPI.CILLabel GetLabelDef (int pos)
613 foreach (LabelInfo li in label_list) {
620 private void CreateSignature ()
623 signature = CreateVarargSignature (RetType, name, param_list);
625 signature = CreateSignature (RetType, name, param_list, GenParamCount);
628 public static string CreateSignature (BaseTypeRef RetType, string name, IList param_list, int gen_param_count)
630 StringBuilder builder = new StringBuilder ();
632 builder.Append (RetType.FullName);
633 builder.Append (" ");
634 builder.Append (name);
635 if (gen_param_count > 0)
636 builder.AppendFormat ("`{0}", gen_param_count);
637 builder.Append ('(');
639 if (param_list != null) {
641 foreach (ParamDef paramdef in param_list) {
643 builder.Append (',');
644 builder.Append (paramdef.TypeName);
648 builder.Append (')');
650 return builder.ToString ();
653 public static string CreateVarargSignature (BaseTypeRef RetType, string name, IList param_list)
655 StringBuilder builder = new StringBuilder ();
656 ParamDef last = null;
658 builder.Append (RetType.FullName);
659 builder.Append (" ");
660 builder.Append (name);
661 builder.Append ('(');
664 if (param_list != null) {
665 foreach (ParamDef paramdef in param_list) {
667 builder.Append (',');
668 builder.Append (paramdef.TypeName);
671 last = (ParamDef) param_list[param_list.Count - 1];
675 if (last == null || !last.IsSentinel ()) {
677 builder.Append (',');
678 builder.Append ("...");
681 builder.Append (')');
683 return builder.ToString ();
686 public static string CreateVarargSignature (BaseTypeRef RetType, string name, BaseTypeRef [] param_list)
688 StringBuilder builder = new StringBuilder ();
689 BaseTypeRef last = null;
691 builder.Append (RetType.FullName);
692 builder.Append (" ");
693 builder.Append (name);
694 builder.Append ('(');
697 if (param_list != null && param_list.Length > 0) {
698 foreach (BaseTypeRef param in param_list) {
700 builder.Append (',');
701 builder.Append (param.FullName);
704 if (param is SentinelTypeRef)
710 if (last == null || !(last is SentinelTypeRef)) {
712 builder.Append (',');
713 builder.Append ("...");
716 builder.Append (')');
718 return builder.ToString ();
721 public static string CreateSignature (BaseTypeRef RetType, string name, BaseTypeRef[] param_list, int gen_param_count)
723 StringBuilder builder = new StringBuilder ();
725 builder.Append (RetType.FullName);
726 builder.Append (" ");
727 builder.Append (name);
728 if (gen_param_count > 0)
729 builder.AppendFormat ("`{0}", gen_param_count);
730 builder.Append ('(');
732 if (param_list != null) {
734 foreach (BaseTypeRef param in param_list) {
736 builder.Append (',');
737 builder.Append (param.FullName);
739 if (param is SentinelTypeRef)
743 builder.Append (')');
745 return builder.ToString ();
748 private void FixAttributes ()
750 if (name == ".ctor" || name == ".cctor")
751 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
752 // If methods aren't flagged as static they are instance
753 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
754 call_conv |= PEAPI.CallConv.Instance;