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