* InstrTable.cs: Add Calli, detabify
[mono.git] / mcs / ilasm / codegen / MethodTable.cs
1 //
2 // Mono.ILASM.MethodTable.cs
3 //
4 // Author(s):
5 //  Jackson Harper (Jackson@LatitudeGeo.com)
6 //
7 // (C) 2003 Jackson Harper, All rights reserved
8 //
9
10 using PEAPI;
11 using System;
12 using System.Text;
13 using System.Collections;
14
15 namespace Mono.ILASM {
16
17
18         public delegate void MethodDefinedEvent (object sender, MethodDefinedEventArgs args);
19         public delegate void MethodReferencedEvent (object sender, MethodReferencedEventArgs args);
20
21         public class MethodEventArgs : EventArgs {
22                 
23                 public readonly string Signature;
24                 public readonly string Name;
25                 public readonly TypeRef ReturnType;
26                 public readonly Param[] ParamList;
27                 public readonly bool IsInTable;
28
29                 public MethodEventArgs (string signature, string name,
30                         TypeRef return_type, Param[] param_list, bool is_in_table) 
31                 {
32                         Signature = signature;
33                         Name = name;
34                         ReturnType = return_type;
35                         ParamList = param_list;
36                         IsInTable = is_in_table;
37                 }
38         }
39
40         public class MethodDefinedEventArgs : MethodEventArgs {
41
42                 public readonly MethAttr MethodAttributes;
43                 public readonly ImplAttr ImplAttributes;
44                 public readonly CallConv CallConv;
45                 
46                 public MethodDefinedEventArgs (string signature, string name, 
47                         TypeRef return_type, Param[] param_list, bool is_in_table, MethAttr method_attr, 
48                         ImplAttr impl_attr, CallConv call_conv) : base (signature, name, 
49                         return_type, param_list, is_in_table)
50                 {
51                         MethodAttributes = method_attr;
52                         ImplAttributes = impl_attr;
53                         CallConv = call_conv;
54                 }
55         }
56
57         public class MethodReferencedEventArgs : MethodEventArgs {
58                 
59                 public MethodReferencedEventArgs (string signature, string name, 
60                         TypeRef return_type, Param[] param_list, bool is_in_table) : base (signature, name, 
61                         return_type, param_list, is_in_table)
62                 {
63
64                 }
65         }
66
67
68         public class MethodTable {
69
70                 private class MethodTableItem {
71                 
72                         private static readonly int DefinedFlag = 2;
73         
74                         private int flags;
75
76                         public ArrayList LocationList;
77                         public MethodDef Method;
78
79                         public MethodTableItem (MethodDef method, Location location)
80                         {
81                                 flags = 0;
82                                 Method = method;
83                                 LocationList = new ArrayList ();
84                                 LocationList.Add (location);
85                         }
86                 
87                         public bool Defined {
88                                 get { return ((flags & DefinedFlag) != 0); }
89                                 set {
90                                         if (value)
91                                                 flags |= DefinedFlag;
92                                         else
93                                                 flags ^= DefinedFlag;
94                                 }
95                         }
96                 }
97
98                 protected Hashtable table;
99                 protected ClassDef parent_class;
100                 
101                 public static event MethodReferencedEvent MethodReferencedEvent;
102                 public static event MethodDefinedEvent MethodDefinedEvent;
103
104                 public MethodTable (ClassDef parent_class)
105                 {
106                         this.parent_class = parent_class;
107                         table = new Hashtable ();
108                 }
109
110                 public Method GetReference (string name, TypeRef return_type, 
111                         Param[] param_list, TypeRef[] param_type_list, Location location)
112                 {
113                         string signature = GetSignature (name, return_type, param_type_list);
114
115                         if (MethodReferencedEvent != null)
116                                 MethodReferencedEvent (this, new MethodReferencedEventArgs (signature, name,
117                                         return_type, param_list, table.Contains (signature)));
118
119                         MethodTableItem item = table[signature] as MethodTableItem;
120                         
121                         if (item != null) {
122                                 item.LocationList.Add (location);
123                                 return item.Method;
124                         }
125                         
126                         MethodDef method = parent_class.AddMethod (name, return_type.Type,
127                                 param_list);
128                         
129                         AddReferenced (signature, method, location);
130
131                         return method;
132                 }
133         
134                 public MethodDef AddDefinition (MethAttr method_attr, ImplAttr impl_attr, CallConv call_conv, 
135                         string name, TypeRef return_type, Param[] param_list, 
136                         TypeRef[] param_type_list, Location location) 
137                 {
138                         string signature = GetSignature (name, return_type, param_type_list);
139
140                         if (MethodDefinedEvent != null)
141                                 MethodDefinedEvent (this, new MethodDefinedEventArgs (signature, name,
142                                         return_type, param_list, table.Contains (signature), method_attr, 
143                                         impl_attr, call_conv));
144
145                         MethodTableItem item = (MethodTableItem) table[signature];
146                         
147                         if (item == null) {
148                                 MethodDef method = parent_class.AddMethod (method_attr, impl_attr, name, 
149                                         return_type.Type, param_list);
150                                 method.AddCallConv (call_conv);
151                                 AddDefined (signature, method, location);
152                                 return method;
153                         }
154                         
155                         item.Method.AddMethAttribute (method_attr);
156                         item.Method.AddImplAttribute (impl_attr);
157                         item.Method.AddCallConv (call_conv);
158                         item.Defined = true;
159                 
160                         return item.Method;
161                 }
162
163                 public bool CheckDefined ()
164                 {
165                         foreach (DictionaryEntry dic_entry in table) {
166                                 MethodTableItem table_item = (MethodTableItem) dic_entry.Value;
167                                 if (table_item.Defined)
168                                         continue;
169                                 throw new Exception (String.Format ("Method: {0} is not defined.", dic_entry.Key));
170                         }
171                         return true;
172                 }
173                                         
174                 protected string GetSignature (string name, TypeRef return_type, 
175                         TypeRef[] param_list)
176                 {
177                         StringBuilder builder = new StringBuilder ();
178                         
179                         builder.Append (return_type.FullName);
180                         builder.Append ('_');
181                         builder.Append (name);
182                         builder.Append ('(');
183                         
184                         bool first = true;
185                         foreach (TypeRef type_ref in param_list) {
186                                 if (!first)
187                                         builder.Append (',');
188                                 builder.Append (type_ref.FullName);
189                         }
190                         builder.Append (')');
191
192                         return builder.ToString ();
193                 }
194
195                 protected void AddDefined (string signature, MethodDef method, Location location)
196                 {
197                         if (table.Contains (signature))
198                                 return; 
199
200                         MethodTableItem item = new MethodTableItem (method, location);
201                         item.Defined = true;
202
203                         table[signature] = item;
204                 }
205
206                 protected void AddReferenced (string signature, MethodDef method, Location location)
207                 {
208                         MethodTableItem item = new MethodTableItem (method, location);
209                         
210                         table[signature] = item;
211                 }
212
213                 /// <summary>
214                 ///  If a method is allready defined throw an Error
215                 /// </summary>
216                 protected void CheckExists (string signature) 
217                 {
218                         MethodTableItem item = table[signature] as MethodTableItem;
219                         
220                         if ((item != null) && (item.Defined)) {
221                                 throw new Exception (String.Format ("Method: {0} defined in multiple locations.", 
222                                         signature));
223                         }
224                 }
225         }
226
227 }
228