protected virtual object DynamicInvokeImpl(object[] args) { if (IsDynamicDelegate()) { // DynamicDelegate case object result = ((Func <object[], object>)m_helperObject)(args); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } else { IntPtr invokeThunk = this.GetThunk(DelegateInvokeThunk); #if PROJECTN object result = InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, this, invokeThunk, IntPtr.Zero, this, args, binderBundle: null, wrapInTargetInvocationException: true); #else IntPtr genericDictionary = IntPtr.Zero; if (FunctionPointerOps.IsGenericMethodPointer(invokeThunk)) { unsafe { GenericMethodDescriptor *descriptor = FunctionPointerOps.ConvertToGenericDescriptor(invokeThunk); genericDictionary = descriptor->InstantiationArgument; invokeThunk = descriptor->MethodFunctionPointer; } } object result = InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, null, invokeThunk, genericDictionary, this, args, binderBundle: null, wrapInTargetInvocationException: true, invokeMethodHelperIsThisCall: false); #endif DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } }
public object DynamicInvoke(params object[] args) { object result = DynamicInvokeImpl(args); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); }
public static unsafe T CreateInstance <[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>() { // Grab the pointer to the default constructor of the type. If T doesn't have a default // constructor, the intrinsic returns a marker pointer that we check for. IntPtr defaultConstructor = DefaultConstructorOf <T>(); // Check if we got the marker back. // // TODO: might want to disambiguate the different cases for abstract class, interface, etc. if (defaultConstructor == (IntPtr)(delegate * < Guid >) & MissingConstructorMethod) { throw new MissingMethodException(SR.Format(SR.MissingConstructor_Name, typeof(T))); } T t; try { // Call the default constructor on the allocated instance. if (RuntimeHelpers.IsReference <T>()) { // Grab a pointer to the optimized allocator for the type and call it. IntPtr allocator = AllocatorOf <T>(); t = RawCalliHelper.Call <T>(allocator, EETypePtr.EETypePtrOf <T>().RawValue); RawCalliHelper.Call(defaultConstructor, t); // Debugger goo so that stepping in works. Only affects debug info generation. // The call gets optimized away. DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } else { t = default !;
private unsafe ref byte InvokeWithManyArguments( IntPtr methodToCall, ref byte thisArg, ref byte ret, object?[] parameters, BinderBundle binderBundle, bool wrapInTargetInvocationException) { int argCount = _argumentCount; // We don't check a max stack size since we are invoking a method which // naturally requires a stack size that is dependent on the arg count\size. IntPtr *pStorage = stackalloc IntPtr[2 * argCount]; NativeMemory.Clear(pStorage, (nuint)(2 * argCount) * (nuint)sizeof(IntPtr)); ByReference *pByRefStorage = (ByReference *)(pStorage + argCount); RuntimeImports.GCFrameRegistration regArgStorage = new(pStorage, (uint)argCount, areByRefs : false); RuntimeImports.GCFrameRegistration regByRefStorage = new(pByRefStorage, (uint)argCount, areByRefs : true); try { RuntimeImports.RhRegisterForGCReporting(®ArgStorage); RuntimeImports.RhRegisterForGCReporting(®ByRefStorage); CheckArguments(ref Unsafe.As <IntPtr, object>(ref *pStorage), pByRefStorage, parameters, binderBundle); try { ret = ref RawCalliHelper.Call(InvokeThunk, (void *)methodToCall, ref thisArg, ref ret, pByRefStorage); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } catch (Exception e) when(wrapInTargetInvocationException) { throw new TargetInvocationException(e); } finally { if (_needsCopyBack) { CopyBack(ref Unsafe.As <IntPtr, object>(ref *pStorage), parameters); } } } finally { RuntimeImports.RhUnregisterForGCReporting(®ByRefStorage); RuntimeImports.RhUnregisterForGCReporting(®ArgStorage); } return(ref ret); }
protected virtual object DynamicInvokeImpl(object[] args) { if (IsDynamicDelegate()) { // DynamicDelegate case object result = ((Func <object[], object>)m_helperObject)(args); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } else { IntPtr invokeThunk = this.GetThunk(DelegateInvokeThunk); object result = System.InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, this, invokeThunk, IntPtr.Zero, this, args, binderBundle: null); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } }
protected virtual object?DynamicInvokeImpl(object?[]?args) { if (IsDynamicDelegate()) { // DynamicDelegate case object?result = ((Func <object?[]?, object?>)m_helperObject)(args); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } else { DynamicInvokeInfo dynamicInvokeInfo = ReflectionAugments.ReflectionCoreCallbacks.GetDelegateDynamicInvokeInfo(GetType()); object?result = dynamicInvokeInfo.Invoke(m_firstParameter, m_functionPointer, args, binderBundle: null, wrapInTargetInvocationException: true); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } }
internal static object CallDynamicInvokeMethod( object thisPtr, IntPtr methodToCall, object thisPtrDynamicInvokeMethod, IntPtr dynamicInvokeHelperMethod, IntPtr dynamicInvokeHelperGenericDictionary, object targetMethodOrDelegate, object[] parameters, BinderBundle binderBundle, bool wrapInTargetInvocationException, bool invokeMethodHelperIsThisCall = true, bool methodToCallIsThisCall = true) { // This assert is needed because we've double-purposed "targetMethodOrDelegate" (which is actually a MethodBase anytime a custom binder is used) // as a way of obtaining the true parameter type which we need to pass to Binder.ChangeType(). (The type normally passed to DynamicInvokeParamHelperCore // isn't always the exact type (byref stripped off, enums converted to int, etc.) Debug.Assert(!(binderBundle != null && !(targetMethodOrDelegate is MethodBase)), "The only callers that can pass a custom binder are those servicing MethodBase.Invoke() apis."); bool parametersNeedCopyBack = false; ArgSetupState argSetupState = default(ArgSetupState); // Capture state of thread static invoke helper statics object[] parametersOld = s_parameters; object[] nullableCopyBackObjectsOld = s_nullableCopyBackObjects; int curIndexOld = s_curIndex; object targetMethodOrDelegateOld = s_targetMethodOrDelegate; BinderBundle binderBundleOld = s_binderBundle; s_binderBundle = binderBundle; object[] customBinderProvidedParametersOld = s_customBinderProvidedParameters; s_customBinderProvidedParameters = null; try { // If the passed in array is not an actual object[] instance, we need to copy it over to an actual object[] // instance so that the rest of the code can safely create managed object references to individual elements. if (parameters != null && EETypePtr.EETypePtrOf <object[]>() != parameters.EETypePtr) { s_parameters = new object[parameters.Length]; Array.Copy(parameters, s_parameters, parameters.Length); parametersNeedCopyBack = true; } else { s_parameters = parameters; } s_nullableCopyBackObjects = null; s_curIndex = 0; s_targetMethodOrDelegate = targetMethodOrDelegate; try { object result = null; if (invokeMethodHelperIsThisCall) { Debug.Assert(methodToCallIsThisCall == true); result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, thisPtrDynamicInvokeMethod, thisPtr, methodToCall, ref argSetupState); System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } else { if (dynamicInvokeHelperGenericDictionary != IntPtr.Zero) { result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, dynamicInvokeHelperGenericDictionary, thisPtr, methodToCall, ref argSetupState, methodToCallIsThisCall); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } else { result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, thisPtr, methodToCall, ref argSetupState, methodToCallIsThisCall); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } } return(result); } catch (Exception e) when(wrapInTargetInvocationException && argSetupState.fComplete) { throw new TargetInvocationException(e); } finally { if (parametersNeedCopyBack) { Array.Copy(s_parameters, parameters, parameters.Length); } if (argSetupState.fComplete) { // Nullable objects can't take advantage of the ability to update the boxed value on the heap directly, so perform // an update of the parameters array now. if (argSetupState.nullableCopyBackObjects != null) { for (int i = 0; i < argSetupState.nullableCopyBackObjects.Length; i++) { if (argSetupState.nullableCopyBackObjects[i] != null) { parameters[i] = DynamicInvokeBoxIntoNonNullable(argSetupState.nullableCopyBackObjects[i]); } } } } } } finally { // Restore state of thread static helper statics s_parameters = parametersOld; s_nullableCopyBackObjects = nullableCopyBackObjectsOld; s_curIndex = curIndexOld; s_targetMethodOrDelegate = targetMethodOrDelegateOld; s_binderBundle = binderBundleOld; s_customBinderProvidedParameters = customBinderProvidedParametersOld; } }
public static T CreateInstance <T>() { T t = default(T); bool missingDefaultConstructor = false; EETypePtr eetype = EETypePtr.EETypePtrOf <T>(); if (!RuntimeHelpers.IsReference <T>()) { // Early out for valuetypes since we don't support default constructors anyway. // This lets codegens that expand IsReference<T> optimize away the rest of this code. } else if (eetype.ComponentSize != 0) { // ComponentSize > 0 indicates an array-like type (e.g. string, array, etc). // Allocating this using the normal allocator would result in silent heap corruption. missingDefaultConstructor = true; } else if (eetype.IsInterface) { // Do not attempt to allocate interface types either missingDefaultConstructor = true; } else { bool oldValueOfMissingDefaultCtorMarkerBool = s_createInstanceMissingDefaultConstructor; try { t = (T)(RuntimeImports.RhNewObject(eetype)); // Run the default constructor. If the default constructor was missing, codegen // will expand DefaultConstructorOf to ClassWithMissingConstructor::.ctor // and we detect that later. IntPtr defaultConstructor = DefaultConstructorOf <T>(); RawCalliHelper.Call(defaultConstructor, t); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } catch (Exception e) { throw new TargetInvocationException(e); } if (s_createInstanceMissingDefaultConstructor != oldValueOfMissingDefaultCtorMarkerBool) { missingDefaultConstructor = true; // We didn't call the real .ctor (because there wasn't one), but we still allocated // an uninitialized object. If it has a finalizer, it would run - prevent that. GC.SuppressFinalize(t); } } if (missingDefaultConstructor) { throw new MissingMethodException(SR.Format(SR.MissingConstructor_Name, typeof(T))); } return(t); }
internal static object CallDynamicInvokeMethod( object thisPtr, IntPtr methodToCall, object thisPtrDynamicInvokeMethod, IntPtr dynamicInvokeHelperMethod, IntPtr dynamicInvokeHelperGenericDictionary, object defaultParametersContext, object[] parameters, bool invokeMethodHelperIsThisCall = true, bool methodToCallIsThisCall = true) { bool fDontWrapInTargetInvocationException = false; bool parametersNeedCopyBack = false; ArgSetupState argSetupState = default(ArgSetupState); // Capture state of thread static invoke helper statics object[] parametersOld = s_parameters; object[] nullableCopyBackObjectsOld = s_nullableCopyBackObjects; int curIndexOld = s_curIndex; object defaultParametersContextOld = s_defaultParametersContext; try { // If the passed in array is not an actual object[] instance, we need to copy it over to an actual object[] // instance so that the rest of the code can safely create managed object references to individual elements. if (parameters != null && EETypePtr.EETypePtrOf <object[]>() != parameters.EETypePtr) { s_parameters = new object[parameters.Length]; Array.Copy(parameters, s_parameters, parameters.Length); parametersNeedCopyBack = true; } else { s_parameters = parameters; } s_nullableCopyBackObjects = null; s_curIndex = 0; s_defaultParametersContext = defaultParametersContext; try { object result = null; if (invokeMethodHelperIsThisCall) { Debug.Assert(methodToCallIsThisCall == true); result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, thisPtrDynamicInvokeMethod, thisPtr, methodToCall, ref argSetupState); System.Diagnostics.DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } else { if (dynamicInvokeHelperGenericDictionary != IntPtr.Zero) { result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, dynamicInvokeHelperGenericDictionary, thisPtr, methodToCall, ref argSetupState, methodToCallIsThisCall); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } else { result = CalliIntrinsics.Call(dynamicInvokeHelperMethod, thisPtr, methodToCall, ref argSetupState, methodToCallIsThisCall); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } } return(result); } finally { if (parametersNeedCopyBack) { Array.Copy(s_parameters, parameters, parameters.Length); } if (!argSetupState.fComplete) { fDontWrapInTargetInvocationException = true; } else { // Nullable objects can't take advantage of the ability to update the boxed value on the heap directly, so perform // an update of the parameters array now. if (argSetupState.nullableCopyBackObjects != null) { for (int i = 0; i < argSetupState.nullableCopyBackObjects.Length; i++) { if (argSetupState.nullableCopyBackObjects[i] != null) { parameters[i] = DynamicInvokeBoxIntoNonNullable(argSetupState.nullableCopyBackObjects[i]); } } } } } } catch (Exception e) { if (fDontWrapInTargetInvocationException) { throw; } else { throw new System.Reflection.TargetInvocationException(e); } } finally { // Restore state of thread static helper statics s_parameters = parametersOld; s_nullableCopyBackObjects = nullableCopyBackObjectsOld; s_curIndex = curIndexOld; s_defaultParametersContext = defaultParametersContextOld; } }
public unsafe object?Invoke( object?thisPtr, IntPtr methodToCall, object?[]?parameters, BinderBundle?binderBundle, bool wrapInTargetInvocationException) { int argCount = parameters?.Length ?? 0; if (argCount != _argumentCount) { if (_argumentCount < 0) { if (_argumentCount == ArgumentCount_NotSupported_ByRefLike) { throw new NotSupportedException(SR.NotSupported_ByRefLike); } throw new NotSupportedException(); } throw new TargetParameterCountException(SR.Arg_ParmCnt); } object?returnObject = null; scoped ref byte thisArg = ref Unsafe.NullRef <byte>(); if (!_isStatic) { // The caller is expected to validate this Debug.Assert(thisPtr != null); // See TODO comment in DynamicInvokeMethodThunk.NormalizeSignature // if (_isValueTypeInstanceMethod) // { // // thisArg is a raw data byref for valuetype instance methods // thisArg = ref thisPtr.GetRawData(); // } // else { thisArg = ref Unsafe.As <object?, byte>(ref thisPtr); } } scoped ref byte ret = ref Unsafe.As <object?, byte>(ref returnObject); if ((_returnTransform & Transform.AllocateReturnBox) != 0) { returnObject = RuntimeImports.RhNewObject( (_returnTransform & Transform.Pointer) != 0 ? EETypePtr.EETypePtrOf <IntPtr>() : _returnType); ret = ref returnObject.GetRawData(); } if (argCount == 0) { try { ret = ref RawCalliHelper.Call(InvokeThunk, (void *)methodToCall, ref thisArg, ref ret, null); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } catch (Exception e) when(wrapInTargetInvocationException) { throw new TargetInvocationException(e); } } else if (argCount > MaxStackAllocArgCount) { ret = ref InvokeWithManyArguments(methodToCall, ref thisArg, ref ret, parameters, binderBundle, wrapInTargetInvocationException); } else { StackAllocedArguments argStorage = default; StackAllocatedByRefs byrefStorage = default; CheckArguments(ref argStorage._arg0 !, (ByReference *)&byrefStorage, parameters, binderBundle); try { ret = ref RawCalliHelper.Call(InvokeThunk, (void *)methodToCall, ref thisArg, ref ret, &byrefStorage); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); } catch (Exception e) when(wrapInTargetInvocationException) { throw new TargetInvocationException(e); } finally { if (_needsCopyBack) { CopyBack(ref argStorage._arg0 !, parameters); } } } return(((_returnTransform & (Transform.Nullable | Transform.Pointer | Transform.ByRef)) != 0) ? ReturnTransform(ref ret, wrapInTargetInvocationException) : returnObject); }