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