* MethodDef.cs: Allways set max stack
[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.ImplAttr impl_attr;
51                 private string name;
52                 private string signature;
53                 private ITypeRef ret_type;
54                 private ArrayList param_list;
55                 private ArrayList inst_list;
56                 private Hashtable label_table;
57                 private PEAPI.MethodDef methoddef;
58                 private bool entry_point;
59                 private bool is_resolved;
60                 private bool is_defined;
61                 private ArrayList local_list;
62                 private Hashtable named_local_table;
63                 private bool init_locals;
64                 private int max_stack;
65
66                 public MethodDef (PEAPI.MethAttr meth_attr, PEAPI.ImplAttr impl_attr,
67                                 string name, ITypeRef ret_type, ArrayList param_list)
68                 {
69                         this.meth_attr = meth_attr;
70                         this.impl_attr = impl_attr;
71                         this.name = name;
72                         this.ret_type = ret_type;
73                         this.param_list = param_list;
74
75                         inst_list = new ArrayList ();
76                         label_table = new Hashtable ();
77                         local_list = new ArrayList ();
78                         named_local_table = new Hashtable ();
79                         entry_point = false;
80                         init_locals = false;
81                         max_stack = -1;
82
83                         is_defined = false;
84                         is_resolved = false;
85                         CreateSignature ();
86                 }
87
88                 public string Name {
89                         get { return name; }
90                 }
91
92                 public string Signature {
93                         get { return signature; }
94                 }
95
96                 public PEAPI.MethodDef PeapiMethodDef {
97                         get { return methoddef; }
98                 }
99
100                 public void AddLocals (ArrayList local_list)
101                 {
102                         int slot_pos = this.local_list.Count;
103
104                         foreach (Local local in local_list) {
105                                 if (local.Slot == -1) {
106                                         local.Slot = slot_pos;
107                                 }
108                                 slot_pos++;
109                                 if (local.Name == null)
110                                         continue;
111                                 named_local_table.Add (local.Name, local);
112                         }
113
114                         this.local_list.AddRange (local_list);
115                 }
116
117                 public Local GetNamedLocal (string name)
118                 {
119                         return (Local) named_local_table[name];
120                 }
121
122                 public void InitLocals ()
123                 {
124                         init_locals = true;
125                 }
126
127                 public void EntryPoint ()
128                 {
129                         entry_point = true;
130                 }
131
132                 public void SetMaxStack (int max_stack)
133                 {
134                         this.max_stack = max_stack;
135                 }
136
137                 public PEAPI.MethodDef Resolve (CodeGen code_gen)
138                 {
139                         if (is_resolved)
140                                 return methoddef;
141
142                         PEAPI.Param[] param_array = new PEAPI.Param[param_list.Count];
143                         int count = 0;
144                         ret_type.Resolve (code_gen);
145
146                         foreach (ParamDef paramdef in param_list) {
147                                 paramdef.Define (code_gen);
148                                 param_array[count++] = paramdef.PeapiParam;
149                         }
150
151                         methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
152                                         name, ret_type.PeapiType, param_array);
153
154                         is_resolved = true;
155
156                         return methoddef;
157                 }
158
159                 public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
160                 {
161                         if (is_resolved)
162                                 return methoddef;
163
164                         PEAPI.Param[] param_array = new PEAPI.Param[param_list.Count];
165                         int count = 0;
166                         ret_type.Resolve (code_gen);
167
168                         foreach (ParamDef paramdef in param_list) {
169                                 paramdef.Define (code_gen);
170                                 param_array[count++] = paramdef.PeapiParam;
171                         }
172
173                         methoddef = classdef.AddMethod (meth_attr, impl_attr,
174                                         name, ret_type.PeapiType, param_array);
175
176                         is_resolved = true;
177
178                         return methoddef;
179                 }
180
181                 /// <summary>
182                 ///  Define a global method
183                 /// </summary>
184                 public void Define (CodeGen code_gen)
185                 {
186                         if (is_defined)
187                                 return;
188
189                         Resolve (code_gen);
190
191                         WriteCode (code_gen, methoddef);
192
193                         is_defined = true;
194                 }
195
196                 /// <summary>
197                 ///  Define a member method
198                 /// </summary>
199                 public void Define (CodeGen code_gen, PEAPI.ClassDef classdef)
200                 {
201                         if (is_defined)
202                                 return;
203
204                         Resolve (code_gen, classdef);
205
206                         WriteCode (code_gen, methoddef);
207
208                         is_defined = true;
209                 }
210
211                 public void AddInstr (IInstr instr)
212                 {
213                         inst_list.Add (instr);
214                 }
215
216                 protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
217                 {
218                         if (entry_point)
219                                 methoddef.DeclareEntryPoint ();
220
221                         if (local_list != null) {
222                                 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
223                                 int i = 0;
224
225                                 foreach (Local local in local_list)
226                                         local_array[local.Slot]  = local.GetPeapiLocal (code_gen);
227
228                                 methoddef.AddLocals (local_array, init_locals);
229                         }
230
231                         /// Nothing seems to work if maxstack is not set,
232                         /// i need to find out if this NEEDs to be set
233                         /// and what its default value should be
234                         if (max_stack < 0)
235                                 max_stack = 8;
236                         methoddef.SetMaxStack (max_stack);
237
238                         if (inst_list.Count < 1)
239                                 return;
240
241                         PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
242                         /// Create all the labels
243                         /// TODO: Most labels don't actually need to be created so we could
244                         /// probably only create the ones that need to be
245                         LabelInfo[] label_info = new LabelInfo[label_table.Count];
246                         label_table.Values.CopyTo (label_info, 0);
247                         Array.Sort (label_info);
248
249                         foreach (LabelInfo label in label_info)
250                                 label.Define (cil.NewLabel ());
251
252                         int label_pos = 0;
253                         int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
254
255                         for (int i=0; i<inst_list.Count; i++) {
256                                 IInstr instr = (IInstr) inst_list[i];
257                                 if (next_label_pos == i) {
258                                         cil.CodeLabel (label_info[label_pos].Label);
259                                         if (++label_pos < label_info.Length)
260                                                 next_label_pos = label_info[label_pos].Pos;
261                                         else
262                                                 next_label_pos = -1;
263                                 }
264                                 instr.Emit (code_gen, cil);
265                         }
266
267                 }
268
269                 public void AddLabel (string name)
270                 {
271                         LabelInfo label_info = new LabelInfo (name, inst_list.Count);
272
273                         label_table.Add (name, label_info);
274                 }
275
276                 public PEAPI.CILLabel GetLabelDef (string name)
277                 {
278                         LabelInfo label_info = (LabelInfo) label_table[name];
279
280                         return label_info.Label;
281                 }
282
283                 private void CreateSignature ()
284                 {
285                         signature = CreateSignature (name, param_list);
286                 }
287
288                 public static string CreateSignature (string name, ICollection param_list)
289                 {
290                         StringBuilder builder = new StringBuilder ();
291
292                         builder.Append (name);
293                         builder.Append ('(');
294
295                         bool first = true;
296                         foreach (ParamDef paramdef in param_list) {
297                                 if (!first)
298                                         builder.Append (',');
299                                 builder.Append (paramdef.TypeName);
300                         }
301                         builder.Append (')');
302
303
304                         return builder.ToString ();
305                 }
306         }
307
308 }
309