1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
10 using System.Threading;
11 using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
13 namespace System.Reflection
15 internal sealed class RuntimeMethodInfo : MethodInfo, IRuntimeMethodInfo
17 #region Private Data Members
18 private IntPtr m_handle;
19 private RuntimeTypeCache m_reflectedTypeCache;
20 private string m_name;
21 private string m_toString;
22 private ParameterInfo[] m_parameters;
23 private ParameterInfo m_returnParameter;
24 private BindingFlags m_bindingFlags;
25 private MethodAttributes m_methodAttributes;
26 private Signature m_signature;
27 private RuntimeType m_declaringType;
28 private object m_keepalive;
29 private INVOCATION_FLAGS m_invocationFlags;
31 internal INVOCATION_FLAGS InvocationFlags
35 if ((m_invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_INITIALIZED) == 0)
37 INVOCATION_FLAGS invocationFlags = INVOCATION_FLAGS.INVOCATION_FLAGS_UNKNOWN;
39 Type declaringType = DeclaringType;
42 // first take care of all the NO_INVOKE cases.
43 if (ContainsGenericParameters ||
44 IsDisallowedByRefType(ReturnType) ||
45 (declaringType != null && declaringType.ContainsGenericParameters) ||
46 ((CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs))
48 // We don't need other flags if this method cannot be invoked
49 invocationFlags = INVOCATION_FLAGS.INVOCATION_FLAGS_NO_INVOKE;
53 // Check for byref-like types
54 if ((declaringType != null && declaringType.IsByRefLike) || ReturnType.IsByRefLike)
55 invocationFlags |= INVOCATION_FLAGS.INVOCATION_FLAGS_CONTAINS_STACK_POINTERS;
58 m_invocationFlags = invocationFlags | INVOCATION_FLAGS.INVOCATION_FLAGS_INITIALIZED;
61 return m_invocationFlags;
65 private bool IsDisallowedByRefType(Type type)
70 Type elementType = type.GetElementType();
71 return elementType.IsByRefLike || elementType == typeof(void);
76 internal RuntimeMethodInfo(
77 RuntimeMethodHandleInternal handle, RuntimeType declaringType,
78 RuntimeTypeCache reflectedTypeCache, MethodAttributes methodAttributes, BindingFlags bindingFlags, object keepalive)
80 Debug.Assert(!handle.IsNullHandle());
81 Debug.Assert(methodAttributes == RuntimeMethodHandle.GetAttributes(handle));
83 m_bindingFlags = bindingFlags;
84 m_declaringType = declaringType;
85 m_keepalive = keepalive;
86 m_handle = handle.Value;
87 m_reflectedTypeCache = reflectedTypeCache;
88 m_methodAttributes = methodAttributes;
92 #region Private Methods
93 RuntimeMethodHandleInternal IRuntimeMethodInfo.Value
97 return new RuntimeMethodHandleInternal(m_handle);
101 private RuntimeType ReflectedTypeInternal
105 return m_reflectedTypeCache.GetRuntimeType();
109 private ParameterInfo[] FetchNonReturnParameters()
111 if (m_parameters == null)
112 m_parameters = RuntimeParameterInfo.GetParameters(this, this, Signature);
117 private ParameterInfo FetchReturnParameter()
119 if (m_returnParameter == null)
120 m_returnParameter = RuntimeParameterInfo.GetReturnParameter(this, this, Signature);
122 return m_returnParameter;
126 #region Internal Members
127 internal override bool CacheEquals(object o)
129 RuntimeMethodInfo m = o as RuntimeMethodInfo;
131 if ((object)m == null)
134 return m.m_handle == m_handle;
137 internal Signature Signature
141 if (m_signature == null)
142 m_signature = new Signature(this, m_declaringType);
148 internal BindingFlags BindingFlags { get { return m_bindingFlags; } }
150 internal RuntimeMethodInfo GetParentDefinition()
152 if (!IsVirtual || m_declaringType.IsInterface)
155 RuntimeType parent = (RuntimeType)m_declaringType.BaseType;
160 int slot = RuntimeMethodHandle.GetSlot(this);
162 if (RuntimeTypeHandle.GetNumVirtuals(parent) <= slot)
165 return (RuntimeMethodInfo)RuntimeType.GetMethodBase(parent, RuntimeTypeHandle.GetMethodAt(parent, slot));
168 // Unlike DeclaringType, this will return a valid type even for global methods
169 internal RuntimeType GetDeclaringTypeInternal()
171 return m_declaringType;
174 internal sealed override int GenericParameterCount => RuntimeMethodHandle.GetGenericParameterCount(this);
177 #region Object Overrides
178 public override string ToString()
180 if (m_toString == null)
182 var sbName = new ValueStringBuilder(MethodNameBufferSize);
184 sbName.Append(ReturnType.FormatTypeName());
189 sbName.Append(RuntimeMethodHandle.ConstructInstantiation(this, TypeNameFormatFlags.FormatBasic));
192 AppendParameters(ref sbName, GetParameterTypes(), CallingConvention);
195 m_toString = sbName.ToString();
201 public override int GetHashCode()
203 // See RuntimeMethodInfo.Equals() below.
205 return ValueType.GetHashCodeOfPtr(m_handle);
207 return base.GetHashCode();
210 public override bool Equals(object obj)
212 if (!IsGenericMethod)
213 return obj == (object)this;
215 // We cannot do simple object identity comparisons for generic methods.
216 // Equals will be called in CerHashTable when RuntimeType+RuntimeTypeCache.GetGenericMethodInfo()
217 // retrieve items from and insert items into s_methodInstantiations which is a CerHashtable.
219 RuntimeMethodInfo mi = obj as RuntimeMethodInfo;
221 if (mi == null || !mi.IsGenericMethod)
224 // now we know that both operands are generic methods
226 IRuntimeMethodInfo handle1 = RuntimeMethodHandle.StripMethodInstantiation(this);
227 IRuntimeMethodInfo handle2 = RuntimeMethodHandle.StripMethodInstantiation(mi);
228 if (handle1.Value.Value != handle2.Value.Value)
231 Type[] lhs = GetGenericArguments();
232 Type[] rhs = mi.GetGenericArguments();
234 if (lhs.Length != rhs.Length)
237 for (int i = 0; i < lhs.Length; i++)
239 if (lhs[i] != rhs[i])
243 if (DeclaringType != mi.DeclaringType)
246 if (ReflectedType != mi.ReflectedType)
253 #region ICustomAttributeProvider
254 public override object[] GetCustomAttributes(bool inherit)
256 return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType, inherit);
259 public override object[] GetCustomAttributes(Type attributeType, bool inherit)
261 if (attributeType == null)
262 throw new ArgumentNullException(nameof(attributeType));
264 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
266 if (attributeRuntimeType == null)
267 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
269 return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType, inherit);
272 public override bool IsDefined(Type attributeType, bool inherit)
274 if (attributeType == null)
275 throw new ArgumentNullException(nameof(attributeType));
277 RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
279 if (attributeRuntimeType == null)
280 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
282 return CustomAttribute.IsDefined(this, attributeRuntimeType, inherit);
285 public override IList<CustomAttributeData> GetCustomAttributesData()
287 return CustomAttributeData.GetCustomAttributesInternal(this);
291 #region MemberInfo Overrides
292 public override string Name
297 m_name = RuntimeMethodHandle.GetName(this);
303 public override Type DeclaringType
307 if (m_reflectedTypeCache.IsGlobal)
310 return m_declaringType;
314 public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => HasSameMetadataDefinitionAsCore<RuntimeMethodInfo>(other);
316 public override Type ReflectedType
320 if (m_reflectedTypeCache.IsGlobal)
323 return m_reflectedTypeCache.GetRuntimeType();
327 public override MemberTypes MemberType { get { return MemberTypes.Method; } }
328 public override int MetadataToken
330 get { return RuntimeMethodHandle.GetMethodDef(this); }
332 public override Module Module { get { return GetRuntimeModule(); } }
333 internal RuntimeType GetRuntimeType() { return m_declaringType; }
334 internal RuntimeModule GetRuntimeModule() { return m_declaringType.GetRuntimeModule(); }
335 internal RuntimeAssembly GetRuntimeAssembly() { return GetRuntimeModule().GetRuntimeAssembly(); }
337 public override bool IsSecurityCritical
341 public override bool IsSecuritySafeCritical
343 get { return false; }
345 public override bool IsSecurityTransparent
347 get { return false; }
351 #region MethodBase Overrides
352 internal override ParameterInfo[] GetParametersNoCopy()
354 FetchNonReturnParameters();
359 public override ParameterInfo[] GetParameters()
361 FetchNonReturnParameters();
363 if (m_parameters.Length == 0)
366 ParameterInfo[] ret = new ParameterInfo[m_parameters.Length];
368 Array.Copy(m_parameters, ret, m_parameters.Length);
373 public override MethodImplAttributes GetMethodImplementationFlags()
375 return RuntimeMethodHandle.GetImplAttributes(this);
378 public override RuntimeMethodHandle MethodHandle
382 return new RuntimeMethodHandle(this);
386 public override MethodAttributes Attributes { get { return m_methodAttributes; } }
388 public override CallingConventions CallingConvention
392 return Signature.CallingConvention;
396 public override MethodBody GetMethodBody()
398 RuntimeMethodBody mb = RuntimeMethodHandle.GetMethodBody(this, ReflectedTypeInternal);
400 mb._methodBase = this;
405 #region Invocation Logic(On MemberBase)
406 private void CheckConsistency(object target)
408 // only test instance methods
409 if ((m_methodAttributes & MethodAttributes.Static) != MethodAttributes.Static)
411 if (!m_declaringType.IsInstanceOfType(target))
414 throw new TargetException(SR.RFLCT_Targ_StatMethReqTarg);
416 throw new TargetException(SR.RFLCT_Targ_ITargMismatch);
421 private void ThrowNoInvokeException()
423 // method is on a class that contains stack pointers
424 if ((InvocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_CONTAINS_STACK_POINTERS) != 0)
426 throw new NotSupportedException();
429 else if ((CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs)
431 throw new NotSupportedException();
433 // method is generic or on a generic class
434 else if (DeclaringType.ContainsGenericParameters || ContainsGenericParameters)
436 throw new InvalidOperationException(SR.Arg_UnboundGenParam);
438 // method is abstract class
441 throw new MemberAccessException();
443 else if (ReturnType.IsByRef)
445 Type elementType = ReturnType.GetElementType();
446 if (elementType.IsByRefLike)
447 throw new NotSupportedException(SR.NotSupported_ByRefToByRefLikeReturn);
448 if (elementType == typeof(void))
449 throw new NotSupportedException(SR.NotSupported_ByRefToVoidReturn);
452 throw new TargetException();
455 [DebuggerStepThroughAttribute]
456 [Diagnostics.DebuggerHidden]
457 public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
459 object[] arguments = InvokeArgumentsCheck(obj, invokeAttr, binder, parameters, culture);
461 bool wrapExceptions = (invokeAttr & BindingFlags.DoNotWrapExceptions) == 0;
462 if (arguments == null || arguments.Length == 0)
463 return RuntimeMethodHandle.InvokeMethod(obj, null, Signature, false, wrapExceptions);
466 object retValue = RuntimeMethodHandle.InvokeMethod(obj, arguments, Signature, false, wrapExceptions);
468 // copy out. This should be made only if ByRef are present.
469 for (int index = 0; index < arguments.Length; index++)
470 parameters[index] = arguments[index];
476 [DebuggerStepThroughAttribute]
477 [Diagnostics.DebuggerHidden]
478 private object[] InvokeArgumentsCheck(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
480 Signature sig = Signature;
483 int formalCount = sig.Arguments.Length;
484 int actualCount = (parameters != null) ? parameters.Length : 0;
486 INVOCATION_FLAGS invocationFlags = InvocationFlags;
488 // INVOCATION_FLAGS_CONTAINS_STACK_POINTERS means that the struct (either the declaring type or the return type)
489 // contains pointers that point to the stack. This is either a ByRef or a TypedReference. These structs cannot
490 // be boxed and thus cannot be invoked through reflection which only deals with boxed value type objects.
491 if ((invocationFlags & (INVOCATION_FLAGS.INVOCATION_FLAGS_NO_INVOKE | INVOCATION_FLAGS.INVOCATION_FLAGS_CONTAINS_STACK_POINTERS)) != 0)
492 ThrowNoInvokeException();
494 // check basic method consistency. This call will throw if there are problems in the target/method relationship
495 CheckConsistency(obj);
497 if (formalCount != actualCount)
498 throw new TargetParameterCountException(SR.Arg_ParmCnt);
500 if (actualCount != 0)
501 return CheckArguments(parameters, binder, invokeAttr, culture, sig);
508 #region MethodInfo Overrides
509 public override Type ReturnType
511 get { return Signature.ReturnType; }
514 public override ICustomAttributeProvider ReturnTypeCustomAttributes
516 get { return ReturnParameter; }
519 public override ParameterInfo ReturnParameter
523 FetchReturnParameter();
524 return m_returnParameter as ParameterInfo;
528 public override bool IsCollectible => RuntimeMethodHandle.GetIsCollectible(new RuntimeMethodHandleInternal(m_handle));
530 public override MethodInfo GetBaseDefinition()
532 if (!IsVirtual || IsStatic || m_declaringType == null || m_declaringType.IsInterface)
535 int slot = RuntimeMethodHandle.GetSlot(this);
536 RuntimeType declaringType = (RuntimeType)DeclaringType;
537 RuntimeType baseDeclaringType = declaringType;
538 RuntimeMethodHandleInternal baseMethodHandle = new RuntimeMethodHandleInternal();
542 int cVtblSlots = RuntimeTypeHandle.GetNumVirtuals(declaringType);
544 if (cVtblSlots <= slot)
547 baseMethodHandle = RuntimeTypeHandle.GetMethodAt(declaringType, slot);
548 baseDeclaringType = declaringType;
550 declaringType = (RuntimeType)declaringType.BaseType;
551 } while (declaringType != null);
553 return (MethodInfo)RuntimeType.GetMethodBase(baseDeclaringType, baseMethodHandle);
556 public override Delegate CreateDelegate(Type delegateType)
558 // This API existed in v1/v1.1 and only expected to create closed
559 // instance delegates. Constrain the call to BindToMethodInfo to
560 // open delegates only for backwards compatibility. But we'll allow
561 // relaxed signature checking and open static delegates because
562 // there's no ambiguity there (the caller would have to explicitly
563 // pass us a static method or a method with a non-exact signature
564 // and the only change in behavior from v1.1 there is that we won't
566 return CreateDelegateInternal(
569 DelegateBindingFlags.OpenDelegateOnly | DelegateBindingFlags.RelaxedSignature);
572 public override Delegate CreateDelegate(Type delegateType, object target)
574 // This API is new in Whidbey and allows the full range of delegate
575 // flexability (open or closed delegates binding to static or
576 // instance methods with relaxed signature checking). The delegate
577 // can also be closed over null. There's no ambiguity with all these
578 // options since the caller is providing us a specific MethodInfo.
579 return CreateDelegateInternal(
582 DelegateBindingFlags.RelaxedSignature);
585 private Delegate CreateDelegateInternal(Type delegateType, object firstArgument, DelegateBindingFlags bindingFlags)
587 // Validate the parameters.
588 if (delegateType == null)
589 throw new ArgumentNullException(nameof(delegateType));
591 RuntimeType rtType = delegateType as RuntimeType;
593 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(delegateType));
595 if (!rtType.IsDelegate())
596 throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(delegateType));
598 Delegate d = Delegate.CreateDelegateInternal(rtType, this, firstArgument, bindingFlags);
601 throw new ArgumentException(SR.Arg_DlgtTargMeth);
610 public override MethodInfo MakeGenericMethod(params Type[] methodInstantiation)
612 if (methodInstantiation == null)
613 throw new ArgumentNullException(nameof(methodInstantiation));
615 RuntimeType[] methodInstantionRuntimeType = new RuntimeType[methodInstantiation.Length];
617 if (!IsGenericMethodDefinition)
618 throw new InvalidOperationException(
619 SR.Format(SR.Arg_NotGenericMethodDefinition, this));
621 for (int i = 0; i < methodInstantiation.Length; i++)
623 Type methodInstantiationElem = methodInstantiation[i];
625 if (methodInstantiationElem == null)
626 throw new ArgumentNullException();
628 RuntimeType rtMethodInstantiationElem = methodInstantiationElem as RuntimeType;
630 if (rtMethodInstantiationElem == null)
632 Type[] methodInstantiationCopy = new Type[methodInstantiation.Length];
633 for (int iCopy = 0; iCopy < methodInstantiation.Length; iCopy++)
634 methodInstantiationCopy[iCopy] = methodInstantiation[iCopy];
635 methodInstantiation = methodInstantiationCopy;
636 return System.Reflection.Emit.MethodBuilderInstantiation.MakeGenericMethod(this, methodInstantiation);
639 methodInstantionRuntimeType[i] = rtMethodInstantiationElem;
642 RuntimeType[] genericParameters = GetGenericArgumentsInternal();
644 RuntimeType.SanityCheckGenericArguments(methodInstantionRuntimeType, genericParameters);
646 MethodInfo ret = null;
650 ret = RuntimeType.GetMethodBase(ReflectedTypeInternal,
651 RuntimeMethodHandle.GetStubIfNeeded(new RuntimeMethodHandleInternal(m_handle), m_declaringType, methodInstantionRuntimeType)) as MethodInfo;
653 catch (VerificationException e)
655 RuntimeType.ValidateGenericArguments(this, methodInstantionRuntimeType, e);
662 internal RuntimeType[] GetGenericArgumentsInternal()
664 return RuntimeMethodHandle.GetMethodInstantiationInternal(this);
667 public override Type[] GetGenericArguments()
669 Type[] types = RuntimeMethodHandle.GetMethodInstantiationPublic(this);
673 types = Array.Empty<Type>();
678 public override MethodInfo GetGenericMethodDefinition()
680 if (!IsGenericMethod)
681 throw new InvalidOperationException();
683 return RuntimeType.GetMethodBase(m_declaringType, RuntimeMethodHandle.StripMethodInstantiation(this)) as MethodInfo;
686 public override bool IsGenericMethod
688 get { return RuntimeMethodHandle.HasMethodInstantiation(this); }
691 public override bool IsGenericMethodDefinition
693 get { return RuntimeMethodHandle.IsGenericMethodDefinition(this); }
696 public override bool ContainsGenericParameters
700 if (DeclaringType != null && DeclaringType.ContainsGenericParameters)
703 if (!IsGenericMethod)
706 Type[] pis = GetGenericArguments();
707 for (int i = 0; i < pis.Length; i++)
709 if (pis[i].ContainsGenericParameters)
718 #region Legacy Internal
719 internal static MethodBase InternalGetCurrentMethod(ref StackCrawlMark stackMark)
721 IRuntimeMethodInfo method = RuntimeMethodHandle.GetCurrentMethod(ref stackMark);
726 return RuntimeType.GetMethodBase(method);