2 // System.Reflection.Emit/MethodBuilder.cs
5 // Paolo Molaro (lupus@ximian.com)
7 // (C) 2001 Ximian, Inc. http://www.ximian.com
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
35 using System
.Reflection
;
36 using System
.Reflection
.Emit
;
37 using System
.Globalization
;
38 using System
.Runtime
.CompilerServices
;
39 using System
.Runtime
.InteropServices
;
40 using System
.Diagnostics
.SymbolStore
;
41 using System
.Collections
.Generic
;
43 namespace System
.Reflection
.Emit
45 [StructLayout (LayoutKind
.Sequential
)]
46 public sealed partial class MethodBuilder
: MethodInfo
48 #pragma warning disable 169, 414
49 private RuntimeMethodHandle mhandle
;
51 internal Type
[] parameters
;
52 private MethodAttributes attrs
; /* It's used directly by MCS */
53 private MethodImplAttributes iattrs
;
55 private int table_idx
;
57 private ILGenerator ilgen
;
58 private TypeBuilder type
;
59 internal ParameterBuilder
[] pinfo
;
60 private CustomAttributeBuilder
[] cattrs
;
61 private MethodInfo
[] override_methods
;
62 private string pi_dll
;
63 private string pi_entry
;
64 private CharSet charset
;
65 private uint extra_flags
; /* this encodes set_last_error etc */
66 private CallingConvention native_cc
;
67 private CallingConventions call_conv
;
68 private bool init_locals
= true;
69 private IntPtr generic_container
;
70 internal GenericTypeParameterBuilder
[] generic_params
;
71 private Type
[] returnModReq
;
72 private Type
[] returnModOpt
;
73 private Type
[][] paramModReq
;
74 private Type
[][] paramModOpt
;
75 private object permissions
;
76 #pragma warning restore 169, 414
77 RuntimeMethodInfo created
;
79 internal MethodBuilder (TypeBuilder tb
, string name
, MethodAttributes attributes
, CallingConventions callingConvention
, Type returnType
, Type
[] returnModReq
, Type
[] returnModOpt
, Type
[] parameterTypes
, Type
[][] paramModReq
, Type
[][] paramModOpt
)
82 this.attrs
= attributes
;
83 this.call_conv
= callingConvention
;
84 this.rtype
= returnType
;
85 this.returnModReq
= returnModReq
;
86 this.returnModOpt
= returnModOpt
;
87 this.paramModReq
= paramModReq
;
88 this.paramModOpt
= paramModOpt
;
89 // The MSDN docs does not specify this, but the MS MethodBuilder
90 // appends a HasThis flag if the method is not static
91 if ((attributes
& MethodAttributes
.Static
) == 0)
92 this.call_conv
|= CallingConventions
.HasThis
;
93 if (parameterTypes
!= null) {
94 for (int i
= 0; i
< parameterTypes
.Length
; ++i
)
95 if (parameterTypes
[i
] == null)
96 throw new ArgumentException ("Elements of the parameterTypes array cannot be null", "parameterTypes");
98 this.parameters
= new Type
[parameterTypes
.Length
];
99 System
.Array
.Copy (parameterTypes
, this.parameters
, parameterTypes
.Length
);
102 table_idx
= get_next_table_index (this, 0x06, 1);
104 ((ModuleBuilder
)tb
.Module
).RegisterToken (this, GetToken ().Token
);
107 internal MethodBuilder (TypeBuilder tb
, string name
, MethodAttributes attributes
,
108 CallingConventions callingConvention
, Type returnType
, Type
[] returnModReq
, Type
[] returnModOpt
, Type
[] parameterTypes
, Type
[][] paramModReq
, Type
[][] paramModOpt
,
109 String dllName
, String entryName
, CallingConvention nativeCConv
, CharSet nativeCharset
)
110 : this (tb
, name
, attributes
, callingConvention
, returnType
, returnModReq
, returnModOpt
, parameterTypes
, paramModReq
, paramModOpt
)
113 pi_entry
= entryName
;
114 native_cc
= nativeCConv
;
115 charset
= nativeCharset
;
118 public override bool ContainsGenericParameters
{
119 get { throw new NotSupportedException (); }
122 public bool InitLocals
{
123 get {return init_locals;}
124 set {init_locals = value;}
127 internal TypeBuilder TypeBuilder
{
131 public override RuntimeMethodHandle MethodHandle
{
133 throw NotSupported ();
137 internal RuntimeMethodHandle MethodHandleInternal
{
143 public override Type ReturnType
{
144 get { return rtype; }
147 public override Type ReflectedType
{
151 public override Type DeclaringType
{
155 public override string Name
{
159 public override MethodAttributes Attributes
{
160 get { return attrs; }
163 public override ICustomAttributeProvider ReturnTypeCustomAttributes
{
167 public override CallingConventions CallingConvention
{
168 get { return call_conv; }
171 // FIXME: "Not implemented"
172 public string Signature
{
174 throw new NotImplementedException ();
179 internal bool BestFitMapping
{
181 extra_flags
= (uint) ((extra_flags
& ~
0x30) | (uint)(value ? 0x10 : 0x20));
186 internal bool ThrowOnUnmappableChar
{
188 extra_flags
= (uint) ((extra_flags
& ~
0x3000) | (uint)(value ? 0x1000 : 0x2000));
193 internal bool ExactSpelling
{
195 extra_flags
= (uint) ((extra_flags
& ~
0x01) | (uint)(value ? 0x01 : 0x00));
200 internal bool SetLastError
{
202 extra_flags
= (uint) ((extra_flags
& ~
0x40) | (uint)(value ? 0x40 : 0x00));
206 public MethodToken
GetToken()
208 return new MethodToken(0x06000000 | table_idx
);
211 public override MethodInfo
GetBaseDefinition()
216 public override MethodImplAttributes
GetMethodImplementationFlags()
221 public override ParameterInfo
[] GetParameters()
223 if (!type
.is_created
)
224 throw NotSupported ();
226 return GetParametersInternal ();
229 internal override ParameterInfo
[] GetParametersInternal ()
231 if (parameters
== null)
234 ParameterInfo
[] retval
= new ParameterInfo
[parameters
.Length
];
235 for (int i
= 0; i
< parameters
.Length
; i
++) {
236 retval
[i
] = RuntimeParameterInfo
.New (pinfo
?[i
+ 1], parameters
[i
], this, i
+ 1);
241 internal override int GetParametersCount ()
243 if (parameters
== null)
246 return parameters
.Length
;
249 internal override Type
GetParameterType (int pos
) {
250 return parameters
[pos
];
253 internal MethodBase
RuntimeResolve () {
254 return type
.RuntimeResolve ().GetMethod (this);
257 public Module
GetModule ()
262 public void CreateMethodBody (byte[] il
, int count
)
264 if ((il
!= null) && ((count
< 0) || (count
> il
.Length
)))
265 throw new ArgumentOutOfRangeException ("Index was out of range. Must be non-negative and less than the size of the collection.");
267 if ((code
!= null) || type
.is_created
)
268 throw new InvalidOperationException ("Type definition of the method is complete.");
273 code
= new byte [count
];
274 System
.Array
.Copy(il
, code
, count
);
278 public override Object
Invoke(Object obj
, BindingFlags invokeAttr
, Binder binder
, Object
[] parameters
, CultureInfo culture
)
280 throw NotSupported ();
283 public override bool IsDefined (Type attributeType
, bool inherit
)
285 throw NotSupported ();
288 public override object[] GetCustomAttributes (bool inherit
)
291 * On MS.NET, this always returns not_supported, but we can't do this
292 * since there would be no way to obtain custom attributes of
293 * dynamically created ctors.
296 return MonoCustomAttrs
.GetCustomAttributes (this, inherit
);
298 throw NotSupported ();
301 public override object[] GetCustomAttributes (Type attributeType
, bool inherit
)
304 return MonoCustomAttrs
.GetCustomAttributes (this, attributeType
, inherit
);
306 throw NotSupported ();
309 public ILGenerator
GetILGenerator ()
311 return GetILGenerator (64);
314 public ILGenerator
GetILGenerator (int size
)
316 if (((iattrs
& MethodImplAttributes
.CodeTypeMask
) !=
317 MethodImplAttributes
.IL
) ||
318 ((iattrs
& MethodImplAttributes
.ManagedMask
) !=
319 MethodImplAttributes
.Managed
))
320 throw new InvalidOperationException ("Method body should not exist.");
323 ilgen
= new ILGenerator (type
.Module
, ((ModuleBuilder
)type
.Module
).GetTokenGenerator (), size
);
327 public ParameterBuilder
DefineParameter (int position
, ParameterAttributes attributes
, string strParamName
)
332 // Extension: Mono allows position == 0 for the return attribute
334 if ((position
< 0) || parameters
== null || (position
> parameters
.Length
))
335 throw new ArgumentOutOfRangeException ("position");
337 ParameterBuilder pb
= new ParameterBuilder (this, position
, attributes
, strParamName
);
339 pinfo
= new ParameterBuilder
[parameters
.Length
+ 1];
340 pinfo
[position
] = pb
;
344 internal void check_override ()
346 if (override_methods
!= null) {
347 foreach (var m
in override_methods
) {
348 if (m
.IsVirtual
&& !IsVirtual
)
349 throw new TypeLoadException (String
.Format("Method '{0}' override '{1}' but it is not virtual", name
, m
));
354 internal void fixup ()
356 if (((attrs
& (MethodAttributes
.Abstract
| MethodAttributes
.PinvokeImpl
)) == 0) && ((iattrs
& (MethodImplAttributes
.Runtime
| MethodImplAttributes
.InternalCall
)) == 0)) {
357 // do not allow zero length method body on MS.NET 2.0 (and higher)
358 if (((ilgen
== null) || (ilgen
.ILOffset
== 0)) && (code
== null || code
.Length
== 0))
359 throw new InvalidOperationException (
360 String
.Format ("Method '{0}.{1}' does not have a method body.",
361 DeclaringType
.FullName
, Name
));
364 ilgen
.label_fixup (this);
367 internal void ResolveUserTypes () {
368 rtype
= TypeBuilder
.ResolveUserType (rtype
);
369 TypeBuilder
.ResolveUserTypes (parameters
);
370 TypeBuilder
.ResolveUserTypes (returnModReq
);
371 TypeBuilder
.ResolveUserTypes (returnModOpt
);
372 if (paramModReq
!= null) {
373 foreach (var types
in paramModReq
)
374 TypeBuilder
.ResolveUserTypes (types
);
376 if (paramModOpt
!= null) {
377 foreach (var types
in paramModOpt
)
378 TypeBuilder
.ResolveUserTypes (types
);
382 internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
384 if (ilgen != null && ilgen.HasDebugInfo) {
385 SymbolToken token = new SymbolToken (GetToken().Token);
386 symbolWriter.OpenMethod (token);
387 symbolWriter.SetSymAttribute (token, "__name", System.Text.Encoding.UTF8.GetBytes (Name));
388 ilgen.GenerateDebugInfo (symbolWriter);
389 symbolWriter.CloseMethod ();
393 public void SetCustomAttribute (CustomAttributeBuilder customBuilder
)
395 if (customBuilder
== null)
396 throw new ArgumentNullException ("customBuilder");
398 switch (customBuilder
.Ctor
.ReflectedType
.FullName
) {
399 case "System.Runtime.CompilerServices.MethodImplAttribute":
400 byte[] data
= customBuilder
.Data
;
401 int impla
; // the (stupid) ctor takes a short or an int ...
402 impla
= (int)data
[2];
403 impla
|= ((int)data
[3]) << 8;
404 iattrs
|= (MethodImplAttributes
)impla
;
407 case "System.Runtime.InteropServices.DllImportAttribute":
408 CustomAttributeBuilder
.CustomAttributeInfo attr
= CustomAttributeBuilder
.decode_cattr (customBuilder
);
409 bool preserveSig
= true;
412 * It would be easier to construct a DllImportAttribute from
413 * the custom attribute builder, but the DllImportAttribute
414 * does not contain all the information required here, ie.
415 * - some parameters, like BestFitMapping has three values
416 * ("on", "off", "missing"), but DllImportAttribute only
417 * contains two (on/off).
418 * - PreserveSig is true by default, while it is false by
419 * default in DllImportAttribute.
422 pi_dll
= (string)attr
.ctorArgs
[0];
423 if (pi_dll
== null || pi_dll
.Length
== 0)
424 throw new ArgumentException ("DllName cannot be empty");
426 native_cc
= System
.Runtime
.InteropServices
.CallingConvention
.Winapi
;
428 for (int i
= 0; i
< attr
.namedParamNames
.Length
; ++i
) {
429 string name
= attr
.namedParamNames
[i
];
430 object value = attr
.namedParamValues
[i
];
432 if (name
== "CallingConvention")
433 native_cc
= (CallingConvention
)value;
434 else if (name
== "CharSet")
435 charset
= (CharSet
)value;
436 else if (name
== "EntryPoint")
437 pi_entry
= (string)value;
438 else if (name
== "ExactSpelling")
439 ExactSpelling
= (bool)value;
440 else if (name
== "SetLastError")
441 SetLastError
= (bool)value;
442 else if (name
== "PreserveSig")
443 preserveSig
= (bool)value;
444 else if (name
== "BestFitMapping")
445 BestFitMapping
= (bool)value;
446 else if (name
== "ThrowOnUnmappableChar")
447 ThrowOnUnmappableChar
= (bool)value;
450 attrs
|= MethodAttributes
.PinvokeImpl
;
452 iattrs
|= MethodImplAttributes
.PreserveSig
;
455 case "System.Runtime.InteropServices.PreserveSigAttribute":
456 iattrs
|= MethodImplAttributes
.PreserveSig
;
458 case "System.Runtime.CompilerServices.SpecialNameAttribute":
459 attrs
|= MethodAttributes
.SpecialName
;
461 case "System.Security.SuppressUnmanagedCodeSecurityAttribute":
462 attrs
|= MethodAttributes
.HasSecurity
;
466 if (cattrs
!= null) {
467 CustomAttributeBuilder
[] new_array
= new CustomAttributeBuilder
[cattrs
.Length
+ 1];
468 cattrs
.CopyTo (new_array
, 0);
469 new_array
[cattrs
.Length
] = customBuilder
;
472 cattrs
= new CustomAttributeBuilder
[1];
473 cattrs
[0] = customBuilder
;
478 public void SetCustomAttribute (ConstructorInfo con
, byte[] binaryAttribute
)
481 throw new ArgumentNullException ("con");
482 if (binaryAttribute
== null)
483 throw new ArgumentNullException ("binaryAttribute");
484 SetCustomAttribute (new CustomAttributeBuilder (con
, binaryAttribute
));
487 public void SetImplementationFlags (MethodImplAttributes attributes
)
493 [Obsolete ("An alternate API is available: Emit the MarshalAs custom attribute instead.")]
494 public void SetMarshal (UnmanagedMarshal unmanagedMarshal
)
497 throw new NotImplementedException ();
501 public void SetSymCustomAttribute (string name
, byte[] data
)
504 throw new NotImplementedException ();
507 public override string ToString()
509 return "MethodBuilder [" + type
.Name
+ "::" + name
+ "]";
513 public override bool Equals (object obj
)
515 return base.Equals (obj
);
518 public override int GetHashCode ()
520 return name
.GetHashCode ();
523 internal override int get_next_table_index (object obj
, int table
, int count
)
525 return type
.get_next_table_index (obj
, table
, count
);
528 void ExtendArray
<T
> (ref T
[] array
, T elem
) {
532 var newa
= new T
[array
.Length
+ 1];
533 Array
.Copy (array
, newa
, array
.Length
);
536 array
[array
.Length
- 1] = elem
;
539 internal void set_override (MethodInfo mdecl
)
541 ExtendArray
<MethodInfo
> (ref override_methods
, mdecl
);
544 private void RejectIfCreated ()
547 throw new InvalidOperationException ("Type definition of the method is complete.");
550 private Exception
NotSupported ()
552 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
555 public override MethodInfo
MakeGenericMethod (params Type
[] typeArguments
)
557 if (!IsGenericMethodDefinition
)
558 throw new InvalidOperationException ("Method is not a generic method definition");
559 if (typeArguments
== null)
560 throw new ArgumentNullException ("typeArguments");
561 if (generic_params
.Length
!= typeArguments
.Length
)
562 throw new ArgumentException ("Incorrect length", "typeArguments");
563 foreach (Type type
in typeArguments
) {
565 throw new ArgumentNullException ("typeArguments");
568 return new MethodOnTypeBuilderInst (this, typeArguments
);
571 public override bool IsGenericMethodDefinition
{
573 return generic_params
!= null;
577 public override bool IsGenericMethod
{
579 return generic_params
!= null;
583 public override MethodInfo
GetGenericMethodDefinition ()
585 if (!IsGenericMethodDefinition
)
586 throw new InvalidOperationException ();
591 public override Type
[] GetGenericArguments ()
593 if (generic_params
== null)
596 Type
[] result
= new Type
[generic_params
.Length
];
597 for (int i
= 0; i
< generic_params
.Length
; i
++)
598 result
[i
] = generic_params
[i
];
603 public GenericTypeParameterBuilder
[] DefineGenericParameters (params string[] names
)
606 throw new ArgumentNullException ("names");
607 if (names
.Length
== 0)
608 throw new ArgumentException ("names");
610 generic_params
= new GenericTypeParameterBuilder
[names
.Length
];
611 for (int i
= 0; i
< names
.Length
; i
++) {
612 string item
= names
[i
];
614 throw new ArgumentNullException ("names");
615 generic_params
[i
] = new GenericTypeParameterBuilder (type
, this, item
, i
);
618 return generic_params
;
621 public void SetReturnType (Type returnType
)
626 public void SetParameters (params Type
[] parameterTypes
)
628 if (parameterTypes
!= null) {
629 for (int i
= 0; i
< parameterTypes
.Length
; ++i
)
630 if (parameterTypes
[i
] == null)
631 throw new ArgumentException ("Elements of the parameterTypes array cannot be null", "parameterTypes");
633 this.parameters
= new Type
[parameterTypes
.Length
];
634 System
.Array
.Copy (parameterTypes
, this.parameters
, parameterTypes
.Length
);
638 public void SetSignature (Type returnType
, Type
[] returnTypeRequiredCustomModifiers
, Type
[] returnTypeOptionalCustomModifiers
, Type
[] parameterTypes
, Type
[][] parameterTypeRequiredCustomModifiers
, Type
[][] parameterTypeOptionalCustomModifiers
)
640 SetReturnType (returnType
);
641 SetParameters (parameterTypes
);
642 this.returnModReq
= returnTypeRequiredCustomModifiers
;
643 this.returnModOpt
= returnTypeOptionalCustomModifiers
;
644 this.paramModReq
= parameterTypeRequiredCustomModifiers
;
645 this.paramModOpt
= parameterTypeOptionalCustomModifiers
;
648 public override Module Module
{
654 public override ParameterInfo ReturnParameter
{
656 if (!type
.is_created
)
657 throw new InvalidOperationException (SR
.InvalidOperation_TypeNotCreated
);
659 created
= (RuntimeMethodInfo
)MethodBase
.GetMethodFromHandle (mhandle
);
660 return created
.ReturnParameter
;
665 [StructLayout(LayoutKind
.Sequential
)]
666 readonly struct ExceptionHandler
: IEquatable
<ExceptionHandler
>
668 internal readonly int m_exceptionClass
;
669 internal readonly int m_tryStartOffset
;
670 internal readonly int m_tryEndOffset
;
671 internal readonly int m_filterOffset
;
672 internal readonly int m_handlerStartOffset
;
673 internal readonly int m_handlerEndOffset
;
674 internal readonly ExceptionHandlingClauseOptions m_kind
;
676 public int ExceptionTypeToken
678 get { return m_exceptionClass; }
683 get { return m_tryStartOffset; }
688 get { return m_tryEndOffset - m_tryStartOffset; }
691 public int FilterOffset
693 get { return m_filterOffset; }
696 public int HandlerOffset
698 get { return m_handlerStartOffset; }
701 public int HandlerLength
703 get { return m_handlerEndOffset - m_handlerStartOffset; }
706 public ExceptionHandlingClauseOptions Kind
708 get { return m_kind; }
711 internal ExceptionHandler(int tryStartOffset
, int tryEndOffset
, int filterOffset
, int handlerStartOffset
, int handlerEndOffset
,
712 int kind
, int exceptionTypeToken
)
714 m_tryStartOffset
= tryStartOffset
;
715 m_tryEndOffset
= tryEndOffset
;
716 m_filterOffset
= filterOffset
;
717 m_handlerStartOffset
= handlerStartOffset
;
718 m_handlerEndOffset
= handlerEndOffset
;
719 m_kind
= (ExceptionHandlingClauseOptions
)kind
;
720 m_exceptionClass
= exceptionTypeToken
;
723 private static bool IsValidKind(ExceptionHandlingClauseOptions kind
)
727 case ExceptionHandlingClauseOptions
.Clause
:
728 case ExceptionHandlingClauseOptions
.Filter
:
729 case ExceptionHandlingClauseOptions
.Finally
:
730 case ExceptionHandlingClauseOptions
.Fault
:
738 public override int GetHashCode()
740 return m_exceptionClass ^ m_tryStartOffset ^ m_tryEndOffset ^ m_filterOffset ^ m_handlerStartOffset ^ m_handlerEndOffset ^
(int)m_kind
;
743 public override bool Equals(Object obj
)
745 return obj
is ExceptionHandler
&& Equals((ExceptionHandler
)obj
);
748 public bool Equals(ExceptionHandler other
)
751 other
.m_exceptionClass
== m_exceptionClass
&&
752 other
.m_tryStartOffset
== m_tryStartOffset
&&
753 other
.m_tryEndOffset
== m_tryEndOffset
&&
754 other
.m_filterOffset
== m_filterOffset
&&
755 other
.m_handlerStartOffset
== m_handlerStartOffset
&&
756 other
.m_handlerEndOffset
== m_handlerEndOffset
&&
757 other
.m_kind
== m_kind
;
760 public static bool operator ==(ExceptionHandler left
, ExceptionHandler right
)
762 return left
.Equals(right
);
765 public static bool operator !=(ExceptionHandler left
, ExceptionHandler right
)
767 return !left
.Equals(right
);