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