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