2008-03-06 Zoltan Varga <vargaz@gmail.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                 private IntPtr referenced_by;
63                 private Type owner;
64                 #endregion
65                 private Delegate deleg;
66                 private MonoMethod method;
67                 private ParameterBuilder[] pinfo;
68                 internal bool creating;
69
70                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m) : this (name, returnType, parameterTypes, m, false) {
71                 }
72
73                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner) : this (name, returnType, parameterTypes, owner, false) {
74                 }
75
76                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, m, skipVisibility) {
77                 }
78
79                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, owner, skipVisibility) {
80                 }
81
82                 public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type owner, bool skipVisibility) : this (name, attributes, callingConvention, returnType, parameterTypes, owner, owner.Module, skipVisibility, false) {
83                 }
84
85                 public DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Module m, bool skipVisibility) : this (name, attributes, callingConvention, returnType, parameterTypes, null, m, skipVisibility, false) {
86                 }
87
88                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes) : this (name, returnType, parameterTypes, false) {
89                 }
90
91                 public DynamicMethod (string name, Type returnType, Type[] parameterTypes, bool skipVisibility) : this (name, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, null, null, false, true) {
92                 }
93
94                 DynamicMethod (string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type [] parameterTypes, Type owner, Module m, bool skipVisibility, bool anonHosted)
95                 {
96                         if (name == null)
97                                 throw new ArgumentNullException ("name");
98                         if (returnType == null)
99                                 returnType = typeof (void);
100                         if ((m == null) && !anonHosted)
101                                 throw new ArgumentNullException ("m");
102                         if (returnType.IsByRef)
103                                 throw new ArgumentException ("Return type can't be a byref type", "returnType");
104                         if (parameterTypes != null) {
105                                 for (int i = 0; i < parameterTypes.Length; ++i)
106                                         if (parameterTypes [i] == null)
107                                                 throw new ArgumentException ("Parameter " + i + " is null", "parameterTypes");
108                         }
109
110                         if (m == null)
111                                 m = AnonHostModuleHolder.anon_host_module;
112
113                         this.name = name;
114                         this.attributes = attributes | MethodAttributes.Static;
115                         this.callingConvention = callingConvention;
116                         this.returnType = returnType;
117                         this.parameters = parameterTypes;
118                         this.owner = owner;
119                         this.module = m;
120                         this.skipVisibility = skipVisibility;
121                 }
122
123                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
124                 private extern void create_dynamic_method (DynamicMethod m);
125
126                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
127                 private extern void destroy_dynamic_method (DynamicMethod m);
128
129                 private void CreateDynMethod () {
130                         if (mhandle.Value == IntPtr.Zero) {
131                                 if (ilgen == null || (ILGenerator.Mono_GetCurrentOffset (ilgen) == 0))
132                                         throw new InvalidOperationException ("Method '" + name + "' does not have a method body.");
133
134                                 ilgen.label_fixup ();
135
136                                 // Have to create all DynamicMethods referenced by this one
137                                 try {
138                                         // Used to avoid cycles
139                                         creating = true;
140                                         if (refs != null) {
141                                                 for (int i = 0; i < refs.Length; ++i) {
142                                                         if (refs [i] is DynamicMethod) {
143                                                                 DynamicMethod m = (DynamicMethod)refs [i];
144                                                                 if (!m.creating)
145                                                                         m.CreateDynMethod ();
146                                                         }
147                                                 }
148                                         }
149                                 } finally {
150                                         creating = false;
151                                 }
152
153                                 create_dynamic_method (this);
154                         }
155                 }
156
157                 ~DynamicMethod ()
158                 {
159                         destroy_dynamic_method (this);
160                 }
161
162                 [ComVisible (true)]
163                 public Delegate CreateDelegate (Type delegateType)
164                 {
165                         if (delegateType == null)
166                                 throw new ArgumentNullException ("delegateType");
167                         if (deleg != null)
168                                 return deleg;
169
170                         CreateDynMethod ();
171
172                         deleg = Delegate.CreateDelegate (delegateType, this);
173                         return deleg;
174                 }
175
176                 [ComVisible (true)]
177                 public Delegate CreateDelegate (Type delegateType, object target)
178                 {
179                         if (delegateType == null)
180                                 throw new ArgumentNullException ("delegateType");
181
182                         CreateDynMethod ();
183
184                         /* Can't cache the delegate since it is different for each target */
185                         return Delegate.CreateDelegate (delegateType, target, this);
186                 }
187                 
188                 public ParameterBuilder DefineParameter (int position, ParameterAttributes attributes, string strParamName)
189                 {
190                         //
191                         // Extension: Mono allows position == 0 for the return attribute
192                         //
193                         if ((position < 0) || (position > parameters.Length))
194                                 throw new ArgumentOutOfRangeException ("position");
195
196                         RejectIfCreated ();
197
198                         ParameterBuilder pb = new ParameterBuilder (this, position, attributes, strParamName);
199                         if (pinfo == null)
200                                 pinfo = new ParameterBuilder [parameters.Length + 1];
201                         pinfo [position] = pb;
202                         return pb;
203                 }
204
205                 public override MethodInfo GetBaseDefinition () {
206                         return this;
207                 }
208
209                 [MonoTODO("Not implemented")]
210                 public override object[] GetCustomAttributes (bool inherit) {
211                         throw new NotImplementedException ();
212                 }
213
214                 [MonoTODO("Not implemented")]
215                 public override object[] GetCustomAttributes (Type attributeType,
216                                                                                                           bool inherit) {
217                         throw new NotImplementedException ();
218                 }
219
220                 [MonoTODO("Not implemented")]
221                 public DynamicILInfo GetDynamicILInfo () {
222                         throw new NotImplementedException ();
223                 }
224
225                 public ILGenerator GetILGenerator () {
226                         return GetILGenerator (64);
227                 }
228
229                 public ILGenerator GetILGenerator (int size) {
230                         if (((GetMethodImplementationFlags () & MethodImplAttributes.CodeTypeMask) != 
231                                  MethodImplAttributes.IL) ||
232                                 ((GetMethodImplementationFlags () & MethodImplAttributes.ManagedMask) != 
233                                  MethodImplAttributes.Managed))
234                                 throw new InvalidOperationException ("Method body should not exist.");
235                         if (ilgen != null)
236                                 return ilgen;
237                         ilgen = new ILGenerator (Module, new DynamicMethodTokenGenerator (this), size);
238                         return ilgen;
239                 }               
240
241                 public override MethodImplAttributes GetMethodImplementationFlags () {
242                         return MethodImplAttributes.IL | MethodImplAttributes.Managed;
243                 }
244
245                 public override ParameterInfo[] GetParameters () {
246                         if (parameters == null)
247                                 return new ParameterInfo [0];
248
249                         ParameterInfo[] retval = new ParameterInfo [parameters.Length];
250                         for (int i = 0; i < parameters.Length; i++) {
251                                 retval [i] = new ParameterInfo (pinfo == null ? null : pinfo [i + 1], parameters [i], this, i + 1);
252                         }
253                         return retval;
254                 }
255
256                 /*
257                 public override object Invoke (object obj, object[] parameters) {
258                         CreateDynMethod ();
259                         if (method == null)
260                                 method = new MonoMethod (mhandle);
261                         return method.Invoke (obj, parameters);
262                 }
263                 */
264
265                 public override object Invoke (object obj, BindingFlags invokeAttr,
266                                                                            Binder binder, object[] parameters,
267                                                                            CultureInfo culture) {
268                         CreateDynMethod ();
269                         if (method == null)
270                                 method = new MonoMethod (mhandle);
271                         return method.Invoke (obj, parameters);
272                 }
273
274                 [MonoTODO("Not implemented")]
275                 public override bool IsDefined (Type attributeType, bool inherit) {
276                         throw new NotImplementedException ();
277                 }
278
279                 public override string ToString () {
280                         string parms = String.Empty;
281                         ParameterInfo[] p = GetParameters ();
282                         for (int i = 0; i < p.Length; ++i) {
283                                 if (i > 0)
284                                         parms = parms + ", ";
285                                 parms = parms + p [i].ParameterType.Name;
286                         }
287                         return ReturnType.Name+" "+Name+"("+parms+")";
288                 }
289
290                 public override MethodAttributes Attributes {
291                         get {
292                                 return attributes;
293                         }
294                 }
295
296                 public override CallingConventions CallingConvention {
297                         get {
298                                 return callingConvention;
299                         }
300                 }
301
302                 public override Type DeclaringType {
303                         get {
304                                 return null;
305                         }
306                 }
307
308                 public bool InitLocals {
309                         get {
310                                 return init_locals;
311                         }
312                         set {
313                                 init_locals = value;
314                         }
315                 }
316
317                 public override RuntimeMethodHandle MethodHandle {
318                         get {
319                                 return mhandle;
320                         }
321                 }
322
323                 public override Module Module {
324                         get {
325                                 return module;
326                         }
327                 }
328
329                 public override string Name {
330                         get {
331                                 return name;
332                         }
333                 }
334
335                 public override Type ReflectedType {
336                         get {
337                                 return null;
338                         }
339                 }
340
341                 [MonoTODO("Not implemented")]
342                 public override ParameterInfo ReturnParameter {
343                         get {
344                                 throw new NotImplementedException ();
345                         }
346                 }
347
348                 public override Type ReturnType {
349                         get {
350                                 return returnType;
351                         }
352                 }
353
354                 [MonoTODO("Not implemented")]
355                 public override ICustomAttributeProvider ReturnTypeCustomAttributes {
356                         get {
357                                 throw new NotImplementedException ();
358                         }
359                 }
360
361 /*
362                 public override int MetadataToken {
363                         get {
364                                 return 0;
365                         }
366                 }
367 */
368
369                 private void RejectIfCreated () {
370                         if (mhandle.Value != IntPtr.Zero)
371                                 throw new InvalidOperationException ("Type definition of the method is complete.");
372                 }
373
374                 private Exception NotSupported () {
375                         return new NotSupportedException ("The invoked member is not supported on a dynamic method.");
376                 }
377
378                 internal int AddRef (object reference) {
379                         if (refs == null)
380                                 refs = new object [4];
381                         if (nrefs >= refs.Length - 1) {
382                                 object [] new_refs = new object [refs.Length * 2];
383                                 System.Array.Copy (refs, new_refs, refs.Length);
384                                 refs = new_refs;
385                         }
386                         refs [nrefs] = reference;
387                         /* Reserved by the runtime */
388                         refs [nrefs + 1] = null;
389                         nrefs += 2;
390                         return nrefs - 1;
391                 }
392
393                 // This class takes care of constructing the module in a thread safe manner
394                 class AnonHostModuleHolder {
395                         public static Module anon_host_module;
396
397                         static AnonHostModuleHolder () {
398                                 AssemblyName aname = new AssemblyName ();
399                                 aname.Name = "Anonymously Hosted DynamicMethods Assembly";
400                                 AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
401
402                                 anon_host_module = ab.GetManifestModule ();
403                         }
404                 }
405         }
406
407         internal class DynamicMethodTokenGenerator : TokenGenerator {
408
409                 private DynamicMethod m;
410
411                 public DynamicMethodTokenGenerator (DynamicMethod m) {
412                         this.m = m;
413                 }
414
415                 public int GetToken (string str) {
416                         return m.AddRef (str);
417                 }
418
419                 public int GetToken (MethodInfo method, Type[] opt_param_types) {
420                         throw new InvalidOperationException ();
421                 }
422
423                 public int GetToken (MemberInfo member) {
424                         return m.AddRef (member);
425                 }
426
427                 public int GetToken (SignatureHelper helper) {
428                         return m.AddRef (helper);
429                 }
430         }
431 }
432
433 #endif