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