2005-11-07 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Reflection.Emit / DynamicMethod.cs
1 //
2 // System.Reflection.Emit/DynamicMethod.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //   Zoltan Varga (vargaz@freemail.hu)
7 //
8 // (C) 2003 Ximian, Inc.  http://www.ximian.com
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 #if NET_2_0 || BOOTSTRAP_NET_2_0
35
36 using System;
37 using System.Reflection;
38 using System.Reflection.Emit;
39 using System.Globalization;
40 using System.Runtime.CompilerServices;
41 using System.Runtime.InteropServices;
42
43 namespace System.Reflection.Emit {
44
45 #if NET_2_0
46         [ComVisible (true)]
47 #endif
48         public sealed class DynamicMethod : MethodInfo {
49                 #region Sync with reflection.h
50                 private RuntimeMethodHandle mhandle;
51                 private string name;
52                 private Type returnType;
53                 private Type[] parameters;
54                 private MethodAttributes attributes;
55                 private CallingConventions callingConvention;
56                 private Module module;
57                 private bool skipVisibility;
58                 private bool init_locals = true;
59                 private ILGenerator ilgen;
60                 private int nrefs;
61                 private object[] refs;
62                 #endregion
63                 private Delegate deleg;
64                 private MonoMethod method;
65                 private ParameterBuilder[] pinfo;
66
67                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m) : this (name, returnType, parameterTypes, m, false) {
68                 }
69
70                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner) : this (name, returnType, parameterTypes, owner, false) {
71                 }
72
73                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, m, skipVisibility) {
74                 }
75
76                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, owner, skipVisibility) {
77                 }
78
79                 public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, attributes, callingConvention, returnType, parameterTypes, owner.Module, skipVisibility) {
80                 }
81
82                 public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) {
83                         if (name == null)
84                                 throw new ArgumentNullException ("name");
85                         if (name == String.Empty)
86                                 throw new ArgumentException ("Name can't be empty", "name");
87                         if (returnType == null)
88                                 throw new ArgumentNullException ("returnType");
89                         if (m == null)
90                                 throw new ArgumentNullException ("m");
91                         if (returnType.IsByRef)
92                                 throw new ArgumentException ("Return type can't be a byref type", "returnType");
93                         if (parameterTypes != null) {
94                                 for (int i = 0; i < parameterTypes.Length; ++i)
95                                         if (parameterTypes [i] == null)
96                                                 throw new ArgumentException ("Parameter " + i + " is null", "parameterTypes");
97                         }
98
99                         this.name = name;
100                         this.attributes = attributes | MethodAttributes.Static;
101                         this.callingConvention = callingConvention;
102                         this.returnType = returnType;
103                         this.parameters = parameterTypes;
104                         this.module = m;
105                         this.skipVisibility = skipVisibility;
106                 }
107
108                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
109                 private extern void create_dynamic_method (DynamicMethod m);
110
111                 private void CreateDynMethod () {
112                         if (mhandle.Value == IntPtr.Zero) {
113                                 if (ilgen != null)
114                                         ilgen.label_fixup ();
115                                 create_dynamic_method (this);
116                         }
117                 }
118
119                 [ComVisible (true)]
120                 public Delegate CreateDelegate (Type delegateType)
121                 {
122                         if (delegateType == null)
123                                 throw new ArgumentNullException ("delegateType");
124                         if (deleg != null)
125                                 return deleg;
126
127                         CreateDynMethod ();
128
129                         deleg = Delegate.CreateDelegate (delegateType, this);
130                         return deleg;
131                 }
132
133                 [ComVisible (true)]
134                 public Delegate CreateDelegate (Type delegateType, object target)
135                 {
136                         if (delegateType == null)
137                                 throw new ArgumentNullException ("delegateType");
138
139                         CreateDynMethod ();
140
141                         /* Can't cache the delegate since it is different for each target */
142                         return Delegate.CreateDelegate (delegateType, target, this);
143                 }
144                 
145                 [MonoTODO]
146                 public ParameterBuilder DefineParameter (int position, ParameterAttributes attributes, string strParamName)
147                 {
148                         //
149                         // Extension: Mono allows position == 0 for the return attribute
150                         //
151                         if ((position < 0) || (position > parameters.Length))
152                                 throw new ArgumentOutOfRangeException ("position");
153
154                         RejectIfCreated ();
155
156                         throw new NotImplementedException ();
157                 }
158
159                 public override MethodInfo GetBaseDefinition () {
160                         return this;
161                 }
162
163                 [MonoTODO]
164                 public override object[] GetCustomAttributes (bool inherit) {
165                         throw new NotImplementedException ();
166                 }
167
168                 [MonoTODO]
169                 public override object[] GetCustomAttributes (Type attributeType,
170                                                                                                           bool inherit) {
171                         throw new NotImplementedException ();
172                 }
173
174                 public ILGenerator GetILGenerator () {
175                         return GetILGenerator (64);
176                 }
177
178                 public ILGenerator GetILGenerator (int size) {
179                         if (((GetMethodImplementationFlags () & MethodImplAttributes.CodeTypeMask) != 
180                                  MethodImplAttributes.IL) ||
181                                 ((GetMethodImplementationFlags () & MethodImplAttributes.ManagedMask) != 
182                                  MethodImplAttributes.Managed))
183                                 throw new InvalidOperationException ("Method body should not exist.");
184                         if (ilgen != null)
185                                 return ilgen;
186                         ilgen = new ILGenerator (Module, new DynamicMethodTokenGenerator (this), size);
187                         return ilgen;
188                 }               
189
190                 public override MethodImplAttributes GetMethodImplementationFlags () {
191                         return MethodImplAttributes.IL | MethodImplAttributes.Managed;
192                 }
193
194                 public override ParameterInfo[] GetParameters () {
195                         if (parameters == null)
196                                 return new ParameterInfo [0];
197
198                         ParameterInfo[] retval = new ParameterInfo [parameters.Length];
199                         for (int i = 0; i < parameters.Length; i++) {
200                                 retval [i] = new ParameterInfo (pinfo == null ? null : pinfo [i + 1], parameters [i], this, i + 1);
201                         }
202                         return retval;
203                 }
204
205                 public override object Invoke (object obj, object[] parameters) {
206                         CreateDynMethod ();
207                         if (method == null)
208                                 method = new MonoMethod (mhandle);
209                         return method.Invoke (obj, parameters);
210                 }
211
212                 public override object Invoke (object obj, BindingFlags invokeAttr,
213                                                                            Binder binder, object[] parameters,
214                                                                            CultureInfo culture) {
215                         CreateDynMethod ();
216                         if (method == null)
217                                 method = new MonoMethod (mhandle);
218                         return method.Invoke (obj, parameters);
219                 }
220
221                 [MonoTODO]
222                 public override bool IsDefined (Type attributeType, bool inherit) {
223                         throw new NotImplementedException ();
224                 }
225
226                 public override string ToString () {
227                         string parms = "";
228                         ParameterInfo[] p = GetParameters ();
229                         for (int i = 0; i < p.Length; ++i) {
230                                 if (i > 0)
231                                         parms = parms + ", ";
232                                 parms = parms + p [i].ParameterType.Name;
233                         }
234                         return ReturnType.Name+" "+Name+"("+parms+")";
235                 }
236
237                 public override MethodAttributes Attributes {
238                         get {
239                                 return attributes;
240                         }
241                 }
242
243                 public override CallingConventions CallingConvention {
244                         get {
245                                 return callingConvention;
246                         }
247                 }
248
249                 public override Type DeclaringType {
250                         get {
251                                 return null;
252                         }
253                 }
254
255                 public bool InitLocals {
256                         get {
257                                 return init_locals;
258                         }
259                         set {
260                                 init_locals = value;
261                         }
262                 }
263
264                 public override RuntimeMethodHandle MethodHandle {
265                         get {
266                                 return mhandle;
267                         }
268                 }
269
270                 public override Module Module {
271                         get {
272                                 return module;
273                         }
274                 }
275
276                 public override string Name {
277                         get {
278                                 return name;
279                         }
280                 }
281
282                 public override Type ReflectedType {
283                         get {
284                                 return null;
285                         }
286                 }
287
288                 [MonoTODO]
289                 public ParameterInfo ReturnParameter {
290                         get {
291                                 throw new NotImplementedException ();
292                         }
293                 }
294
295                 public override Type ReturnType {
296                         get {
297                                 return returnType;
298                         }
299                 }
300
301                 [MonoTODO]
302                 public override ICustomAttributeProvider ReturnTypeCustomAttributes {
303                         get {
304                                 throw new NotImplementedException ();
305                         }
306                 }
307
308                 public override int MetadataToken {
309                         get {
310                                 return 0;
311                         }
312                 }
313
314                 private void RejectIfCreated () {
315                         if (mhandle.Value != IntPtr.Zero)
316                                 throw new InvalidOperationException ("Type definition of the method is complete.");
317                 }
318
319                 private Exception NotSupported () {
320                         return new NotSupportedException ("The invoked member is not supported on a dynamic method.");
321                 }
322
323                 internal int AddRef (object reference) {
324                         if (refs == null)
325                                 refs = new object [4];
326                         if (nrefs >= refs.Length - 1) {
327                                 object [] new_refs = new object [refs.Length * 2];
328                                 System.Array.Copy (refs, new_refs, refs.Length);
329                                 refs = new_refs;
330                         }
331                         refs [nrefs] = reference;
332                         /* Reserved by the runtime */
333                         refs [nrefs + 1] = null;
334                         nrefs += 2;
335                         return nrefs - 1;
336                 }
337         }
338
339         internal class DynamicMethodTokenGenerator : TokenGenerator {
340
341                 private DynamicMethod m;
342
343                 public DynamicMethodTokenGenerator (DynamicMethod m) {
344                         this.m = m;
345                 }
346
347                 public int GetToken (string str) {
348                         return m.AddRef (str);
349                 }
350
351                 public int GetToken (MethodInfo method, Type[] opt_param_types) {
352                         throw new InvalidOperationException ();
353                 }
354
355                 public int GetToken (MemberInfo member) {
356                         return m.AddRef (member);
357                 }
358
359                 public int GetToken (SignatureHelper helper) {
360                         return m.AddRef (helper);
361                 }
362         }
363 }
364
365 #endif