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