* IInstr.cs: Instructions now get their parent method when being
[mono.git] / mcs / ilasm / codegen / MethodDef.cs
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 //
9
10
11 using System;
12 using System.Text;
13 using System.Collections;
14
15
16 namespace Mono.ILASM {
17
18         public class MethodDef {
19
20                 protected class LabelInfo : IComparable {
21
22                         public readonly string Name;
23                         public readonly int Pos;
24                         public PEAPI.CILLabel Label;
25
26                         public LabelInfo (string name, int pos)
27                         {
28                                 Name = name;
29                                 Pos = pos;
30                                 Label = null;
31                         }
32
33                         public void Define (PEAPI.CILLabel label)
34                         {
35                                 Label = label;
36                         }
37
38                         public int CompareTo (object obj)
39                         {
40                                 LabelInfo other = obj as LabelInfo;
41
42                                 if(other != null)
43                                         return Pos.CompareTo(other.Pos);
44
45                                 throw new ArgumentException ("object is not a LabelInfo");
46                         }
47                 }
48
49                 private PEAPI.MethAttr meth_attr;
50                 private PEAPI.CallConv call_conv;
51                 private PEAPI.ImplAttr impl_attr;
52                 private string name;
53                 private string signature;
54                 private ITypeRef ret_type;
55                 private ArrayList param_list;
56                 private Hashtable named_param_table;
57                 private ArrayList inst_list;
58                 private ArrayList customattr_list;
59                 private Hashtable label_table;
60                 private PEAPI.MethodDef methoddef;
61                 private bool entry_point;
62                 private bool is_resolved;
63                 private bool is_defined;
64                 private ArrayList local_list;
65                 private Hashtable named_local_table;
66                 private bool init_locals;
67                 private int max_stack;
68                 private Random label_random;
69
70                 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.CallConv call_conv,
71                                 PEAPI.ImplAttr impl_attr, string name,
72                                 ITypeRef ret_type, ArrayList param_list)
73                 {
74                         this.meth_attr = meth_attr;
75                         this.call_conv = call_conv;
76                         this.impl_attr = impl_attr;
77                         this.name = name;
78                         this.ret_type = ret_type;
79                         this.param_list = param_list;
80
81                         inst_list = new ArrayList ();
82                         customattr_list = new ArrayList ();
83                         label_table = new Hashtable ();
84                         local_list = new ArrayList ();
85                         named_local_table = new Hashtable ();
86                         named_param_table = new Hashtable ();
87                         label_random = new Random ();
88                         entry_point = false;
89                         init_locals = false;
90                         max_stack = -1;
91
92                         is_defined = false;
93                         is_resolved = false;
94                         CreateSignature ();
95                         CreateNamedParamTable ();
96                 }
97
98                 public string Name {
99                         get { return name; }
100                 }
101
102                 public string Signature {
103                         get { return signature; }
104                 }
105
106                 public PEAPI.MethodDef PeapiMethodDef {
107                         get { return methoddef; }
108                 }
109
110                 public bool IsVararg {
111                         get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
112                 }
113
114                 public void AddLocals (ArrayList local_list)
115                 {
116                         int slot_pos = this.local_list.Count;
117
118                         foreach (Local local in local_list) {
119                                 if (local.Slot == -1) {
120                                         local.Slot = slot_pos;
121                                 }
122                                 slot_pos++;
123                                 if (local.Name == null)
124                                         continue;
125                                 named_local_table.Add (local.Name, local);
126                         }
127
128                         this.local_list.AddRange (local_list);
129                 }
130
131                 public Local GetNamedLocal (string name)
132                 {
133                         return (Local) named_local_table[name];
134                 }
135
136                 public int GetNamedLocalSlot (string name)
137                 {
138                         Local local = (Local) named_local_table[name];
139
140                         return local.Slot;
141                 }
142
143                 public int GetNamedParamPos (string name)
144                 {
145                         int pos = (int) named_param_table[name];
146
147                         return pos;
148                 }
149
150                 public void InitLocals ()
151                 {
152                         init_locals = true;
153                 }
154
155                 public void EntryPoint ()
156                 {
157                         entry_point = true;
158                 }
159
160                 public void SetMaxStack (int max_stack)
161                 {
162                         this.max_stack = max_stack;
163                 }
164
165                 public void AddCustomAttr (CustomAttr customattr)
166                 {
167                         customattr_list.Add (customattr);
168                 }
169
170                 public PEAPI.MethodDef Resolve (CodeGen code_gen)
171                 {
172                         if (is_resolved)
173                                 return methoddef;
174
175                         PEAPI.Param[] param_array;
176
177                         if (param_list != null) {
178                                 int param_count = param_list.Count;
179                                 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)
180                                         param_count--;
181                                 param_array = new PEAPI.Param[param_count];
182                                 int count = 0;
183
184                                 foreach (ParamDef paramdef in param_list) {
185                                         if (paramdef == ParamDef.Ellipsis)
186                                                 break;
187                                         paramdef.Define (code_gen);
188                                         param_array[count++] = paramdef.PeapiParam;
189                                 }
190                         } else {
191                                 param_array = new PEAPI.Param[0];
192                         }
193
194                         FixAttributes ();
195                         ret_type.Resolve (code_gen);
196
197                         methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
198                                         name, ret_type.PeapiType, param_array);
199
200                         methoddef.AddCallConv (call_conv);
201                         is_resolved = true;
202
203                         return methoddef;
204                 }
205
206                 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
207                 {
208                         if (is_resolved)
209                                 return methoddef;
210
211                         PEAPI.Param[] param_array;
212
213                         if (param_list != null) {
214                                 int param_count = param_list.Count;
215                                 if (IsVararg && param_list[param_count-1] == ParamDef.Ellipsis)         
216                                         param_count--;
217                                 param_array = new PEAPI.Param[param_count];
218                                 int count = 0;
219                                 
220                                 foreach (ParamDef paramdef in param_list) {
221                                         if (paramdef == ParamDef.Ellipsis)
222                                                 break;
223                                         paramdef.Define (code_gen);
224                                         param_array[count++] = paramdef.PeapiParam;
225                                 }
226                         } else {
227                                 param_array = new PEAPI.Param[0];
228                         }
229
230                         FixAttributes ();
231                         ret_type.Resolve (code_gen);
232
233                         methoddef = classdef.AddMethod (meth_attr, impl_attr,
234                                         name, ret_type.PeapiType, param_array);
235
236                         methoddef.AddCallConv (call_conv);
237                         is_resolved = true;
238
239                         return methoddef;
240                 }
241
242                 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
243                 {
244                         if (!is_resolved)
245                                 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
246
247                         return methoddef.MakeVarArgSignature (opt);
248                 }
249
250                 /// <summary>
251                 ///  Define a global method
252                 /// </summary>
253                 public void Define (CodeGen code_gen)
254                 {
255                         if (is_defined)
256                                 return;
257
258                         Resolve (code_gen);
259
260                         WriteCode (code_gen, methoddef);
261
262                         is_defined = true;
263                 }
264
265                 /// <summary>
266                 ///  Define a member method
267                 /// </summary>
268                 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
269                 {
270                         if (is_defined)
271                                 return;
272
273                         Resolve (code_gen, classdef);
274
275                         WriteCode (code_gen, methoddef);
276
277                         is_defined = true;
278                 }
279
280                 public void AddInstr (IInstr instr)
281                 {
282                         inst_list.Add (instr);
283                 }
284
285                 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
286                 {
287                         if (entry_point)
288                                 methoddef.DeclareEntryPoint ();
289
290                         if (local_list != null) {
291                                 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
292                                 int i = 0;
293
294                                 foreach (Local local in local_list)
295                                         local_array[local.Slot]  = local.GetPeapiLocal (code_gen);
296
297                                 methoddef.AddLocals (local_array, init_locals);
298                         }
299
300                         /// Nothing seems to work if maxstack is not set,
301                         /// i need to find out if this NEEDs to be set
302                         /// and what its default value should be
303                         if (max_stack < 0)
304                                 max_stack = 8;
305                         methoddef.SetMaxStack (max_stack);
306
307                         /// Add the custrom attributes to this method
308                         foreach (CustomAttr customattr in customattr_list)
309                                 customattr.AddTo (code_gen, methoddef);
310
311                         if (inst_list.Count < 1)
312                                 return;
313
314                         PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
315                         /// Create all the labels
316                         /// TODO: Most labels don't actually need to be created so we could
317                         /// probably only create the ones that need to be
318                         LabelInfo[] label_info = new LabelInfo[label_table.Count];
319                         label_table.Values.CopyTo (label_info, 0);
320                         int previous_pos = -1;
321                         LabelInfo previous_label = null;
322                         Array.Sort (label_info);
323
324                         foreach (LabelInfo label in label_info) {
325                                 if (label.Pos == previous_pos)
326                                         label.Label = previous_label.Label;
327                                 else
328                                         label.Define (cil.NewLabel ());
329                                 previous_label = label;
330                                 previous_pos = label.Pos;
331                         }
332
333                         int label_pos = 0;
334                         int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
335
336                         for (int i=0; i<inst_list.Count; i++) {
337                                 IInstr instr = (IInstr) inst_list[i];
338                                 if (next_label_pos == i) {
339                                         cil.CodeLabel (label_info[label_pos].Label);
340                                         if (label_pos < label_info.Length) {
341                                                 while (next_label_pos == i && ++label_pos < label_info.Length)
342                                                         next_label_pos = label_info[label_pos].Pos;
343                                         }
344                                         if (label_pos >= label_info.Length)
345                                                 next_label_pos = -1;
346                                 }
347                                 instr.Emit (code_gen, this, cil);
348                         }
349
350                 }
351
352                 public void AddLabel (string name)
353                 {
354                         LabelInfo label_info = new LabelInfo (name, inst_list.Count);
355
356                         label_table.Add (name, label_info);
357                 }
358
359                 /// TODO: This whole process is kinda a hack.
360                 public string RandomLabel ()
361                 {
362                         int rand = label_random.Next ();
363                         string name = rand.ToString ();
364                         LabelInfo label_info = new LabelInfo (name, inst_list.Count);
365
366                         label_table.Add (name, label_info);
367                         return name;
368                 }
369
370                 public PEAPI.CILLabel GetLabelDef (string name)
371                 {
372                         LabelInfo label_info = (LabelInfo) label_table[name];
373
374                         return label_info.Label;
375                 }
376
377                 private void CreateSignature ()
378                 {
379                         signature = CreateSignature (name, param_list);
380                 }
381
382                 public static string CreateSignature (string name, IList param_list)
383                 {
384                         StringBuilder builder = new StringBuilder ();
385
386                         builder.Append (name);
387                         builder.Append ('(');
388
389                         if (param_list != null) {
390                                 bool first = true;
391                                 foreach (ParamDef paramdef in param_list) {
392                                         if (ParamDef.Ellipsis == paramdef)
393                                                 break;
394                                         if (!first)
395                                                 builder.Append (',');
396                                         builder.Append (paramdef.TypeName);
397                                         first = false;
398                                 }
399                         }
400                         builder.Append (')');
401
402                         return builder.ToString ();
403                 }
404
405                 public static string CreateSignature (string name, ITypeRef[] param_list)
406                 {
407                         StringBuilder builder = new StringBuilder ();
408
409                         builder.Append (name);
410                         builder.Append ('(');
411
412                         if (param_list != null) {
413                                 bool first = true;
414                                 foreach (ITypeRef param in param_list) {
415                                         if (param == TypeRef.Ellipsis)
416                                                 break;
417                                         if (!first)
418                                                 builder.Append (',');
419                                         builder.Append (param.FullName);
420                                         first = false;
421                                 }
422                         }
423                         builder.Append (')');
424
425                         return builder.ToString ();
426                 }
427
428                 private void CreateNamedParamTable ()
429                 {
430                         if (param_list == null)
431                                 return;
432
433                         int count = 0;
434                         foreach (ParamDef param in param_list) {
435                                 if (param.Name != null)
436                                         named_param_table.Add (param.Name, count);
437                                 count++;
438                         }
439                 }
440
441                 private void FixAttributes ()
442                 {
443                         if (name == ".ctor" || name == ".cctor")
444                                 meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
445                         // If methods aren't flagged as static they are instance
446                         if ((PEAPI.MethAttr.Static & meth_attr) == 0)
447                                 call_conv |= PEAPI.CallConv.Instance;
448                 }
449
450         }
451
452 }
453