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 BaseTypeRef ret_type;
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 PEAPI.NativeType ret_native_type;
49 private TypeDef type_def;
50 private GenericParameters gen_params;
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.ret_type = ret_type;
62 this.param_list = param_list;
63 this.type_def = type_def;
64 this.gen_params = gen_params;
66 inst_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 ();
84 codegen.BeginMethodDef (this);
86 if (codegen.SymbolWriter != null)
87 source = codegen.SymbolWriter.BeginMethod (this, start);
94 public string Signature {
95 get { return signature; }
98 public BaseTypeRef RetType {
99 get { return ret_type; }
102 public PEAPI.CallConv CallConv {
103 get { return call_conv; }
106 public PEAPI.MethodDef PeapiMethodDef {
107 get { return methoddef; }
110 public PEAPI.MethAttr Attributes {
111 get { return meth_attr; }
112 set { meth_attr = value; }
115 public bool IsVararg {
116 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
119 public bool IsStatic {
120 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
123 public bool IsVirtual {
124 get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
127 public bool IsAbstract {
128 get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
131 public BaseTypeRef[] ParamTypeList () {
133 if (param_list == null)
134 return new BaseTypeRef[0];
136 BaseTypeRef[] type_list = new BaseTypeRef[param_list.Count];
137 foreach (ParamDef param in param_list) {
138 type_list[count++] = param.Type;
143 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
146 this.pinvoke_attr = pinvoke_attr;
147 this.pinvoke_mod = pinvoke_mod;
148 this.pinvoke_name = pinvoke_name;
152 public int GenParamCount {
153 get { return (gen_params != null ? gen_params.Count : 0); }
156 public GenericParameter GetGenericParam (string id)
158 if (gen_params == null)
161 return gen_params.GetGenericParam (id);
164 public GenericParameter GetGenericParam (int index)
166 if (gen_params == null || index < 0 || index >= gen_params.Count)
169 return gen_params [index];
172 public int GetGenericParamNum (string id)
174 if (gen_params == null)
177 return gen_params.GetGenericParamNum (id);
180 public void AddParamDefaultValue (int index, PEAPI.Constant defval)
182 if (param_list [index] != null) {
183 ((ParamDef)param_list [index]).AddDefaultValue (defval);
187 public void AddCustomAttribute (CustomAttr customattr)
189 if (customattr_list == null)
190 customattr_list = new ArrayList ();
192 customattr_list.Add (customattr);
195 public void AddPermissionSet (PEAPI.SecurityAction sec_action, PermissionSet ps)
197 if (decl_sec == null)
198 decl_sec = new DeclSecurity ();
200 decl_sec.AddPermissionSet (sec_action, ps);
203 public void AddPermission (PEAPI.SecurityAction sec_action, IPermission iper)
205 if (decl_sec == null)
206 decl_sec = new DeclSecurity ();
208 decl_sec.AddPermission (sec_action, iper);
211 public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
213 this.ret_native_type = native_type;
216 public void AddLocals (ArrayList local_list)
218 int slot_pos = this.local_list.Count;
220 foreach (Local local in local_list) {
221 if (local.Slot == -1) {
222 local.Slot = slot_pos;
225 if (local.Name == null)
227 if(!named_local_table.Contains(local.Name))
228 named_local_table.Add (local.Name, local);
231 this.local_list.AddRange (local_list);
234 public Local GetNamedLocal (string name)
236 return (Local) named_local_table[name];
239 public int GetNamedLocalSlot (string name)
241 Local local = (Local) named_local_table[name];
246 public int GetNamedParamPos (string name)
251 foreach (ParamDef param in param_list) {
253 if (param.Name.CompareTo (name) == 0)
260 public ParamDef GetParam (int index)
262 if (param_list [index] != null)
263 return (ParamDef)param_list [index];
268 public void InitLocals ()
273 public void EntryPoint ()
276 throw new Exception ("Non-static method as entrypoint.");
280 public void ZeroInit ()
285 public void SetMaxStack (int max_stack)
287 this.max_stack = max_stack;
290 public void ResolveGenParam (PEAPI.GenParam gpar)
292 if (gpar.Index != -1)
295 if (gpar.Type == PEAPI.GenParamType.MVar)
296 gpar.Index = GetGenericParamNum (gpar.Name);
298 gpar.Index = type_def.GetGenericParamNum (gpar.Name);
301 /* TODO: Report error */
302 throw new Exception (String.Format ("Invalid {0}type parameter '{1}'",
303 (gpar.Type == PEAPI.GenParamType.MVar ? "method " : ""),
307 public void ResolveGenParams ()
309 GenericParameters type_params = (type_def != null) ? type_def.TypeParameters : null;
311 if (gen_params == null && type_params == null)
314 if (gen_params != null)
315 gen_params.ResolveConstraints (type_params, gen_params);
317 BaseGenericTypeRef gtr = ret_type as BaseGenericTypeRef;
319 gtr.Resolve (type_params, gen_params);
321 if (param_list == null)
324 foreach (ParamDef param in param_list) {
325 gtr = param.Type as BaseGenericTypeRef;
327 gtr.Resolve (type_params, gen_params);
331 public PEAPI.MethodDef Resolve (CodeGen code_gen)
333 return Resolve (code_gen, null);
336 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
341 PEAPI.Param [] param_array = GenerateParams (code_gen);
343 ret_type.Resolve (code_gen);
345 if (classdef == null)
346 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
347 name, ret_type.PeapiType, param_array);
349 methoddef = classdef.AddMethod (meth_attr, impl_attr,
350 name, ret_type.PeapiType, param_array);
352 methoddef.AddCallConv (call_conv);
354 if (ret_native_type != null)
355 methoddef.AddRetTypeMarshallInfo (ret_native_type);
362 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
364 PEAPI.Param[] param_array;
366 if (param_list != null && param_list.Count > 0) {
367 int param_count = param_list.Count;
369 // Remove the last param if its the sentinel, not sure what
370 // should happen with more then one sentinel
371 ParamDef last = (ParamDef) param_list [param_count-1];
372 if (last.IsSentinel ())
375 param_array = new PEAPI.Param [param_count];
376 for (int i = 0; i < param_count; i++) {
377 ParamDef paramdef = (ParamDef) param_list [i];
378 paramdef.Define (code_gen);
379 param_array [i] = paramdef.PeapiParam;
383 param_array = new PEAPI.Param [0];
389 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
392 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
394 PEAPI.MethodRef methref = null;
395 StringBuilder sigbuilder = new StringBuilder ();
397 foreach (PEAPI.Type t in opt)
398 sigbuilder.Append (opt + ", ");
399 sig = sigbuilder.ToString ();
401 if (vararg_sig_table == null) {
402 vararg_sig_table = new Hashtable ();
404 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
407 if (methref == null) {
408 methref = methoddef.MakeVarArgSignature (opt);
409 vararg_sig_table [sig] = methref;
416 /// Define a member method
418 public void Define (CodeGen code_gen)
423 if (type_def == null)
425 Resolve (code_gen, null);
427 Resolve (code_gen, (PEAPI.ClassDef) type_def.ClassDef);
429 WriteCode (code_gen, methoddef);
431 //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name));
435 public void AddInstr (IInstr instr)
437 inst_list.Add (instr);
440 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
442 /// Add the custrom attributes to this method
443 if (customattr_list != null)
444 foreach (CustomAttr customattr in customattr_list) {
445 customattr.AddTo (code_gen, methoddef);
446 if (customattr.IsSuppressUnmanaged (code_gen))
447 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
450 /// Add declarative security to this method
451 if (decl_sec != null) {
452 decl_sec.AddTo (code_gen, methoddef);
453 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
456 // Generic type parameters
457 if (gen_params != null)
458 gen_params.Resolve (code_gen, methoddef);
464 methoddef.DeclareEntryPoint ();
466 if (local_list.Count > 0) {
467 int ec = code_gen.Report.ErrorCount;
468 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
471 foreach (Local local in local_list)
472 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
474 if (code_gen.Report.ErrorCount > ec)
480 methoddef.AddLocals (local_array, init_locals);
483 /// Nothing seems to work if maxstack is not set,
484 /// i need to find out if this NEEDs to be set
485 /// and what its default value should be
488 methoddef.SetMaxStack (max_stack);
491 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
492 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
495 if (inst_list.Count < 1)
498 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
499 /// Create all the labels
500 /// TODO: Most labels don't actually need to be created so we could
501 /// probably only create the ones that need to be
502 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
503 label_table.Values.CopyTo (label_info, 0);
504 label_list.CopyTo (label_info, label_table.Count);
505 int previous_pos = -1;
506 LabelInfo previous_label = null;
507 Array.Sort (label_info);
509 foreach (LabelInfo label in label_info) {
510 if (label.UseOffset) {
511 label.Define (new PEAPI.CILLabel (label.Offset));
514 if (label.Pos == previous_pos)
515 label.Label = previous_label.Label;
517 label.Define (cil.NewLabel ());
519 previous_label = label;
520 previous_pos = label.Pos;
523 // Set all the label refs
524 foreach (LabelInfo label in labelref_table.Values) {
525 LabelInfo def = (LabelInfo) label_table[label.Name];
527 code_gen.Report.Error ("Undefined Label: " + label);
530 label.Label = def.Label;
534 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
536 for (int i=0; i<inst_list.Count; i++) {
537 IInstr instr = (IInstr) inst_list[i];
538 if (next_label_pos == i) {
539 cil.CodeLabel (label_info[label_pos].Label);
540 if (label_pos < label_info.Length) {
541 while (next_label_pos == i && ++label_pos < label_info.Length) {
542 if (label_info[label_pos].UseOffset)
543 cil.CodeLabel (label_info[label_pos].Label);
544 next_label_pos = label_info[label_pos].Pos;
547 if (label_pos >= label_info.Length)
551 source.MarkLocation (instr.Location.line, cil.Offset);
552 instr.Emit (code_gen, this, cil);
556 source.MarkLocation (source.EndLine, cil.Offset);
559 public LabelInfo AddLabel (string name)
561 LabelInfo label_info = (LabelInfo) label_table[name];
562 if (label_info != null)
564 label_info = new LabelInfo (name, inst_list.Count);
565 label_table.Add (name, label_info);
569 public LabelInfo AddLabelRef (string name)
571 LabelInfo label_info = (LabelInfo) label_table[name];
572 if (label_info != null)
574 label_info = (LabelInfo) labelref_table[name];
575 if (label_info != null)
577 label_info = new LabelInfo (name, -1);
578 labelref_table.Add (name, label_info);
582 public LabelInfo AddLabel (int offset)
584 // We go pos + 1 so this line is not counted
585 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
586 label_list.Add (label_info);
590 public LabelInfo AddLabel ()
592 int pos = inst_list.Count;
593 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
594 label_list.Add (label_info);
598 public PEAPI.CILLabel GetLabelDef (string name)
600 LabelInfo label_info = (LabelInfo) label_table[name];
602 return label_info.Label;
605 public PEAPI.CILLabel GetLabelDef (int pos)
607 foreach (LabelInfo li in label_list) {
614 private void CreateSignature ()
617 signature = CreateVarargSignature (RetType, name, param_list);
619 signature = CreateSignature (RetType, name, param_list, GenParamCount);
622 public static string CreateSignature (BaseTypeRef RetType, string name, IList param_list, int gen_param_count)
624 StringBuilder builder = new StringBuilder ();
626 builder.Append (RetType.FullName);
627 builder.Append (" ");
628 builder.Append (name);
629 if (gen_param_count > 0)
630 builder.AppendFormat ("`{0}", gen_param_count);
631 builder.Append ('(');
633 if (param_list != null) {
635 foreach (ParamDef paramdef in param_list) {
637 builder.Append (',');
638 builder.Append (paramdef.TypeName);
642 builder.Append (')');
644 return builder.ToString ();
647 public static string CreateVarargSignature (BaseTypeRef RetType, string name, IList param_list)
649 StringBuilder builder = new StringBuilder ();
650 ParamDef last = null;
652 builder.Append (RetType.FullName);
653 builder.Append (" ");
654 builder.Append (name);
655 builder.Append ('(');
658 if (param_list != null) {
659 foreach (ParamDef paramdef in param_list) {
661 builder.Append (',');
662 builder.Append (paramdef.TypeName);
665 last = (ParamDef) param_list[param_list.Count - 1];
669 if (last == null || !last.IsSentinel ()) {
671 builder.Append (',');
672 builder.Append ("...");
675 builder.Append (')');
677 return builder.ToString ();
680 public static string CreateVarargSignature (BaseTypeRef RetType, string name, BaseTypeRef [] param_list)
682 StringBuilder builder = new StringBuilder ();
683 BaseTypeRef last = null;
685 builder.Append (RetType.FullName);
686 builder.Append (" ");
687 builder.Append (name);
688 builder.Append ('(');
691 if (param_list != null && param_list.Length > 0) {
692 foreach (BaseTypeRef param in param_list) {
694 builder.Append (',');
695 builder.Append (param.FullName);
698 if (param is SentinelTypeRef)
704 if (last == null || !(last is SentinelTypeRef)) {
706 builder.Append (',');
707 builder.Append ("...");
710 builder.Append (')');
712 return builder.ToString ();
715 public static string CreateSignature (BaseTypeRef RetType, string name, BaseTypeRef[] param_list, int gen_param_count)
717 StringBuilder builder = new StringBuilder ();
719 builder.Append (RetType.FullName);
720 builder.Append (" ");
721 builder.Append (name);
722 if (gen_param_count > 0)
723 builder.AppendFormat ("`{0}", gen_param_count);
724 builder.Append ('(');
726 if (param_list != null) {
728 foreach (BaseTypeRef param in param_list) {
730 builder.Append (',');
731 builder.Append (param.FullName);
733 if (param is SentinelTypeRef)
737 builder.Append (')');
739 return builder.ToString ();
742 private void FixAttributes ()
744 if (name == ".ctor" || name == ".cctor")
745 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
746 // If methods aren't flagged as static they are instance
747 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
748 call_conv |= PEAPI.CallConv.Instance;