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