**** Merged from MCS ****
[mono-project.git] / mcs / ilasm / codegen / MethodDef.cs
blobdd46e1708afcec659a0b535fc71566fdbcf3f547
1 //
2 // Mono.ILASM.MethodDef
3 //
4 // Author(s):
5 // Jackson Harper (Jackson@LatitudeGeo.com)
6 //
7 // (C) 2003 Jackson Harper, All rights reserved
8 //
11 using System;
12 using System.Text;
13 using System.Collections;
16 namespace Mono.ILASM {
18 public class MethodDef {
20 protected class GenericInfo {
21 public string Id;
22 public ArrayList ConstraintList;
25 private PEAPI.MethAttr meth_attr;
26 private PEAPI.CallConv call_conv;
27 private PEAPI.ImplAttr impl_attr;
28 private string name;
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;
53 private SourceMethod source;
55 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
56 PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
57 string name, ITypeRef ret_type, ArrayList param_list,
58 Location start)
60 this.meth_attr = meth_attr;
61 this.call_conv = call_conv;
62 this.impl_attr = impl_attr;
63 this.name = name;
64 this.ret_type = ret_type;
65 this.param_list = param_list;
67 inst_list = new ArrayList ();
68 customattr_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 ();
74 named_param_table = new Hashtable ();
76 entry_point = false;
77 zero_init = false;
78 init_locals = false;
79 max_stack = -1;
80 pinvoke_info = false;
82 is_defined = false;
83 is_resolved = false;
84 CreateSignature ();
85 CreateNamedParamTable ();
87 codegen.BeginMethodDef (this);
89 if (codegen.SymbolWriter != null)
90 source = codegen.SymbolWriter.BeginMethod (this, start);
93 public string Name {
94 get { return name; }
97 public string Signature {
98 get { return signature; }
101 public ITypeRef RetType {
102 get { return ret_type; }
105 public PEAPI.CallConv CallConv {
106 get { return call_conv; }
109 public PEAPI.MethodDef PeapiMethodDef {
110 get { return methoddef; }
113 public bool IsVararg {
114 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
117 public bool IsStatic {
118 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
121 public ITypeRef[] ParamTypeList () {
123 if (param_list == null)
124 return new ITypeRef[0];
125 int count = 0;
126 ITypeRef[] type_list = new ITypeRef[param_list.Count];
127 foreach (ParamDef param in param_list) {
128 type_list[count++] = param.Type;
130 return type_list;
133 public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
134 string pinvoke_name)
136 this.pinvoke_attr = pinvoke_attr;
137 this.pinvoke_mod = pinvoke_mod;
138 this.pinvoke_name = pinvoke_name;
139 pinvoke_info = true;
142 public void AddGenericParam (string id)
144 if (typar_list == null)
145 typar_list = new ArrayList ();
147 GenericInfo gi = new GenericInfo ();
148 gi.Id = id;
150 typar_list.Add (gi);
153 public void AddGenericConstraint (int index, ITypeRef constraint)
155 GenericInfo gi = (GenericInfo) typar_list[index];
157 if (gi.ConstraintList == null)
158 gi.ConstraintList = new ArrayList ();
159 gi.ConstraintList.Add (constraint);
162 public void AddLocals (ArrayList local_list)
164 int slot_pos = this.local_list.Count;
166 foreach (Local local in local_list) {
167 if (local.Slot == -1) {
168 local.Slot = slot_pos;
170 slot_pos++;
171 if (local.Name == null)
172 continue;
173 named_local_table.Add (local.Name, local);
176 this.local_list.AddRange (local_list);
179 public Local GetNamedLocal (string name)
181 return (Local) named_local_table[name];
184 public int GetNamedLocalSlot (string name)
186 Local local = (Local) named_local_table[name];
188 return local.Slot;
191 public int GetNamedParamPos (string name)
193 int pos = (int) named_param_table[name];
195 return pos;
198 public void InitLocals ()
200 init_locals = true;
203 public void EntryPoint ()
205 entry_point = true;
208 public void ZeroInit ()
210 zero_init = true;
213 public void SetMaxStack (int max_stack)
215 this.max_stack = max_stack;
218 public void AddCustomAttr (CustomAttr customattr)
220 customattr_list.Add (customattr);
223 public PEAPI.MethodDef Resolve (CodeGen code_gen)
225 if (is_resolved)
226 return methoddef;
228 PEAPI.Param [] param_array = GenerateParams (code_gen);
229 FixAttributes ();
230 ret_type.Resolve (code_gen);
232 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
233 name, ret_type.PeapiType, param_array);
235 methoddef.AddCallConv (call_conv);
236 is_resolved = true;
238 return methoddef;
241 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
243 if (is_resolved)
244 return methoddef;
246 PEAPI.Param [] param_array = GenerateParams (code_gen);
247 FixAttributes ();
248 ret_type.Resolve (code_gen);
250 methoddef = classdef.AddMethod (meth_attr, impl_attr,
251 name, ret_type.PeapiType, param_array);
253 methoddef.AddCallConv (call_conv);
254 is_resolved = true;
256 return methoddef;
259 private PEAPI.Param [] GenerateParams (CodeGen code_gen)
261 PEAPI.Param[] param_array;
263 if (param_list != null && param_list.Count > 0) {
264 int param_count = param_list.Count;
266 // Remove the last param if its the sentinel, not sure what
267 // should happen with more then one sentinel
268 ParamDef last = (ParamDef) param_list [param_count-1];
269 if (last.IsSentinel ())
270 param_count--;
272 param_array = new PEAPI.Param [param_count];
273 for (int i = 0; i < param_count; i++) {
274 ParamDef paramdef = (ParamDef) param_list [i];
275 paramdef.Define (code_gen);
276 param_array [i] = paramdef.PeapiParam;
279 } else {
280 param_array = new PEAPI.Param [0];
283 return param_array;
286 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
288 if (!is_resolved)
289 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
291 PEAPI.MethodRef methref = null;
292 StringBuilder sigbuilder = new StringBuilder ();
293 string sig;
294 foreach (PEAPI.Type t in opt)
295 sigbuilder.Append (opt + ", ");
296 sig = sigbuilder.ToString ();
298 if (vararg_sig_table == null) {
299 vararg_sig_table = new Hashtable ();
300 } else {
301 methref = vararg_sig_table [sig] as PEAPI.MethodRef;
304 if (methref == null) {
305 methref = methoddef.MakeVarArgSignature (opt);
306 vararg_sig_table [sig] = methref;
309 return methref;
312 /// <summary>
313 /// Define a global method
314 /// </summary>
315 public void Define (CodeGen code_gen)
317 if (is_defined)
318 return;
320 Resolve (code_gen);
322 WriteCode (code_gen, methoddef);
324 code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
325 is_defined = true;
328 /// <summary>
329 /// Define a member method
330 /// </summary>
331 public void Define (CodeGen code_gen, TypeDef typedef)
333 if (is_defined)
334 return;
336 Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
337 WriteCode (code_gen, methoddef);
339 code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name)); is_defined = true;
342 public void AddInstr (IInstr instr)
344 inst_list.Add (instr);
347 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
349 if (entry_point)
350 methoddef.DeclareEntryPoint ();
352 if (local_list.Count > 0) {
353 int ec = code_gen.Report.ErrorCount;
354 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
355 int i = 0;
357 foreach (Local local in local_list)
358 local_array[local.Slot] = local.GetPeapiLocal (code_gen);
360 if (code_gen.Report.ErrorCount > ec)
361 return;
363 if (zero_init)
364 init_locals = true;
366 methoddef.AddLocals (local_array, init_locals);
369 /// Nothing seems to work if maxstack is not set,
370 /// i need to find out if this NEEDs to be set
371 /// and what its default value should be
372 if (max_stack < 0)
373 max_stack = 8;
374 methoddef.SetMaxStack (max_stack);
376 /// Add the custrom attributes to this method
377 foreach (CustomAttr customattr in customattr_list)
378 customattr.AddTo (code_gen, methoddef);
380 if (pinvoke_info) {
381 methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
382 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
386 if (inst_list.Count < 1)
387 return;
389 PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
390 /// Create all the labels
391 /// TODO: Most labels don't actually need to be created so we could
392 /// probably only create the ones that need to be
393 LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
394 label_table.Values.CopyTo (label_info, 0);
395 label_list.CopyTo (label_info, label_table.Count);
396 int previous_pos = -1;
397 LabelInfo previous_label = null;
398 Array.Sort (label_info);
400 foreach (LabelInfo label in label_info) {
401 if (label.UseOffset) {
402 label.Define (new PEAPI.CILLabel (label.Offset));
403 continue;
405 if (label.Pos == previous_pos)
406 label.Label = previous_label.Label;
407 else
408 label.Define (cil.NewLabel ());
410 previous_label = label;
411 previous_pos = label.Pos;
414 // Set all the label refs
415 foreach (LabelInfo label in labelref_table.Values) {
416 LabelInfo def = (LabelInfo) label_table[label.Name];
417 if (def == null) {
418 code_gen.Report.Error ("Undefined Label: " + label);
419 return;
421 label.Label = def.Label;
424 int label_pos = 0;
425 int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
427 for (int i=0; i<inst_list.Count; i++) {
428 IInstr instr = (IInstr) inst_list[i];
429 if (next_label_pos == i) {
430 cil.CodeLabel (label_info[label_pos].Label);
431 if (label_pos < label_info.Length) {
432 while (next_label_pos == i && ++label_pos < label_info.Length) {
433 if (label_info[label_pos].UseOffset)
434 cil.CodeLabel (label_info[label_pos].Label);
435 next_label_pos = label_info[label_pos].Pos;
438 if (label_pos >= label_info.Length)
439 next_label_pos = -1;
441 if (source != null)
442 source.MarkLocation (instr.Location.line, cil.Offset);
443 instr.Emit (code_gen, this, cil);
446 if (source != null)
447 source.MarkLocation (source.EndLine, cil.Offset);
449 // Generic type parameters
450 if (typar_list != null) {
451 short index = 0;
452 foreach (GenericInfo gi in typar_list) {
453 PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
454 if (gi.ConstraintList != null) {
455 foreach (ITypeRef cnst in gi.ConstraintList) {
456 cnst.Resolve (code_gen);
457 gp.AddConstraint (cnst.PeapiType);
464 public LabelInfo AddLabel (string name)
466 LabelInfo label_info = (LabelInfo) label_table[name];
467 if (label_info != null)
468 return label_info;
469 label_info = new LabelInfo (name, inst_list.Count);
470 label_table.Add (name, label_info);
471 return label_info;
474 public LabelInfo AddLabelRef (string name)
476 LabelInfo label_info = (LabelInfo) label_table[name];
477 if (label_info != null)
478 return label_info;
479 label_info = (LabelInfo) labelref_table[name];
480 if (label_info != null)
481 return label_info;
482 label_info = new LabelInfo (name, -1);
483 labelref_table.Add (name, label_info);
484 return label_info;
487 public LabelInfo AddLabel (int offset)
489 // We go pos + 1 so this line is not counted
490 LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
491 label_list.Add (label_info);
492 return label_info;
495 public LabelInfo AddLabel ()
497 int pos = inst_list.Count;
498 LabelInfo label_info = new LabelInfo (null, inst_list.Count);
499 label_list.Add (label_info);
500 return label_info;
503 public PEAPI.CILLabel GetLabelDef (string name)
505 LabelInfo label_info = (LabelInfo) label_table[name];
507 return label_info.Label;
510 public PEAPI.CILLabel GetLabelDef (int pos)
512 foreach (LabelInfo li in label_list) {
513 if (li.Pos == pos)
514 return li.Label;
516 return null;
519 private void CreateSignature ()
521 if (IsVararg)
522 signature = CreateVarargSignature (name, param_list);
523 else
524 signature = CreateSignature (name, param_list);
527 public static string CreateSignature (string name, IList param_list)
529 StringBuilder builder = new StringBuilder ();
531 builder.Append (name);
532 builder.Append ('(');
534 if (param_list != null) {
535 bool first = true;
536 foreach (ParamDef paramdef in param_list) {
537 if (!first)
538 builder.Append (',');
539 builder.Append (paramdef.TypeName);
540 first = false;
543 builder.Append (')');
545 return builder.ToString ();
548 public static string CreateVarargSignature (string name, IList param_list)
550 StringBuilder builder = new StringBuilder ();
551 ParamDef last = null;
553 builder.Append (name);
554 builder.Append ('(');
556 bool first = true;
557 if (param_list != null) {
558 foreach (ParamDef paramdef in param_list) {
559 if (!first)
560 builder.Append (',');
561 builder.Append (paramdef.TypeName);
562 first = false;
564 last = (ParamDef) param_list[param_list.Count - 1];
568 if (last == null || !last.IsSentinel ()) {
569 if (!first)
570 builder.Append (',');
571 builder.Append ("...");
574 builder.Append (')');
576 return builder.ToString ();
579 public static string CreateVarargSignature (string name, ITypeRef [] param_list)
581 StringBuilder builder = new StringBuilder ();
582 ITypeRef last = null;
584 builder.Append (name);
585 builder.Append ('(');
587 bool first = true;
588 if (param_list != null && param_list.Length > 0) {
589 foreach (ITypeRef param in param_list) {
590 if (!first)
591 builder.Append (',');
592 builder.Append (param.FullName);
593 first = false;
594 last = param;
595 if (param is SentinelTypeRef)
596 break;
601 if (last == null || !(last is SentinelTypeRef)) {
602 if (!first)
603 builder.Append (',');
604 builder.Append ("...");
607 builder.Append (')');
609 return builder.ToString ();
612 public static string CreateSignature (string name, ITypeRef[] param_list)
614 StringBuilder builder = new StringBuilder ();
616 builder.Append (name);
617 builder.Append ('(');
619 if (param_list != null) {
620 bool first = true;
621 foreach (ITypeRef param in param_list) {
622 if (!first)
623 builder.Append (',');
624 builder.Append (param.FullName);
625 first = false;
626 if (param is SentinelTypeRef)
627 break;
630 builder.Append (')');
632 return builder.ToString ();
635 private void CreateNamedParamTable ()
637 if (param_list == null)
638 return;
640 int count = (IsStatic ? 0 : 1);
642 foreach (ParamDef param in param_list) {
643 if (param.Name != null)
644 named_param_table.Add (param.Name, count);
645 count++;
649 private void FixAttributes ()
651 if (name == ".ctor" || name == ".cctor")
652 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
653 // If methods aren't flagged as static they are instance
654 if ((PEAPI.MethAttr.Static & meth_attr) == 0)
655 call_conv |= PEAPI.CallConv.Instance;