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); }
private static unsafe void RunFunctionWithConservativelyReportedBufferInternal <T>(int cbBuffer, IntPtr pfnTargetToInvoke, ref T context, ref RuntimeImports.ConservativelyReportedRegionDesc regionDesc) { fixed(RuntimeImports.ConservativelyReportedRegionDesc *pRegionDesc = ®ionDesc) { int cbBufferAligned = (cbBuffer + (sizeof(IntPtr) - 1)) & ~(sizeof(IntPtr) - 1); // The conservative region must be IntPtr aligned, and a multiple of IntPtr in size void *region = stackalloc IntPtr[cbBufferAligned / sizeof(IntPtr)]; RuntimeImports.RhInitializeConservativeReportingRegion(pRegionDesc, region, cbBufferAligned); RawCalliHelper.Call <T>(pfnTargetToInvoke, region, ref context); RuntimeImports.RhDisableConservativeReportingRegion(pRegionDesc); } }
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); }
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); }