private protected Span <object?> CheckArguments( ref StackAllocedArguments stackArgs, object?[]?parameters, Binder?binder, BindingFlags invokeAttr, CultureInfo?culture, Signature sig ) { Debug.Assert( Unsafe.SizeOf <StackAllocedArguments>() == StackAllocedArguments.MaxStackAllocArgCount * Unsafe.SizeOf <object>(), "MaxStackAllocArgCount not properly defined." ); Span <object?> copyOfParameters = default; if (parameters is not null) { // We need to perform type safety validation against the incoming arguments, but we also need // to be resilient against the possibility that some other thread (or even the binder itself!) // may mutate the array after we've validated the arguments but before we've properly invoked // the method. The solution is to copy the arguments to a different, not-user-visible buffer // as we validate them. n.b. This disallows use of ArrayPool, as ArrayPool-rented arrays are // considered user-visible to threads which may still be holding on to returned instances. copyOfParameters = (parameters.Length <= StackAllocedArguments.MaxStackAllocArgCount) ? MemoryMarshal.CreateSpan(ref stackArgs._arg0, parameters.Length) : new Span <object?>(new object?[parameters.Length]); ParameterInfo[]? p = null; for (int i = 0; i < parameters.Length; i++) { object? arg = parameters[i]; RuntimeType argRT = sig.Arguments[i]; if (arg == Type.Missing) { p ??= GetParametersNoCopy(); if (p[i].DefaultValue == System.DBNull.Value) { throw new ArgumentException(SR.Arg_VarMissNull, nameof(parameters)); } arg = p[i].DefaultValue !; } copyOfParameters[i] = argRT.CheckValue(arg, binder, culture, invokeAttr); } } return(copyOfParameters); }
public override object?Invoke(object?obj, BindingFlags invokeAttr, Binder?binder, object?[]?parameters, CultureInfo?culture) { if ((CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs) { throw new NotSupportedException(SR.NotSupported_CallToVarArg); } // // We do not demand any permission here because the caller already has access // to the current DynamicMethod object, and it could just as easily emit another // Transparent DynamicMethod to call the current DynamicMethod. // _ = GetMethodDescriptor(); // ignore obj since it's a static method // create a signature object Signature sig = new Signature( this.m_methodHandle !, m_parameterTypes, m_returnType, CallingConvention); // verify arguments int formalCount = sig.Arguments.Length; int actualCount = (parameters != null) ? parameters.Length : 0; if (formalCount != actualCount) { throw new TargetParameterCountException(SR.Arg_ParmCnt); } // if we are here we passed all the previous checks. Time to look at the arguments bool wrapExceptions = (invokeAttr & BindingFlags.DoNotWrapExceptions) == 0; StackAllocedArguments stackArgs = default; Span <object?> arguments = default; if (actualCount != 0) { arguments = CheckArguments(ref stackArgs, parameters, binder, invokeAttr, culture, sig.Arguments); } object?retValue = RuntimeMethodHandle.InvokeMethod(null, arguments, sig, false, wrapExceptions); // copy out. This should be made only if ByRef are present. // n.b. cannot use Span<T>.CopyTo, as parameters.GetType() might not actually be typeof(object[]) for (int index = 0; index < arguments.Length; index++) { parameters ![index] = arguments[index];
public override object?Invoke( object?obj, BindingFlags invokeAttr, Binder?binder, object?[]?parameters, CultureInfo?culture) { if ((InvocationFlags & InvocationFlags.NoInvoke) != 0) { ThrowNoInvokeException(); } ValidateInvokeTarget(obj); if ((InvocationFlags & InvocationFlags.RunClassConstructor) != 0) { // Run the class constructor through the class constructor mechanism instead of the Invoke path. // This avoids allowing mutation of readonly static fields, and initializes the type correctly. InvokeClassConstructor(); return(null); } // Correct number of arguments supplied int actualCount = (parameters is null) ? 0 : parameters.Length; if (ArgumentTypes.Length != actualCount) { throw new TargetParameterCountException(SR.Arg_ParmCnt); } StackAllocedArguments stackArgs = default; Span <object?> arguments = default; if (actualCount != 0) { arguments = CheckArguments(ref stackArgs, parameters, binder, invokeAttr, culture, ArgumentTypes); } object?retValue = InvokeWorker(obj, invokeAttr, arguments); // copy out. This should be made only if ByRef are present. // n.b. cannot use Span<T>.CopyTo, as parameters.GetType() might not actually be typeof(object[]) for (int index = 0; index < arguments.Length; index++) { parameters ![index] = arguments[index];
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); }