2009-08-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mcs / class / corlib / System.Reflection.Emit / MethodBuilder.cs
1 //
2 // System.Reflection.Emit/MethodBuilder.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Reflection;
35 using System.Reflection.Emit;
36 using System.Globalization;
37 using System.Security;
38 using System.Security.Permissions;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Diagnostics.SymbolStore;
42
43 namespace System.Reflection.Emit
44 {
45 #if NET_2_0
46         [ComVisible (true)]
47         [ComDefaultInterface (typeof (_MethodBuilder))]
48 #endif
49         [ClassInterface (ClassInterfaceType.None)]
50         public sealed class MethodBuilder : MethodInfo, _MethodBuilder
51         {
52 #pragma warning disable 169, 414
53                 private RuntimeMethodHandle mhandle;
54                 private Type rtype;
55                 internal Type[] parameters;
56                 private MethodAttributes attrs; /* It's used directly by MCS */
57                 private MethodImplAttributes iattrs;
58                 private string name;
59                 private int table_idx;
60                 private byte[] code;
61                 private ILGenerator ilgen;
62                 private TypeBuilder type;
63                 internal ParameterBuilder[] pinfo;
64                 private CustomAttributeBuilder[] cattrs;
65                 private MethodInfo override_method;
66                 private string pi_dll;
67                 private string pi_entry;
68                 private CharSet charset;
69                 private uint extra_flags; /* this encodes set_last_error etc */
70                 private CallingConvention native_cc;
71                 private CallingConventions call_conv;
72                 private bool init_locals = true;
73                 private IntPtr generic_container;
74 #if NET_2_0 || BOOTSTRAP_NET_2_0
75                 internal GenericTypeParameterBuilder[] generic_params;
76 #else
77                 private Object generic_params; /* so offsets are the same */
78 #endif
79                 private Type[] returnModReq;
80                 private Type[] returnModOpt;
81                 private Type[][] paramModReq;
82                 private Type[][] paramModOpt;
83                 private RefEmitPermissionSet[] permissions;
84 #pragma warning restore 169, 414
85
86                 internal MethodBuilder (TypeBuilder tb, string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] returnModReq, Type[] returnModOpt, Type[] parameterTypes, Type[][] paramModReq, Type[][] paramModOpt)
87                 {
88                         this.name = name;
89                         this.attrs = attributes;
90                         this.call_conv = callingConvention;
91                         this.rtype = returnType;
92                         this.returnModReq = returnModReq;
93                         this.returnModOpt = returnModOpt;
94                         this.paramModReq = paramModReq;
95                         this.paramModOpt = paramModOpt;
96                         // The MSDN docs does not specify this, but the MS MethodBuilder
97                         // appends a HasThis flag if the method is not static
98                         if ((attributes & MethodAttributes.Static) == 0)
99                                 this.call_conv |= CallingConventions.HasThis;
100                         if (parameterTypes != null) {
101                                 for (int i = 0; i < parameterTypes.Length; ++i)
102                                         if (parameterTypes [i] == null)
103                                                 throw new ArgumentException ("Elements of the parameterTypes array cannot be null", "parameterTypes");
104
105                                 this.parameters = new Type [parameterTypes.Length];
106                                 System.Array.Copy (parameterTypes, this.parameters, parameterTypes.Length);
107                         }
108                         type = tb;
109                         table_idx = get_next_table_index (this, 0x06, true);
110
111                         ((ModuleBuilder)tb.Module).RegisterToken (this, GetToken ().Token);
112                 }
113
114                 internal MethodBuilder (TypeBuilder tb, string name, MethodAttributes attributes, 
115                                                                 CallingConventions callingConvention, Type returnType, Type[] returnModReq, Type[] returnModOpt, Type[] parameterTypes, Type[][] paramModReq, Type[][] paramModOpt, 
116                         String dllName, String entryName, CallingConvention nativeCConv, CharSet nativeCharset) 
117                         : this (tb, name, attributes, callingConvention, returnType, returnModReq, returnModOpt, parameterTypes, paramModReq, paramModOpt)
118                 {
119                         pi_dll = dllName;
120                         pi_entry = entryName;
121                         native_cc = nativeCConv;
122                         charset = nativeCharset;
123                 }
124
125 #if NET_2_0
126                 public override bool ContainsGenericParameters {
127                         get { throw new NotSupportedException (); }
128                 }
129 #endif
130
131                 public bool InitLocals {
132                         get {return init_locals;}
133                         set {init_locals = value;}
134                 }
135
136                 internal TypeBuilder TypeBuilder {
137                         get {return type;}
138                 }
139
140                 public override RuntimeMethodHandle MethodHandle {
141                         get {
142                                 throw NotSupported ();
143                         }
144                 }
145
146                 public override Type ReturnType {
147                         get { return rtype; }
148                 }
149
150                 public override Type ReflectedType {
151                         get { return type; }
152                 }
153
154                 public override Type DeclaringType {
155                         get { return type; }
156                 }
157
158                 public override string Name {
159                         get { return name; }
160                 }
161
162                 public override MethodAttributes Attributes {
163                         get { return attrs; }
164                 }
165
166                 public override ICustomAttributeProvider ReturnTypeCustomAttributes {
167                         get { return null; }
168                 }
169
170                 public override CallingConventions CallingConvention {
171                         get { return call_conv; }
172                 }
173
174                 [MonoTODO("Not implemented")]
175                 public string Signature {
176                         get {
177                                 throw new NotImplementedException ();
178                         }
179                 }
180
181                 /* Used by mcs */
182                 internal bool BestFitMapping {
183                         set {
184                                 extra_flags = (uint) ((extra_flags & ~0x30) | (uint)(value ? 0x10 : 0x20));
185                         }
186                 }
187
188                 /* Used by mcs */
189                 internal bool ThrowOnUnmappableChar {
190                         set {
191                                 extra_flags = (uint) ((extra_flags & ~0x3000) | (uint)(value ? 0x1000 : 0x2000));
192                         }
193                 }
194
195                 /* Used by mcs */
196                 internal bool ExactSpelling {
197                         set {
198                                 extra_flags = (uint) ((extra_flags & ~0x01) | (uint)(value ? 0x01 : 0x00));
199                         }
200                 }
201
202                 /* Used by mcs */
203                 internal bool SetLastError {
204                         set {
205                                 extra_flags = (uint) ((extra_flags & ~0x40) | (uint)(value ? 0x40 : 0x00));
206                         }
207                 }
208
209                 public MethodToken GetToken()
210                 {
211                         return new MethodToken(0x06000000 | table_idx);
212                 }
213                 
214                 public override MethodInfo GetBaseDefinition()
215                 {
216                         return this;
217                 }
218
219                 public override MethodImplAttributes GetMethodImplementationFlags()
220                 {
221                         return iattrs;
222                 }
223
224                 public override ParameterInfo[] GetParameters()
225                 {
226                         if (!type.is_created)
227                                 throw NotSupported ();
228                         if (parameters == null)
229                                 return null;
230
231                         ParameterInfo[] retval = new ParameterInfo [parameters.Length];
232                         for (int i = 0; i < parameters.Length; i++) {
233                                 retval [i] = new ParameterInfo (pinfo == null ? null : pinfo [i + 1], parameters [i], this, i + 1);
234                         }
235                         return retval;
236                 }
237                 
238                 internal override int GetParameterCount ()
239                 {
240                         if (parameters == null)
241                                 return 0;
242                         
243                         return parameters.Length;
244                 }
245
246                 public Module GetModule ()
247                 {
248                         return type.Module;
249                 }
250
251                 public void CreateMethodBody (byte[] il, int count)
252                 {
253                         if ((il != null) && ((count < 0) || (count > il.Length)))
254                                 throw new ArgumentOutOfRangeException ("Index was out of range.  Must be non-negative and less than the size of the collection.");
255
256                         if ((code != null) || type.is_created)
257                                 throw new InvalidOperationException ("Type definition of the method is complete.");
258
259                         if (il == null)
260                                 code = null;
261                         else {
262                                 code = new byte [count];
263                                 System.Array.Copy(il, code, count);
264                         }
265                 }
266
267                 public override Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
268                 {
269                         throw NotSupported ();
270                 }
271
272                 public override bool IsDefined (Type attributeType, bool inherit)
273                 {
274                         throw NotSupported ();
275                 }
276
277                 public override object[] GetCustomAttributes (bool inherit)
278                 {
279                         /*
280                          * On MS.NET, this always returns not_supported, but we can't do this
281                          * since there would be no way to obtain custom attributes of 
282                          * dynamically created ctors.
283                          */
284                         if (type.is_created)
285                                 return MonoCustomAttrs.GetCustomAttributes (this, inherit);
286                         else
287                                 throw NotSupported ();
288                 }
289
290                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
291                 {
292                         if (type.is_created)
293                                 return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
294                         else
295                                 throw NotSupported ();
296                 }
297
298                 public ILGenerator GetILGenerator ()
299                 {
300                         return GetILGenerator (64);
301                 }
302
303                 public ILGenerator GetILGenerator (int size)
304                 {
305                         if (((iattrs & MethodImplAttributes.CodeTypeMask) != 
306                                  MethodImplAttributes.IL) ||
307                                 ((iattrs & MethodImplAttributes.ManagedMask) != 
308                                  MethodImplAttributes.Managed))
309                                 throw new InvalidOperationException ("Method body should not exist.");
310                         if (ilgen != null)
311                                 return ilgen;
312                         ilgen = new ILGenerator (type.Module, ((ModuleBuilder)type.Module).GetTokenGenerator (), size);
313                         return ilgen;
314                 }
315                 
316                 public ParameterBuilder DefineParameter (int position, ParameterAttributes attributes, string strParamName)
317                 {
318                         RejectIfCreated ();
319                         
320                         //
321                         // Extension: Mono allows position == 0 for the return attribute
322                         //
323                         if ((position < 0) || (position > parameters.Length))
324                                 throw new ArgumentOutOfRangeException ("position");
325
326                         ParameterBuilder pb = new ParameterBuilder (this, position, attributes, strParamName);
327                         if (pinfo == null)
328                                 pinfo = new ParameterBuilder [parameters.Length + 1];
329                         pinfo [position] = pb;
330                         return pb;
331                 }
332
333                 internal void check_override ()
334                 {
335                         if (override_method != null && override_method.IsVirtual && !IsVirtual)
336                                 throw new TypeLoadException (String.Format("Method '{0}' override '{1}' but it is not virtual", name, override_method));
337                 }
338
339                 internal void fixup ()
340                 {
341                         if (((attrs & (MethodAttributes.Abstract | MethodAttributes.PinvokeImpl)) == 0) && ((iattrs & (MethodImplAttributes.Runtime | MethodImplAttributes.InternalCall)) == 0)) {
342 #if NET_2_0
343                                 // do not allow zero length method body on MS.NET 2.0 (and higher)
344                                 if (((ilgen == null) || (ILGenerator.Mono_GetCurrentOffset (ilgen) == 0)) && (code == null || code.Length == 0))
345 #else
346                                 if (((ilgen == null) || (ILGenerator.Mono_GetCurrentOffset (ilgen) == 0)) && (code == null))
347 #endif
348                                         throw new InvalidOperationException (
349                                                                              String.Format ("Method '{0}.{1}' does not have a method body.",
350                                                                                             DeclaringType.FullName, Name));
351                         }
352                         if (ilgen != null)
353                                 ilgen.label_fixup ();
354                 }
355                 
356                 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
357                 {
358                         if (ilgen != null && ilgen.HasDebugInfo) {
359                                 SymbolToken token = new SymbolToken (GetToken().Token);
360                                 symbolWriter.OpenMethod (token);
361                                 symbolWriter.SetSymAttribute (token, "__name", System.Text.Encoding.UTF8.GetBytes (Name));
362                                 ilgen.GenerateDebugInfo (symbolWriter);
363                                 symbolWriter.CloseMethod ();
364                         }
365                 }
366
367                 public void SetCustomAttribute (CustomAttributeBuilder customBuilder)
368                 {
369                         if (customBuilder == null)
370                                 throw new ArgumentNullException ("customBuilder");
371
372                         switch (customBuilder.Ctor.ReflectedType.FullName) {
373                                 case "System.Runtime.CompilerServices.MethodImplAttribute":
374                                         byte[] data = customBuilder.Data;
375                                         int impla; // the (stupid) ctor takes a short or an int ... 
376                                         impla = (int)data [2];
377                                         impla |= ((int)data [3]) << 8;
378                                         iattrs |= (MethodImplAttributes)impla;
379                                         return;
380
381                                 case "System.Runtime.InteropServices.DllImportAttribute":
382                                         CustomAttributeBuilder.CustomAttributeInfo attr = CustomAttributeBuilder.decode_cattr (customBuilder);
383                                         bool preserveSig = true;
384
385                                         /*
386                                          * It would be easier to construct a DllImportAttribute from
387                                          * the custom attribute builder, but the DllImportAttribute 
388                                          * does not contain all the information required here, ie.
389                                          * - some parameters, like BestFitMapping has three values
390                                          *   ("on", "off", "missing"), but DllImportAttribute only
391                                          *   contains two (on/off).
392                                          * - PreserveSig is true by default, while it is false by
393                                          *   default in DllImportAttribute.
394                                          */
395
396                                         pi_dll = (string)attr.ctorArgs[0];
397                                         if (pi_dll == null || pi_dll.Length == 0)
398                                                 throw new ArgumentException ("DllName cannot be empty");
399
400                                         native_cc = System.Runtime.InteropServices.CallingConvention.Winapi;
401
402                                         for (int i = 0; i < attr.namedParamNames.Length; ++i) {
403                                                 string name = attr.namedParamNames [i];
404                                                 object value = attr.namedParamValues [i];
405
406                                                 if (name == "CallingConvention")
407                                                         native_cc = (CallingConvention)value;
408                                                 else if (name == "CharSet")
409                                                         charset = (CharSet)value;
410                                                 else if (name == "EntryPoint")
411                                                         pi_entry = (string)value;
412                                                 else if (name == "ExactSpelling")
413                                                         ExactSpelling = (bool)value;
414                                                 else if (name == "SetLastError")
415                                                         SetLastError = (bool)value;
416                                                 else if (name == "PreserveSig")
417                                                         preserveSig = (bool)value;
418 #if NET_1_1
419                                         else if (name == "BestFitMapping")
420                                                 BestFitMapping = (bool)value;
421                                         else if (name == "ThrowOnUnmappableChar")
422                                                 ThrowOnUnmappableChar = (bool)value;
423 #endif
424                                         }
425
426                                         attrs |= MethodAttributes.PinvokeImpl;
427                                         if (preserveSig)
428                                                 iattrs |= MethodImplAttributes.PreserveSig;
429                                         return;
430
431                                 case "System.Runtime.InteropServices.PreserveSigAttribute":
432                                         iattrs |= MethodImplAttributes.PreserveSig;
433                                         return;
434 #if NET_2_0
435                                 case "System.Runtime.CompilerServices.SpecialNameAttribute":
436                                         attrs |= MethodAttributes.SpecialName;
437                                         return;
438 #endif
439                                 case "System.Security.SuppressUnmanagedCodeSecurityAttribute":
440                                         attrs |= MethodAttributes.HasSecurity;
441                                         break;
442                         }
443
444                         if (cattrs != null) {
445                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
446                                 cattrs.CopyTo (new_array, 0);
447                                 new_array [cattrs.Length] = customBuilder;
448                                 cattrs = new_array;
449                         } else {
450                                 cattrs = new CustomAttributeBuilder [1];
451                                 cattrs [0] = customBuilder;
452                         }
453                 }
454
455 #if NET_2_0
456                 [ComVisible (true)]
457 #endif
458                 public void SetCustomAttribute (ConstructorInfo con, byte[] binaryAttribute)
459                 {
460                         if (con == null)
461                                 throw new ArgumentNullException ("con");
462                         if (binaryAttribute == null)
463                                 throw new ArgumentNullException ("binaryAttribute");
464                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
465                 }
466
467                 public void SetImplementationFlags (MethodImplAttributes attributes)
468                 {
469                         RejectIfCreated ();
470                         iattrs = attributes;
471                 }
472
473                 public void AddDeclarativeSecurity (SecurityAction action, PermissionSet pset)
474                 {
475                         if (pset == null)
476                                 throw new ArgumentNullException ("pset");
477                         if ((action == SecurityAction.RequestMinimum) ||
478                                 (action == SecurityAction.RequestOptional) ||
479                                 (action == SecurityAction.RequestRefuse))
480                                 throw new ArgumentOutOfRangeException ("Request* values are not permitted", "action");
481
482                         RejectIfCreated ();
483
484                         if (permissions != null) {
485                                 /* Check duplicate actions */
486                                 foreach (RefEmitPermissionSet set in permissions)
487                                         if (set.action == action)
488                                                 throw new InvalidOperationException ("Multiple permission sets specified with the same SecurityAction.");
489
490                                 RefEmitPermissionSet[] new_array = new RefEmitPermissionSet [permissions.Length + 1];
491                                 permissions.CopyTo (new_array, 0);
492                                 permissions = new_array;
493                         }
494                         else
495                                 permissions = new RefEmitPermissionSet [1];
496
497                         permissions [permissions.Length - 1] = new RefEmitPermissionSet (action, pset.ToXml ().ToString ());
498                         attrs |= MethodAttributes.HasSecurity;
499                 }
500
501 #if NET_2_0
502                 [Obsolete ("An alternate API is available: Emit the MarshalAs custom attribute instead.")]
503 #endif
504                 public void SetMarshal (UnmanagedMarshal unmanagedMarshal)
505                 {
506                         RejectIfCreated ();
507                         throw new NotImplementedException ();
508                 }
509
510                 [MonoTODO]
511                 public void SetSymCustomAttribute (string name, byte[] data)
512                 {
513                         RejectIfCreated ();
514                         throw new NotImplementedException ();
515                 }
516
517                 public override string ToString()
518                 {
519                         return "MethodBuilder [" + type.Name + "::" + name + "]";
520                 }
521
522                 [MonoTODO]
523                 public override bool Equals (object obj)
524                 {
525                         return base.Equals (obj);
526                 }
527
528                 public override int GetHashCode ()
529                 {
530                         return name.GetHashCode ();
531                 }
532
533                 internal override int get_next_table_index (object obj, int table, bool inc)
534                 {
535                         return type.get_next_table_index (obj, table, inc);
536                 }
537
538                 internal void set_override (MethodInfo mdecl)
539                 {
540                         override_method = mdecl;
541                 }
542
543                 private void RejectIfCreated ()
544                 {
545                         if (type.is_created)
546                                 throw new InvalidOperationException ("Type definition of the method is complete.");
547                 }
548
549                 private Exception NotSupported ()
550                 {
551                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
552                 }
553
554 #if NET_2_0 || BOOTSTRAP_NET_2_0
555                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
556                 public override extern MethodInfo MakeGenericMethod (params Type [] typeArguments);
557
558                 public override bool IsGenericMethodDefinition {
559                         get {
560                                 return generic_params != null;
561                         }
562                 }
563
564                 public override bool IsGenericMethod {
565                         get {
566                                 return generic_params != null;
567                         }
568                 }
569
570                 public override MethodInfo GetGenericMethodDefinition ()
571                 {
572                         if (!IsGenericMethodDefinition)
573                                 throw new InvalidOperationException ();
574
575                         return this;
576                 }
577
578                 public override Type[] GetGenericArguments ()
579                 {
580                         if (generic_params == null)
581                                 return Type.EmptyTypes;
582
583                         Type[] result = new Type [generic_params.Length];
584                         for (int i = 0; i < generic_params.Length; i++)
585                                 result [i] = generic_params [i];
586
587                         return result;
588                 }
589
590                 public GenericTypeParameterBuilder[] DefineGenericParameters (params string[] names)
591                 {
592                         if (names == null)
593                                 throw new ArgumentNullException ("names");
594
595                         generic_params = new GenericTypeParameterBuilder [names.Length];
596                         for (int i = 0; i < names.Length; i++)
597                                 generic_params [i] = new GenericTypeParameterBuilder (
598                                         type, this, names [i], i);
599
600                         return generic_params;
601                 }
602
603                 public void SetReturnType (Type returnType)
604                 {
605                         rtype = returnType;
606                 }
607
608                 public void SetParameters (params Type[] parameterTypes)
609                 {
610                         if (parameterTypes != null) {
611                                 for (int i = 0; i < parameterTypes.Length; ++i)
612                                         if (parameterTypes [i] == null)
613                                                 throw new ArgumentException ("Elements of the parameterTypes array cannot be null", "parameterTypes");
614
615                                 this.parameters = new Type [parameterTypes.Length];
616                                 System.Array.Copy (parameterTypes, this.parameters, parameterTypes.Length);
617                         }
618                 }
619
620                 public void SetSignature (Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
621                 {
622                         SetReturnType (returnType);
623                         SetParameters (parameterTypes);
624                         this.returnModReq = returnTypeRequiredCustomModifiers;
625                         this.returnModOpt = returnTypeOptionalCustomModifiers;
626                         this.paramModReq = parameterTypeRequiredCustomModifiers;
627                         this.paramModOpt = parameterTypeOptionalCustomModifiers;
628                 }
629
630                 public override Module Module {
631                         get {
632                                 return base.Module;
633                         }
634                 }
635 #endif
636
637                 void _MethodBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
638                 {
639                         throw new NotImplementedException ();
640                 }
641
642                 void _MethodBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
643                 {
644                         throw new NotImplementedException ();
645                 }
646
647                 void _MethodBuilder.GetTypeInfoCount (out uint pcTInfo)
648                 {
649                         throw new NotImplementedException ();
650                 }
651
652                 void _MethodBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
653                 {
654                         throw new NotImplementedException ();
655                 }
656         }
657 }