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