From 96197f12c956a6fd1b5bbba606398af0bf4fbc80 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:04:34 +0200 Subject: [PATCH 01/11] Convert more COM interop MethodDescCallSite to UCO --- .../src/System/Delegate.CoreCLR.cs | 13 +++ .../src/System/StubHelpers.cs | 110 ++++++++++++++++++ src/coreclr/vm/clrtocomcall.cpp | 13 +-- src/coreclr/vm/comcallablewrapper.cpp | 21 +--- src/coreclr/vm/comconnectionpoints.cpp | 26 +---- src/coreclr/vm/corelib.h | 6 + src/coreclr/vm/metasig.h | 6 + src/coreclr/vm/runtimecallablewrapper.cpp | 18 +-- src/coreclr/vm/stdinterfaces.cpp | 32 ++--- 9 files changed, 162 insertions(+), 83 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 358dab7f43674d..7e475d68817460 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -479,6 +479,19 @@ private void DelegateConstruct(object target, IntPtr method) Construct(ObjectHandleOnStack.Create(ref _this), ObjectHandleOnStack.Create(ref target), method); } + [UnmanagedCallersOnly] + private static unsafe void DelegateConstructUco(Delegate* pDelegate, object* pTarget, IntPtr method, Exception* pException) + { + try + { + (*pDelegate).DelegateConstruct(*pTarget, method); + } + catch (Exception ex) + { + *pException = ex; + } + } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_Construct")] private static partial void Construct(ObjectHandleOnStack _this, ObjectHandleOnStack target, IntPtr method); diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index a913fca431da0a..b1c62e471a42e4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1492,6 +1492,116 @@ internal static void SetPendingExceptionObject(Exception? exception) [SupportedOSPlatform("windows")] internal static object GetIEnumeratorToEnumVariantMarshaler() => EnumeratorToEnumVariantMarshaler.GetInstance(string.Empty); + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, int* pResult, Exception* pException) + { + try + { + int result = 0; + PropertyInfo property = *pMemberInfo; + if (property.CanRead) + { + result |= 1; + } + + if (property.CanWrite) + { + result |= 2; + } + + *pResult = result; + } + catch (Exception ex) + { + *pException = ex; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObject, Guid* pIid, IntPtr* ppObject, int* pResult, Exception* pException) + { + try + { + *pResult = (int)(*pObject).GetInterface(ref *pIid, out *ppObject); + } + catch (Exception ex) + { + *pException = ex; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + private static unsafe void InvokeComObjectCreationCallback(Delegate* pDelegate, IntPtr pOuter, IntPtr* pResult, Exception* pException) + { + try + { + object? callbackResult = (*pDelegate).DynamicInvoke([pOuter]); + *pResult = callbackResult is null ? IntPtr.Zero : (IntPtr)callbackResult; + } + catch (Exception ex) + { + *pException = ex; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + private static unsafe void InvokeConnectionPointProviderMethod(object* pProvider, IntPtr pMethodDesc, Delegate* pDelegate, Exception* pException) + { + try + { + RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); + MethodBase method = MethodBase.GetMethodFromHandle(methodHandle)!; + method.Invoke(*pProvider, [*pDelegate]); + } + catch (Exception ex) + { + *pException = ex is TargetInvocationException { InnerException: Exception inner } ? inner : ex; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + private static unsafe void InvokeClrToComEventProviderMethod(object* pEventProvider, IntPtr pMethodDesc, Delegate* pEventHandler, IntPtr* pResult, Exception* pException) + { + try + { + RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); + MethodBase method = MethodBase.GetMethodFromHandle(methodHandle)!; + object? result = method.Invoke(*pEventProvider, [*pEventHandler]); + *pResult = ConvertToArgSlot(result); + } + catch (Exception ex) + { + *pException = ex is TargetInvocationException { InnerException: Exception inner } ? inner : ex; + } + } + + [SupportedOSPlatform("windows")] + private static IntPtr ConvertToArgSlot(object? value) + { + return value switch + { + null => IntPtr.Zero, + IntPtr pointer => pointer, + UIntPtr pointer => unchecked((IntPtr)pointer), + bool boolean => boolean ? (IntPtr)1 : IntPtr.Zero, + char character => (IntPtr)character, + byte number => (IntPtr)number, + sbyte number => (IntPtr)number, + short number => (IntPtr)number, + ushort number => (IntPtr)number, + int number => (IntPtr)number, + uint number => unchecked((IntPtr)number), + long number => checked((IntPtr)number), + ulong number => unchecked((IntPtr)number), + _ => throw new NotSupportedException() + }; + } + [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] private static unsafe void GetIEnumeratorToEnumVariantMarshaler(object* pResult, Exception* pException) diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp index 3a2373b8e8735b..3f21e6c1251e9c 100644 --- a/src/coreclr/vm/clrtocomcall.cpp +++ b/src/coreclr/vm/clrtocomcall.cpp @@ -325,23 +325,18 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe MetaSig mSig(pMD); ArgIterator ArgItr(&mSig); - // Make the call on the event provider method desc. - MethodDescCallSite eventProvider(pEvProvMD, &gc.EventProviderObj); - // Retrieve the event handler passed in. OBJECTREF EventHandlerObj = ObjectToOBJECTREF(*(Object**)(pFrame->GetTransitionBlock() + ArgItr.GetNextOffset())); - ARG_SLOT EventMethArgs[] = - { - ObjToArgSlot(gc.EventProviderObj), - ObjToArgSlot(EventHandlerObj) - }; + INT_PTR eventProviderResult = NULL; + UnmanagedCallersOnlyCaller invokeClrToComEventProviderMethod(METHOD__STUBHELPERS__INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD); + invokeClrToComEventProviderMethod.InvokeThrowing(&gc.EventProviderObj, (INT_PTR)pEvProvMD, &EventHandlerObj, &eventProviderResult); // // If this can ever return something bigger than an INT64 byval // then this code is broken. Currently, however, it cannot. // - *(ARG_SLOT *)(pFrame->GetReturnValuePtr()) = eventProvider.Call_RetArgSlot(EventMethArgs); + *(ARG_SLOT *)(pFrame->GetReturnValuePtr()) = (ARG_SLOT)eventProviderResult; // The COM event call worker does not support value returned in // floating point registers. diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index 1b0c6eea5a4e45..dcc671ac465e36 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -2340,22 +2340,13 @@ VOID __stdcall InvokeICustomQueryInterfaceGetInterface_CallBack(LPVOID ptr) GCPROTECT_BEGIN(pObj); - // 1. Get MD - MethodDesc *pMD = pArgs->pWrap->GetSimpleWrapper()->GetComCallWrapperTemplate()->GetICustomQueryInterfaceGetInterfaceMD(); + INT_PTR queriedInterface = reinterpret_cast(*pArgs->ppUnk); + INT32 result = static_cast(CustomQueryInterfaceResult::NotHandled); + UnmanagedCallersOnlyCaller callICustomQueryInterface(METHOD__STUBHELPERS__CALL_ICUSTOM_QUERY_INTERFACE); + callICustomQueryInterface.InvokeThrowing(&pObj, pArgs->pGuid, &queriedInterface, &result); - // 2. Get Object Handle - OBJECTHANDLE hndCustomQueryInterface = pArgs->pWrap->GetObjectHandle(); - - // 3 construct the MethodDescCallSite - MethodDescCallSite GetInterface(pMD, hndCustomQueryInterface); - - ARG_SLOT Args[] = { - ObjToArgSlot(pObj), - PtrToArgSlot(pArgs->pGuid), - PtrToArgSlot(pArgs->ppUnk), - }; - - *(pArgs->pRetVal) = (CustomQueryInterfaceResult)GetInterface.Call_RetArgSlot(Args); + *pArgs->ppUnk = reinterpret_cast(queriedInterface); + *(pArgs->pRetVal) = (CustomQueryInterfaceResult)result; GCPROTECT_END(); } } diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 6442c534436567..9fa4470dbb38cf 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -547,29 +547,13 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs GCPROTECT_BEGIN( pDelegate ); { - // Initialize the delegate using the arguments structure. - // Generics: ensure we get the right MethodDesc here and in similar places - // Accept both void (object, native int) and void (object, native uint) - MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); - if (pDlgCtorMD == NULL) - pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_UIntPtr_RetVoid); + UnmanagedCallersOnlyCaller delegateCtor(METHOD__DELEGATE__CONSTRUCT_DELEGATE_UCO); + delegateCtor.InvokeThrowing(&pDelegate, &pSubscriber, (INT_PTR)pEventMethodDesc->GetMultiCallableAddrOfCode()); - // The loader is responsible for only accepting well-formed delegate classes. - _ASSERTE(pDlgCtorMD); + UnmanagedCallersOnlyCaller invokeConnectionPointProviderMethod(METHOD__STUBHELPERS__INVOKE_CONNECTION_POINT_PROVIDER_METHOD); - MethodDescCallSite dlgCtor(pDlgCtorMD); - - ARG_SLOT CtorArgs[3] = { ObjToArgSlot(pDelegate), - ObjToArgSlot(pSubscriber), - (ARG_SLOT)pEventMethodDesc->GetMultiCallableAddrOfCode() - }; - dlgCtor.Call(CtorArgs); - - MethodDescCallSite prov(pProvMethodDesc, &pProvider); - - // Do the actual invocation of the method method. - ARG_SLOT Args[2] = { ObjToArgSlot( pProvider ), ObjToArgSlot( pDelegate ) }; - prov.Call(Args); + // Do the actual invocation of the provider method. + invokeConnectionPointProviderMethod.InvokeThrowing(&pProvider, (INT_PTR)pProvMethodDesc, &pDelegate); } GCPROTECT_END(); } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 03655015fe1e50..e385329a5a8ee6 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -236,6 +236,7 @@ DEFINE_FIELD(DELEGATE, TARGET, _target) DEFINE_FIELD(DELEGATE, METHOD_PTR, _methodPtr) DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux) DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid) +DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE_UCO, DelegateConstructUco, SM_PtrDelegate_PtrObj_IntPtr_PtrException_RetVoid) DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr) DEFINE_CLASS(INT128, System, Int128) @@ -1046,6 +1047,11 @@ DEFINE_METHOD(STUBHELPERS, GET_PENDING_EXCEPTION_OBJECT, GetPendingExce DEFINE_METHOD(STUBHELPERS, CREATE_CUSTOM_MARSHALER, CreateCustomMarshaler, SM_IntPtr_Int_IntPtr_RetObj) #ifdef FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, GetIEnumeratorToEnumVariantMarshaler, SM_PtrObj_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_COM_OBJECT_CREATION_CALLBACK, InvokeComObjectCreationCallback, SM_PtrDelegate_IntPtr_PtrIntPtr_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, SM_PtrObj_IntPtr_PtrDelegate_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrObj_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid) #endif // FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, CHECK_STRING_LENGTH, CheckStringLength, SM_Int_RetVoid) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 87a7f81a40c16e..ee35d300a23201 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -214,6 +214,12 @@ DEFINE_METASIG(SM(RefByte_RefByte_UIntPtr_RetVoid, r(b) r(b) U, v)) DEFINE_METASIG(SM(RefByte_Byte_UIntPtr_RetVoid, r(b) b U, v)) DEFINE_METASIG(SM(RefByte_UIntPtr_RetVoid, r(b) U, v)) DEFINE_METASIG(SM(PtrVoid_Byte_UInt_RetVoid, P(v) b K, v)) +DEFINE_METASIG_T(SM(PtrDelegate_IntPtr_PtrIntPtr_PtrException_RetVoid, P(C(DELEGATE)) I P(I) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrDelegate_PtrObj_IntPtr_PtrException_RetVoid, P(C(DELEGATE)) P(j) I P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid, P(C(ICUSTOM_QUERYINTERFACE)) P(g(GUID)) P(I) P(i) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(I) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrInt_PtrException_RetVoid, P(C(PROPERTY_INFO)) P(i) P(C(EXCEPTION)), v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_RetVoid, I r(j) I, v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_Int_RetVoid, I r(j) I i,v)) DEFINE_METASIG(SM(IntPtr_IntPtr_Int_Int_IntPtr_RetVoid, I I i i I, v)) diff --git a/src/coreclr/vm/runtimecallablewrapper.cpp b/src/coreclr/vm/runtimecallablewrapper.cpp index 076a4a043fa7af..81db5b52a007ba 100644 --- a/src/coreclr/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/vm/runtimecallablewrapper.cpp @@ -322,25 +322,15 @@ OBJECTREF ComClassFactory::CreateAggregatedInstance(MethodTable* pMTClass, BOOL // Otherwise we just CoCreateInstance it. if (bUseDelegate) { - ARG_SLOT args[2]; - OBJECTREF orDelegate = pCallbackMT->GetObjCreateDelegate(); - MethodDesc *pMeth = COMDelegate::GetMethodDesc(orDelegate); GCPROTECT_BEGIN(orDelegate) { - _ASSERTE(pMeth); - MethodDescCallSite delegateMethod(pMeth, &orDelegate); - - // Get the OR on which we are going to invoke the method and set it - // as the first parameter in arg above. - args[0] = (ARG_SLOT)OBJECTREFToObject(COMDelegate::GetTargetObject(orDelegate)); - - // Pass the IUnknown of the aggregator as the second argument. - args[1] = (ARG_SLOT)(IUnknown*)pOuter; + INT_PTR callbackResult = NULL; + UnmanagedCallersOnlyCaller invokeComObjectCreationCallback(METHOD__STUBHELPERS__INVOKE_COM_OBJECT_CREATION_CALLBACK); + invokeComObjectCreationCallback.InvokeThrowing(&orDelegate, reinterpret_cast((IUnknown*)pOuter), &callbackResult); - // Call the method... - pUnk = (IUnknown *)delegateMethod.Call_RetArgSlot(args); + pUnk = reinterpret_cast(callbackResult); if (!pUnk) COMPlusThrowHR(E_FAIL); } diff --git a/src/coreclr/vm/stdinterfaces.cpp b/src/coreclr/vm/stdinterfaces.cpp index 50b39ed1eb3921..d34868afee8c4c 100644 --- a/src/coreclr/vm/stdinterfaces.cpp +++ b/src/coreclr/vm/stdinterfaces.cpp @@ -1887,34 +1887,18 @@ HRESULT __stdcall DispatchEx_GetMemberProperties ( case Property: { - BOOL bCanRead = FALSE; - BOOL bCanWrite = FALSE; - - // Find the MethodDesc's for the CanRead property. - MethodDesc *pCanReadMD = MemberLoader::FindPropertyMethod(MemberInfoObj->GetMethodTable(), PROPERTY_INFO_CAN_READ_PROP, PropertyGet); - _ASSERTE_MSG((pCanReadMD != NULL), "Unable to find getter method for property PropertyInfo::CanRead"); - MethodDescCallSite canRead(pCanReadMD, &MemberInfoObj); - - // Find the MethodDesc's for the CanWrite property. - MethodDesc *pCanWriteMD = MemberLoader::FindPropertyMethod(MemberInfoObj->GetMethodTable(), PROPERTY_INFO_CAN_WRITE_PROP, PropertyGet); - _ASSERTE_MSG((pCanWriteMD != NULL), "Unable to find setter method for property PropertyInfo::CanWrite"); - MethodDescCallSite canWrite(pCanWriteMD, &MemberInfoObj); - - // Check to see if the property can be read. - ARG_SLOT CanReadArgs[] = + enum : INT32 { - ObjToArgSlot(MemberInfoObj) + DispatchExPropertyCanRead = 1, + DispatchExPropertyCanWrite = 2, }; - bCanRead = canRead.Call_RetBool(CanReadArgs); - - // Check to see if the property can be written to. - ARG_SLOT CanWriteArgs[] = - { - ObjToArgSlot(MemberInfoObj) - }; + INT32 propertyFlags = 0; + UnmanagedCallersOnlyCaller getDispatchExPropertyFlags(METHOD__STUBHELPERS__GET_DISPATCH_EX_PROPERTY_FLAGS); + getDispatchExPropertyFlags.InvokeThrowing(&MemberInfoObj, &propertyFlags); - bCanWrite = canWrite.Call_RetBool(CanWriteArgs); + BOOL bCanRead = (propertyFlags & DispatchExPropertyCanRead) != 0; + BOOL bCanWrite = (propertyFlags & DispatchExPropertyCanWrite) != 0; *pgrfdex = (bCanRead ? fdexPropCanGet : fdexPropCannotGet) | (bCanWrite ? fdexPropCanPut : fdexPropCannotPut) | From 83f8dd6f8381767afcc59d2a324f3757e2117e6e Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 13 Mar 2026 02:41:55 +0200 Subject: [PATCH 02/11] Add guard --- src/coreclr/vm/metasig.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index ee35d300a23201..5334ffdfe7f233 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -216,7 +216,9 @@ DEFINE_METASIG(SM(RefByte_UIntPtr_RetVoid, r(b) U, v)) DEFINE_METASIG(SM(PtrVoid_Byte_UInt_RetVoid, P(v) b K, v)) DEFINE_METASIG_T(SM(PtrDelegate_IntPtr_PtrIntPtr_PtrException_RetVoid, P(C(DELEGATE)) I P(I) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrDelegate_PtrObj_IntPtr_PtrException_RetVoid, P(C(DELEGATE)) P(j) I P(C(EXCEPTION)), v)) +#ifdef FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid, P(C(ICUSTOM_QUERYINTERFACE)) P(g(GUID)) P(I) P(i) P(C(EXCEPTION)), v)) +#endif // FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(I) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrInt_PtrException_RetVoid, P(C(PROPERTY_INFO)) P(i) P(C(EXCEPTION)), v)) From e4b6de629d6eec30c7fd9b67df497ae4a9349683 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:46:16 +0000 Subject: [PATCH 03/11] Address CR fb --- .../src/System/Delegate.CoreCLR.cs | 13 ---- .../src/System/StubHelpers.cs | 74 ++++++++++++++----- src/coreclr/vm/clrtocomcall.cpp | 14 ++-- src/coreclr/vm/comcallablewrapper.cpp | 20 ----- src/coreclr/vm/comcallablewrapper.h | 3 - src/coreclr/vm/comconnectionpoints.cpp | 28 +++++-- src/coreclr/vm/corelib.h | 6 +- src/coreclr/vm/metasig.h | 6 +- src/coreclr/vm/methodtable.cpp | 38 ---------- src/coreclr/vm/methodtable.h | 3 - src/coreclr/vm/runtimecallablewrapper.cpp | 51 +------------ 11 files changed, 90 insertions(+), 166 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 7e475d68817460..358dab7f43674d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -479,19 +479,6 @@ private void DelegateConstruct(object target, IntPtr method) Construct(ObjectHandleOnStack.Create(ref _this), ObjectHandleOnStack.Create(ref target), method); } - [UnmanagedCallersOnly] - private static unsafe void DelegateConstructUco(Delegate* pDelegate, object* pTarget, IntPtr method, Exception* pException) - { - try - { - (*pDelegate).DelegateConstruct(*pTarget, method); - } - catch (Exception ex) - { - *pException = ex; - } - } - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_Construct")] private static partial void Construct(ObjectHandleOnStack _this, ObjectHandleOnStack target, IntPtr method); diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index b1c62e471a42e4..150c3773e68379 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1532,51 +1532,87 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj } } - [SupportedOSPlatform("windows")] - [UnmanagedCallersOnly] - private static unsafe void InvokeComObjectCreationCallback(Delegate* pDelegate, IntPtr pOuter, IntPtr* pResult, Exception* pException) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) { - try - { - object? callbackResult = (*pDelegate).DynamicInvoke([pOuter]); - *pResult = callbackResult is null ? IntPtr.Zero : (IntPtr)callbackResult; - } - catch (Exception ex) + IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); + return new Signature(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe object? InvokeMethodWithArgs(object? target, RuntimeMethodHandle methodHandle, Span copyOfArgs) + { + Signature signature = GetMethodSignature(methodHandle); + + MethodBase.StackAllocatedByRefs byrefs = default; + IntPtr* pByRefFixedStorage = (IntPtr*)&byrefs; + + for (int i = 0; i < copyOfArgs.Length; i++) { - *pException = ex; + *(ByReference*)(pByRefFixedStorage + i) = ByReference.Create(ref copyOfArgs[i]); } + + return RuntimeMethodHandle.InvokeMethod(target, (void**)pByRefFixedStorage, signature, isConstructor: false); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe object? InvokeMethodWithOneArg(object? target, RuntimeMethodHandle methodHandle, object? arg0) + { + MethodBase.StackAllocatedArguments stackStorage = new(arg0, null, null, null); + return InvokeMethodWithArgs(target, methodHandle, ((Span)stackStorage._args).Slice(0, 1)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe object? InvokeMethodWithTwoArgs(object? target, RuntimeMethodHandle methodHandle, object? arg0, object? arg1) + { + MethodBase.StackAllocatedArguments stackStorage = new(arg0, arg1, null, null); + return InvokeMethodWithArgs(target, methodHandle, ((Span)stackStorage._args).Slice(0, 2)); } [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] - private static unsafe void InvokeConnectionPointProviderMethod(object* pProvider, IntPtr pMethodDesc, Delegate* pDelegate, Exception* pException) + private static unsafe void InvokeConnectionPointProviderMethod( + object* pProvider, + IntPtr pProviderMethodDesc, + object* pDelegate, + IntPtr pDelegateCtorMethodDesc, + object* pSubscriber, + IntPtr pEventMethodCodePtr, + bool useUIntPtrCtor, + Exception* pException) { try { - RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); - MethodBase method = MethodBase.GetMethodFromHandle(methodHandle)!; - method.Invoke(*pProvider, [*pDelegate]); + RuntimeMethodHandle delegateCtorMethodHandle = RuntimeMethodHandle.FromIntPtr(pDelegateCtorMethodDesc); + object eventMethodCodeArg = useUIntPtrCtor ? unchecked((UIntPtr)(nuint)pEventMethodCodePtr) : pEventMethodCodePtr; + + // Construct the delegate before invoking the provider method. + InvokeMethodWithTwoArgs(*pDelegate, delegateCtorMethodHandle, *pSubscriber, eventMethodCodeArg); + + RuntimeMethodHandle providerMethodHandle = RuntimeMethodHandle.FromIntPtr(pProviderMethodDesc); + InvokeMethodWithOneArg(*pProvider, providerMethodHandle, *pDelegate); } catch (Exception ex) { - *pException = ex is TargetInvocationException { InnerException: Exception inner } ? inner : ex; + *pException = ex; } } [SupportedOSPlatform("windows")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2062:Value passed to parameter cannot be statically determined", Justification = "The runtime passes a RuntimeType describing the COM event provider. The dynamic constructor access requirements are enforced by runtime callsite semantics.")] [UnmanagedCallersOnly] - private static unsafe void InvokeClrToComEventProviderMethod(object* pEventProvider, IntPtr pMethodDesc, Delegate* pEventHandler, IntPtr* pResult, Exception* pException) + private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, Delegate* pEventHandler, IntPtr* pResult, Exception* pException) { try { + object eventProvider = pComObject->GetEventProvider(*pProviderType); RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); - MethodBase method = MethodBase.GetMethodFromHandle(methodHandle)!; - object? result = method.Invoke(*pEventProvider, [*pEventHandler]); + object? result = InvokeMethodWithOneArg(eventProvider, methodHandle, *pEventHandler); *pResult = ConvertToArgSlot(result); } catch (Exception ex) { - *pException = ex is TargetInvocationException { InnerException: Exception inner } ? inner : ex; + *pException = ex; } } diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp index 3f21e6c1251e9c..05d7c0007e7d39 100644 --- a/src/coreclr/vm/clrtocomcall.cpp +++ b/src/coreclr/vm/clrtocomcall.cpp @@ -297,11 +297,9 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe struct { OBJECTREF EventProviderTypeObj; - OBJECTREF EventProviderObj; OBJECTREF ThisObj; } gc; gc.EventProviderTypeObj = NULL; - gc.EventProviderObj = NULL; gc.ThisObj = NULL; LOG((LF_STUBS, LL_INFO1000, "Calling CLRToCOMEventCallWorker %s::%s \n", pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName)); @@ -316,11 +314,6 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe gc.EventProviderTypeObj = pEvProvMT->GetManagedClassObject(); gc.ThisObj = pFrame->GetThis(); - UnmanagedCallersOnlyCaller getEventProvider(METHOD__COM_OBJECT__GET_EVENT_PROVIDER); - - // Retrieve the event provider for the event interface type. - getEventProvider.InvokeThrowing(&gc.ThisObj, &gc.EventProviderTypeObj, &gc.EventProviderObj); - // Set up an arg iterator to retrieve the arguments from the frame. MetaSig mSig(pMD); ArgIterator ArgItr(&mSig); @@ -330,7 +323,12 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe INT_PTR eventProviderResult = NULL; UnmanagedCallersOnlyCaller invokeClrToComEventProviderMethod(METHOD__STUBHELPERS__INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD); - invokeClrToComEventProviderMethod.InvokeThrowing(&gc.EventProviderObj, (INT_PTR)pEvProvMD, &EventHandlerObj, &eventProviderResult); + invokeClrToComEventProviderMethod.InvokeThrowing( + &gc.ThisObj, + &gc.EventProviderTypeObj, + (INT_PTR)pEvProvMD, + &EventHandlerObj, + &eventProviderResult); // // If this can ever return something bigger than an INT64 byval diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index dcc671ac465e36..dfb83a20d95d75 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -4665,7 +4665,6 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas pTemplate->m_pClassComMT = NULL; // Defer setting this up. pTemplate->m_pBasicComMT = NULL; pTemplate->m_pDefaultItf = NULL; - pTemplate->m_pICustomQueryInterfaceGetInterfaceMD = NULL; pTemplate->m_flags = 0; // Determine the COM visibility of classes in our hierarchy. @@ -4785,7 +4784,6 @@ ComCallWrapperTemplate *ComCallWrapperTemplate::CreateTemplateForInterface(Metho pTemplate->m_pClassComMT = NULL; pTemplate->m_pBasicComMT = NULL; pTemplate->m_pDefaultItf = pItfMT; - pTemplate->m_pICustomQueryInterfaceGetInterfaceMD = NULL; pTemplate->m_flags = enum_RepresentsVariantInterface; // Initialize the one ComMethodTable @@ -4919,24 +4917,6 @@ ComMethodTable *ComCallWrapperTemplate::SetupComMethodTableForClass(MethodTable } -MethodDesc * ComCallWrapperTemplate::GetICustomQueryInterfaceGetInterfaceMD() -{ - CONTRACT (MethodDesc*) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(m_flags & enum_ImplementsICustomQueryInterface); - } - CONTRACT_END; - - if (m_pICustomQueryInterfaceGetInterfaceMD == NULL) - m_pICustomQueryInterfaceGetInterfaceMD = m_thClass.GetMethodTable()->GetMethodDescForInterfaceMethod( - CoreLibBinder::GetMethod(METHOD__ICUSTOM_QUERYINTERFACE__GET_INTERFACE), - TRUE /* throwOnConflict */); - RETURN m_pICustomQueryInterfaceGetInterfaceMD; -} - //-------------------------------------------------------------------------- // Module* ComCallMethodDesc::GetModule() // Get Module diff --git a/src/coreclr/vm/comcallablewrapper.h b/src/coreclr/vm/comcallablewrapper.h index 64292714243b37..9b0b4bb93ee7f1 100644 --- a/src/coreclr/vm/comcallablewrapper.h +++ b/src/coreclr/vm/comcallablewrapper.h @@ -235,8 +235,6 @@ class ComCallWrapperTemplate // Sets up the class method table for the IClassX and also lays it out. static ComMethodTable *SetupComMethodTableForClass(MethodTable *pMT, BOOL bLayOutComMT); - MethodDesc * GetICustomQueryInterfaceGetInterfaceMD(); - BOOL HasInvisibleParent() { LIMITED_METHOD_CONTRACT; @@ -328,7 +326,6 @@ class ComCallWrapperTemplate enum_IsSafeTypeForMarshalling = 0x2000, // The class can be safely marshalled out of process via DCOM }; DWORD m_flags; - MethodDesc* m_pICustomQueryInterfaceGetInterfaceMD; ULONG m_cbInterfaces; SLOT* m_rgpIPtr[1]; }; diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 9fa4470dbb38cf..c9879e5c97c4cb 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -539,6 +539,20 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // Retrieve the EE class representing the argument. MethodTable *pDelegateCls = MethodSig.GetLastTypeHandleThrowing().GetMethodTable(); + // Initialize the delegate using the arguments structure. + // Generics: ensure we get the right MethodDesc here and in similar places + // Accept both void (object, native int) and void (object, native uint) + MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); + BOOL useUIntPtrCtor = FALSE; + if (pDlgCtorMD == NULL) + { + pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_UIntPtr_RetVoid); + useUIntPtrCtor = TRUE; + } + + // The loader is responsible for only accepting well-formed delegate classes. + _ASSERTE(pDlgCtorMD); + // Make sure we activate the assembly containing the target method desc pEventMethodDesc->EnsureActive(); @@ -547,13 +561,17 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs GCPROTECT_BEGIN( pDelegate ); { - UnmanagedCallersOnlyCaller delegateCtor(METHOD__DELEGATE__CONSTRUCT_DELEGATE_UCO); - delegateCtor.InvokeThrowing(&pDelegate, &pSubscriber, (INT_PTR)pEventMethodDesc->GetMultiCallableAddrOfCode()); - UnmanagedCallersOnlyCaller invokeConnectionPointProviderMethod(METHOD__STUBHELPERS__INVOKE_CONNECTION_POINT_PROVIDER_METHOD); - // Do the actual invocation of the provider method. - invokeConnectionPointProviderMethod.InvokeThrowing(&pProvider, (INT_PTR)pProvMethodDesc, &pDelegate); + // Construct the delegate and invoke the provider method in one helper. + invokeConnectionPointProviderMethod.InvokeThrowing( + &pProvider, + (INT_PTR)pProvMethodDesc, + &pDelegate, + (INT_PTR)pDlgCtorMD, + &pSubscriber, + (INT_PTR)pEventMethodDesc->GetMultiCallableAddrOfCode(), + CLR_BOOL_ARG(useUIntPtrCtor)); } GCPROTECT_END(); } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index e385329a5a8ee6..66ae19050b2780 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -236,7 +236,6 @@ DEFINE_FIELD(DELEGATE, TARGET, _target) DEFINE_FIELD(DELEGATE, METHOD_PTR, _methodPtr) DEFINE_FIELD(DELEGATE, METHOD_PTR_AUX, _methodPtrAux) DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE, DelegateConstruct, IM_Obj_IntPtr_RetVoid) -DEFINE_METHOD(DELEGATE, CONSTRUCT_DELEGATE_UCO, DelegateConstructUco, SM_PtrDelegate_PtrObj_IntPtr_PtrException_RetVoid) DEFINE_METHOD(DELEGATE, GET_INVOKE_METHOD, GetInvokeMethod, IM_RetIntPtr) DEFINE_CLASS(INT128, System, Int128) @@ -1049,9 +1048,8 @@ DEFINE_METHOD(STUBHELPERS, CREATE_CUSTOM_MARSHALER, CreateCustomMarshal DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, GetIEnumeratorToEnumVariantMarshaler, SM_PtrObj_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, INVOKE_COM_OBJECT_CREATION_CALLBACK, InvokeComObjectCreationCallback, SM_PtrDelegate_IntPtr_PtrIntPtr_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, SM_PtrObj_IntPtr_PtrDelegate_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrObj_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, SM_PtrObj_IntPtr_PtrObj_IntPtr_PtrObj_IntPtr_Bool_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid) #endif // FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, CHECK_STRING_LENGTH, CheckStringLength, SM_Int_RetVoid) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 5334ffdfe7f233..d2205512b8ae6f 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -214,13 +214,10 @@ DEFINE_METASIG(SM(RefByte_RefByte_UIntPtr_RetVoid, r(b) r(b) U, v)) DEFINE_METASIG(SM(RefByte_Byte_UIntPtr_RetVoid, r(b) b U, v)) DEFINE_METASIG(SM(RefByte_UIntPtr_RetVoid, r(b) U, v)) DEFINE_METASIG(SM(PtrVoid_Byte_UInt_RetVoid, P(v) b K, v)) -DEFINE_METASIG_T(SM(PtrDelegate_IntPtr_PtrIntPtr_PtrException_RetVoid, P(C(DELEGATE)) I P(I) P(C(EXCEPTION)), v)) -DEFINE_METASIG_T(SM(PtrDelegate_PtrObj_IntPtr_PtrException_RetVoid, P(C(DELEGATE)) P(j) I P(C(EXCEPTION)), v)) #ifdef FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid, P(C(ICUSTOM_QUERYINTERFACE)) P(g(GUID)) P(I) P(i) P(C(EXCEPTION)), v)) #endif // FEATURE_COMINTEROP -DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(C(EXCEPTION)), v)) -DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid, P(j) I P(C(DELEGATE)) P(I) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrObj_IntPtr_PtrObj_IntPtr_PtrObj_IntPtr_Bool_PtrException_RetVoid, P(j) I P(j) I P(j) I F P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrInt_PtrException_RetVoid, P(C(PROPERTY_INFO)) P(i) P(C(EXCEPTION)), v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_RetVoid, I r(j) I, v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_Int_RetVoid, I r(j) I i,v)) @@ -438,6 +435,7 @@ DEFINE_METASIG_T(SM(PtrResolver_Int_PtrStr_PtrException_RetVoid, P(C(RESOLVER)) #ifdef FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrClass_PtrStr_Int_PtrObj_PtrArrObj_PtrArrBool_PtrArrInt_PtrArrType_PtrType_PtrObj_PtrException_RetVoid, P(C(CLASS)) P(s) i P(j) P(a(j)) P(a(F)) P(a(i)) P(a(C(TYPE))) P(C(TYPE)) P(j) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrComObject_PtrClass_PtrObj_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) P(j) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) I P(C(DELEGATE)) P(I) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_IntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) I P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_PtrType_PtrBool_PtrIntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) P(C(TYPE)) P(F) P(I) P(C(EXCEPTION)), v)) #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index eb4954d19bc3be..baccfe5f9e717d 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -708,44 +708,6 @@ MethodTable* CreateMinimalMethodTable(Module* pContainingModule, return pMT; } - -#ifdef FEATURE_COMINTEROP -//========================================================================================== -OBJECTREF MethodTable::GetObjCreateDelegate() -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - _ASSERT(!IsInterface()); - if (GetOHDelegate()) - return ObjectFromHandle(GetOHDelegate()); - else - return NULL; -} - -//========================================================================================== -void MethodTable::SetObjCreateDelegate(OBJECTREF orDelegate) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_NOTRIGGER; - THROWS; // From CreateHandle - } - CONTRACTL_END; - - if (GetOHDelegate()) - StoreObjectInHandle(GetOHDelegate(), orDelegate); - else - SetOHDelegate (GetAppDomain()->CreateHandle(orDelegate)); -} -#endif // FEATURE_COMINTEROP - - //========================================================================================== void MethodTable::SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap) { diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index b99dcb293337be..2f972a78db1c60 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1062,9 +1062,6 @@ class MethodTable BOOL SetComClassFactory(ClassFactoryBase *pFactory); #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION - OBJECTREF GetObjCreateDelegate(); - void SetObjCreateDelegate(OBJECTREF orDelegate); - private: // This is for COM Interop backwards compatibility BOOL InsertComInteropData(InteropMethodTableData *pData); diff --git a/src/coreclr/vm/runtimecallablewrapper.cpp b/src/coreclr/vm/runtimecallablewrapper.cpp index 81db5b52a007ba..24d621a5dc37de 100644 --- a/src/coreclr/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/vm/runtimecallablewrapper.cpp @@ -276,9 +276,6 @@ OBJECTREF ComClassFactory::CreateAggregatedInstance(MethodTable* pMTClass, BOOL HRESULT hr = S_OK; NewRCWHolder pNewRCW; - BOOL bUseDelegate = FALSE; - - MethodTable *pCallbackMT = NULL; OBJECTREF oref = NULL; COMOBJECTREF cref = NULL; @@ -289,58 +286,14 @@ OBJECTREF ComClassFactory::CreateAggregatedInstance(MethodTable* pMTClass, BOOL //get wrapper for the object, this could enable GC CCWHolder pComWrap = ComCallWrapper::InlineGetWrapper((OBJECTREF *)&cref); - // Make sure the ClassInitializer has run, since the user might have - // wanted to set up a COM object creation callback. - pMTClass->CheckRunClassInitThrowing(); - - // If the user is going to use a delegate to allocate the COM object - // (rather than CoCreateInstance), we need to know now, before we enable - // preemptive GC mode (since we touch object references in the - // determination). - // We don't just check the current class to see if it has a cllabck - // registered, we check up the class chain to see if any of our parents - // did. - - pCallbackMT = pMTClass; - while ((pCallbackMT != NULL) && - (pCallbackMT->GetObjCreateDelegate() == NULL) && - !pCallbackMT->IsComImport()) - { - pCallbackMT = pCallbackMT->GetParentMethodTable(); - } - - if (pCallbackMT && !pCallbackMT->IsComImport()) - bUseDelegate = TRUE; - DebuggerExitFrame __def; // get the IUnknown interface for the managed object pOuter = ComCallWrapper::GetComIPFromCCW(pComWrap, IID_IUnknown, NULL); _ASSERTE(pOuter != NULL); - // If the user has set a delegate to allocate the COM object, use it. - // Otherwise we just CoCreateInstance it. - if (bUseDelegate) - { - OBJECTREF orDelegate = pCallbackMT->GetObjCreateDelegate(); - - GCPROTECT_BEGIN(orDelegate) - { - INT_PTR callbackResult = NULL; - UnmanagedCallersOnlyCaller invokeComObjectCreationCallback(METHOD__STUBHELPERS__INVOKE_COM_OBJECT_CREATION_CALLBACK); - invokeComObjectCreationCallback.InvokeThrowing(&orDelegate, reinterpret_cast((IUnknown*)pOuter), &callbackResult); - - pUnk = reinterpret_cast(callbackResult); - if (!pUnk) - COMPlusThrowHR(E_FAIL); - } - GCPROTECT_END(); - } - else - { - _ASSERTE(m_pClassMT); - pUnk = CreateInstanceInternal(pOuter, &fDidContainment); - } + _ASSERTE(m_pClassMT); + pUnk = CreateInstanceInternal(pOuter, &fDidContainment); __def.Pop(); From 988e82aaf4477293c9d0d5edf500cc49ba6b511a Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:02:14 +0200 Subject: [PATCH 04/11] Use raw data for value type --- .../System.Private.CoreLib/src/System/StubHelpers.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 150c3773e68379..969298833c4b46 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1549,7 +1549,11 @@ private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) for (int i = 0; i < copyOfArgs.Length; i++) { - *(ByReference*)(pByRefFixedStorage + i) = ByReference.Create(ref copyOfArgs[i]); + ref object? arg = ref copyOfArgs[i]; + *(ByReference*)(pByRefFixedStorage + i) = + arg is not null && RuntimeHelpers.GetMethodTable(arg)->IsValueType + ? ByReference.Create(ref arg.GetRawData()) + : ByReference.Create(ref arg); } return RuntimeMethodHandle.InvokeMethod(target, (void**)pByRefFixedStorage, signature, isConstructor: false); From 68e943f29d87a0ed7d6897e33a7eab73981611d1 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:40:19 +0000 Subject: [PATCH 05/11] Address CR fb --- .../src/System/StubHelpers.cs | 55 +++++++++---------- src/coreclr/vm/clrtocomcall.cpp | 4 +- src/coreclr/vm/corelib.h | 2 +- src/coreclr/vm/metasig.h | 2 +- src/coreclr/vm/stdinterfaces.cpp | 4 +- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 969298833c4b46..5d0d5a49fcff2d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1492,6 +1492,9 @@ internal static void SetPendingExceptionObject(Exception? exception) [SupportedOSPlatform("windows")] internal static object GetIEnumeratorToEnumVariantMarshaler() => EnumeratorToEnumVariantMarshaler.GetInstance(string.Empty); + private const int DispatchExPropertyCanRead = 1; + private const int DispatchExPropertyCanWrite = 2; + [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, int* pResult, Exception* pException) @@ -1502,12 +1505,12 @@ private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, PropertyInfo property = *pMemberInfo; if (property.CanRead) { - result |= 1; + result |= DispatchExPropertyCanRead; } if (property.CanWrite) { - result |= 2; + result |= DispatchExPropertyCanWrite; } *pResult = result; @@ -1524,7 +1527,7 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj { try { - *pResult = (int)(*pObject).GetInterface(ref *pIid, out *ppObject); + *pResult = (int)pObject->GetInterface(ref *pIid, out *ppObject); } catch (Exception ex) { @@ -1532,17 +1535,10 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) - { - IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); - return new Signature(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe object? InvokeMethodWithArgs(object? target, RuntimeMethodHandle methodHandle, Span copyOfArgs) { - Signature signature = GetMethodSignature(methodHandle); + IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); + Signature signature = new(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); MethodBase.StackAllocatedByRefs byrefs = default; IntPtr* pByRefFixedStorage = (IntPtr*)&byrefs; @@ -1559,14 +1555,12 @@ private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) return RuntimeMethodHandle.InvokeMethod(target, (void**)pByRefFixedStorage, signature, isConstructor: false); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe object? InvokeMethodWithOneArg(object? target, RuntimeMethodHandle methodHandle, object? arg0) { MethodBase.StackAllocatedArguments stackStorage = new(arg0, null, null, null); return InvokeMethodWithArgs(target, methodHandle, ((Span)stackStorage._args).Slice(0, 1)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe object? InvokeMethodWithTwoArgs(object? target, RuntimeMethodHandle methodHandle, object? arg0, object? arg1) { MethodBase.StackAllocatedArguments stackStorage = new(arg0, arg1, null, null); @@ -1588,7 +1582,8 @@ private static unsafe void InvokeConnectionPointProviderMethod( try { RuntimeMethodHandle delegateCtorMethodHandle = RuntimeMethodHandle.FromIntPtr(pDelegateCtorMethodDesc); - object eventMethodCodeArg = useUIntPtrCtor ? unchecked((UIntPtr)(nuint)pEventMethodCodePtr) : pEventMethodCodePtr; + nuint eventMethodCodeValue = (nuint)pEventMethodCodePtr; + object eventMethodCodeArg = useUIntPtrCtor ? (UIntPtr)eventMethodCodeValue : unchecked((IntPtr)eventMethodCodeValue); // Construct the delegate before invoking the provider method. InvokeMethodWithTwoArgs(*pDelegate, delegateCtorMethodHandle, *pSubscriber, eventMethodCodeArg); @@ -1605,7 +1600,7 @@ private static unsafe void InvokeConnectionPointProviderMethod( [SupportedOSPlatform("windows")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2062:Value passed to parameter cannot be statically determined", Justification = "The runtime passes a RuntimeType describing the COM event provider. The dynamic constructor access requirements are enforced by runtime callsite semantics.")] [UnmanagedCallersOnly] - private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, Delegate* pEventHandler, IntPtr* pResult, Exception* pException) + private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, Delegate* pEventHandler, ulong* pResult, Exception* pException) { try { @@ -1621,23 +1616,23 @@ private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComOb } [SupportedOSPlatform("windows")] - private static IntPtr ConvertToArgSlot(object? value) + private static ulong ConvertToArgSlot(object? value) { return value switch { - null => IntPtr.Zero, - IntPtr pointer => pointer, - UIntPtr pointer => unchecked((IntPtr)pointer), - bool boolean => boolean ? (IntPtr)1 : IntPtr.Zero, - char character => (IntPtr)character, - byte number => (IntPtr)number, - sbyte number => (IntPtr)number, - short number => (IntPtr)number, - ushort number => (IntPtr)number, - int number => (IntPtr)number, - uint number => unchecked((IntPtr)number), - long number => checked((IntPtr)number), - ulong number => unchecked((IntPtr)number), + null => 0, + IntPtr pointer => (ulong)(nuint)pointer, + UIntPtr pointer => (ulong)(nuint)pointer, + bool boolean => boolean ? 1UL : 0UL, + char character => character, + byte number => number, + sbyte number => unchecked((ulong)number), + short number => unchecked((ulong)number), + ushort number => number, + int number => unchecked((ulong)number), + uint number => number, + long number => unchecked((ulong)number), + ulong number => number, _ => throw new NotSupportedException() }; } diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp index 05d7c0007e7d39..4b105532d91aff 100644 --- a/src/coreclr/vm/clrtocomcall.cpp +++ b/src/coreclr/vm/clrtocomcall.cpp @@ -321,7 +321,7 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe // Retrieve the event handler passed in. OBJECTREF EventHandlerObj = ObjectToOBJECTREF(*(Object**)(pFrame->GetTransitionBlock() + ArgItr.GetNextOffset())); - INT_PTR eventProviderResult = NULL; + ARG_SLOT eventProviderResult = 0; UnmanagedCallersOnlyCaller invokeClrToComEventProviderMethod(METHOD__STUBHELPERS__INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD); invokeClrToComEventProviderMethod.InvokeThrowing( &gc.ThisObj, @@ -334,7 +334,7 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe // If this can ever return something bigger than an INT64 byval // then this code is broken. Currently, however, it cannot. // - *(ARG_SLOT *)(pFrame->GetReturnValuePtr()) = (ARG_SLOT)eventProviderResult; + *(ARG_SLOT *)(pFrame->GetReturnValuePtr()) = eventProviderResult; // The COM event call worker does not support value returned in // floating point registers. diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 66ae19050b2780..0ce48dba9ca11c 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1049,7 +1049,7 @@ DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, G DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, SM_PtrObj_IntPtr_PtrObj_IntPtr_PtrObj_IntPtr_Bool_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid) #endif // FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, CHECK_STRING_LENGTH, CheckStringLength, SM_Int_RetVoid) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index d2205512b8ae6f..31e1c89b5ba634 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -435,7 +435,7 @@ DEFINE_METASIG_T(SM(PtrResolver_Int_PtrStr_PtrException_RetVoid, P(C(RESOLVER)) #ifdef FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrClass_PtrStr_Int_PtrObj_PtrArrObj_PtrArrBool_PtrArrInt_PtrArrType_PtrType_PtrObj_PtrException_RetVoid, P(C(CLASS)) P(s) i P(j) P(a(j)) P(a(F)) P(a(i)) P(a(C(TYPE))) P(C(TYPE)) P(j) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrComObject_PtrClass_PtrObj_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) P(j) P(C(EXCEPTION)), v)) -DEFINE_METASIG_T(SM(PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrIntPtr_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) I P(C(DELEGATE)) P(I) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) I P(C(DELEGATE)) P(L) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_IntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) I P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_PtrType_PtrBool_PtrIntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) P(C(TYPE)) P(F) P(I) P(C(EXCEPTION)), v)) #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/vm/stdinterfaces.cpp b/src/coreclr/vm/stdinterfaces.cpp index d34868afee8c4c..1e386956ab8a36 100644 --- a/src/coreclr/vm/stdinterfaces.cpp +++ b/src/coreclr/vm/stdinterfaces.cpp @@ -1897,8 +1897,8 @@ HRESULT __stdcall DispatchEx_GetMemberProperties ( UnmanagedCallersOnlyCaller getDispatchExPropertyFlags(METHOD__STUBHELPERS__GET_DISPATCH_EX_PROPERTY_FLAGS); getDispatchExPropertyFlags.InvokeThrowing(&MemberInfoObj, &propertyFlags); - BOOL bCanRead = (propertyFlags & DispatchExPropertyCanRead) != 0; - BOOL bCanWrite = (propertyFlags & DispatchExPropertyCanWrite) != 0; + bool bCanRead = (propertyFlags & DispatchExPropertyCanRead) != 0; + bool bCanWrite = (propertyFlags & DispatchExPropertyCanWrite) != 0; *pgrfdex = (bCanRead ? fdexPropCanGet : fdexPropCannotGet) | (bCanWrite ? fdexPropCanPut : fdexPropCannotPut) | From dd50f41286bf1048a3037bb4dad614e063b32349 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Fri, 13 Mar 2026 21:11:40 +0200 Subject: [PATCH 06/11] Add comment explaining ulong usage --- src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 5d0d5a49fcff2d..71f59aef5510db 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1600,6 +1600,8 @@ private static unsafe void InvokeConnectionPointProviderMethod( [SupportedOSPlatform("windows")] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2062:Value passed to parameter cannot be statically determined", Justification = "The runtime passes a RuntimeType describing the COM event provider. The dynamic constructor access requirements are enforced by runtime callsite semantics.")] [UnmanagedCallersOnly] + // pResult is an unmanaged ARG_SLOT* (see vm/callhelpers.h). ARG_SLOT is always 8 bytes, + // so we use ulong purely as a fixed-width bit container, not for numeric semantics. private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, Delegate* pEventHandler, ulong* pResult, Exception* pException) { try @@ -1616,6 +1618,8 @@ private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComOb } [SupportedOSPlatform("windows")] + // Convert a managed primitive return value into raw ARG_SLOT bits. + // For signed integral inputs, unchecked casts preserve the original two's-complement bit pattern. private static ulong ConvertToArgSlot(object? value) { return value switch From 5057a6acef077cc6f688458d890007a7142531c5 Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Sat, 14 Mar 2026 11:01:13 +0200 Subject: [PATCH 07/11] Delete {G,S}setOHDelegate --- src/coreclr/vm/class.h | 10 ---------- src/coreclr/vm/methodtable.cpp | 16 ---------------- src/coreclr/vm/methodtable.h | 3 --- 3 files changed, 29 deletions(-) diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 9894f59da8f482..4ffe48f7b7344f 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1468,16 +1468,6 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! GetOptionalFields()->m_pCoClassForIntf = th; } - OBJECTHANDLE GetOHDelegate() - { - LIMITED_METHOD_CONTRACT; - return m_ohDelegate; - } - void SetOHDelegate (OBJECTHANDLE _ohDelegate) - { - LIMITED_METHOD_CONTRACT; - m_ohDelegate = _ohDelegate; - } // Set the COM interface type. CorIfaceAttr GetComInterfaceType() { diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index baccfe5f9e717d..b4d4b355d77b1b 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -4864,22 +4864,6 @@ BOOL MethodTable::IsExtensibleRCW() return IsComObjectType() && !GetClass()->IsComImport(); } -//========================================================================================== -OBJECTHANDLE MethodTable::GetOHDelegate() -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(GetClass()); - return GetClass()->GetOHDelegate(); -} - -//========================================================================================== -void MethodTable::SetOHDelegate (OBJECTHANDLE _ohDelegate) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(GetClass()); - GetClass()->SetOHDelegate(_ohDelegate); -} - //========================================================================================== // Helper to skip over COM class in the hierarchy MethodTable* MethodTable::GetComPlusParentMethodTable() diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 2f972a78db1c60..23cc148a09fe57 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1027,9 +1027,6 @@ class MethodTable CorIfaceAttr GetComInterfaceType(); void SetComInterfaceType(CorIfaceAttr ItfType); - OBJECTHANDLE GetOHDelegate(); - void SetOHDelegate (OBJECTHANDLE _ohDelegate); - CorClassIfaceAttr GetComClassInterfaceType(); TypeHandle GetDefItfForComClassItf(); From 3ed9700a9f43cff9c28b66f7dfa3e7c7dd576cd2 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sat, 14 Mar 2026 11:03:27 +0200 Subject: [PATCH 08/11] Update class.h --- src/coreclr/vm/class.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 4ffe48f7b7344f..13d1ee37a8d3cd 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1678,16 +1678,8 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! PTR_MethodDescChunk m_pChunks; #ifdef FEATURE_COMINTEROP - union - { - // For CLR wrapper objects that extend an unmanaged class, this field - // may contain a delegate to be called to allocate the aggregated - // unmanaged class (instead of using CoCreateInstance). - OBJECTHANDLE m_ohDelegate; - - // For interfaces this contains the COM interface type. - CorIfaceAttr m_ComInterfaceType; - }; + // For interfaces this contains the COM interface type. + CorIfaceAttr m_ComInterfaceType; ComCallWrapperTemplate *m_pccwTemplate; // points to interop data structures used when this type is exposed to COM #endif // FEATURE_COMINTEROP From 61f5e7029024f02ac71f34f475256234e60126a6 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sat, 14 Mar 2026 23:51:24 +0200 Subject: [PATCH 09/11] Assert copyOfArgs.Length <= MaxStackAllocArgCount --- src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 71f59aef5510db..392e777eaa03d9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1539,6 +1539,7 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj { IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); Signature signature = new(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); + Debug.Assert(copyOfArgs.Length <= MethodBase.MaxStackAllocArgCount); MethodBase.StackAllocatedByRefs byrefs = default; IntPtr* pByRefFixedStorage = (IntPtr*)&byrefs; From 140e394cdcdb29f674b2d1698b387219c66fbc74 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sun, 15 Mar 2026 05:22:36 +0200 Subject: [PATCH 10/11] Update StubHelpers.cs --- .../src/System/StubHelpers.cs | 123 +++++++++++------- 1 file changed, 73 insertions(+), 50 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 392e777eaa03d9..da2e53aa9df29b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1535,37 +1535,88 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj } } - private static unsafe object? InvokeMethodWithArgs(object? target, RuntimeMethodHandle methodHandle, Span copyOfArgs) + [SupportedOSPlatform("windows")] + private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) { IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); - Signature signature = new(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); - Debug.Assert(copyOfArgs.Length <= MethodBase.MaxStackAllocArgCount); + return new Signature(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); + } - MethodBase.StackAllocatedByRefs byrefs = default; - IntPtr* pByRefFixedStorage = (IntPtr*)&byrefs; + [SupportedOSPlatform("windows")] + private static unsafe void InvokeDelegateConstructor(object delegateInstance, RuntimeMethodHandle methodHandle, object? target, nuint methodCode, bool useUIntPtrCtor) + { + nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); + Debug.Assert(methodEntryPoint != 0); - for (int i = 0; i < copyOfArgs.Length; i++) + if (useUIntPtrCtor) { - ref object? arg = ref copyOfArgs[i]; - *(ByReference*)(pByRefFixedStorage + i) = - arg is not null && RuntimeHelpers.GetMethodTable(arg)->IsValueType - ? ByReference.Create(ref arg.GetRawData()) - : ByReference.Create(ref arg); + ((delegate*)methodEntryPoint)(delegateInstance, target, methodCode); + } + else + { + ((delegate*)methodEntryPoint)(delegateInstance, target, (nint)methodCode); } - - return RuntimeMethodHandle.InvokeMethod(target, (void**)pByRefFixedStorage, signature, isConstructor: false); } - private static unsafe object? InvokeMethodWithOneArg(object? target, RuntimeMethodHandle methodHandle, object? arg0) + [SupportedOSPlatform("windows")] + private static unsafe void InvokeVoidMethodWithOneArg(object target, RuntimeMethodHandle methodHandle, object? arg0) { - MethodBase.StackAllocatedArguments stackStorage = new(arg0, null, null, null); - return InvokeMethodWithArgs(target, methodHandle, ((Span)stackStorage._args).Slice(0, 1)); + nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); + Debug.Assert(methodEntryPoint != 0); + + ((delegate*)methodEntryPoint)(target, arg0); } - private static unsafe object? InvokeMethodWithTwoArgs(object? target, RuntimeMethodHandle methodHandle, object? arg0, object? arg1) + [SupportedOSPlatform("windows")] + private static unsafe ulong InvokeArgSlotMethodWithOneArg(object target, RuntimeMethodHandle methodHandle, object? arg0) { - MethodBase.StackAllocatedArguments stackStorage = new(arg0, arg1, null, null); - return InvokeMethodWithArgs(target, methodHandle, ((Span)stackStorage._args).Slice(0, 2)); + Signature signature = GetMethodSignature(methodHandle); + RuntimeType returnType = signature.ReturnType; + nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); + Debug.Assert(methodEntryPoint != 0); + + if (returnType == typeof(void)) + { + ((delegate*)methodEntryPoint)(target, arg0); + return 0; + } + + if (returnType == typeof(bool)) + { + return ((delegate*)methodEntryPoint)(target, arg0) ? 1UL : 0UL; + } + + if (returnType == typeof(int)) + { + return unchecked((ulong)((delegate*)methodEntryPoint)(target, arg0)); + } + + if (returnType == typeof(uint)) + { + return ((delegate*)methodEntryPoint)(target, arg0); + } + + if (returnType == typeof(long)) + { + return unchecked((ulong)((delegate*)methodEntryPoint)(target, arg0)); + } + + if (returnType == typeof(ulong)) + { + return ((delegate*)methodEntryPoint)(target, arg0); + } + + if (returnType == typeof(IntPtr)) + { + return (ulong)(nuint)((delegate*)methodEntryPoint)(target, arg0); + } + + if (returnType == typeof(UIntPtr)) + { + return (ulong)((delegate*)methodEntryPoint)(target, arg0); + } + + throw new NotSupportedException(); } [SupportedOSPlatform("windows")] @@ -1583,14 +1634,11 @@ private static unsafe void InvokeConnectionPointProviderMethod( try { RuntimeMethodHandle delegateCtorMethodHandle = RuntimeMethodHandle.FromIntPtr(pDelegateCtorMethodDesc); - nuint eventMethodCodeValue = (nuint)pEventMethodCodePtr; - object eventMethodCodeArg = useUIntPtrCtor ? (UIntPtr)eventMethodCodeValue : unchecked((IntPtr)eventMethodCodeValue); - // Construct the delegate before invoking the provider method. - InvokeMethodWithTwoArgs(*pDelegate, delegateCtorMethodHandle, *pSubscriber, eventMethodCodeArg); + InvokeDelegateConstructor(*pDelegate, delegateCtorMethodHandle, *pSubscriber, (nuint)pEventMethodCodePtr, useUIntPtrCtor); RuntimeMethodHandle providerMethodHandle = RuntimeMethodHandle.FromIntPtr(pProviderMethodDesc); - InvokeMethodWithOneArg(*pProvider, providerMethodHandle, *pDelegate); + InvokeVoidMethodWithOneArg(*pProvider, providerMethodHandle, *pDelegate); } catch (Exception ex) { @@ -1609,8 +1657,7 @@ private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComOb { object eventProvider = pComObject->GetEventProvider(*pProviderType); RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); - object? result = InvokeMethodWithOneArg(eventProvider, methodHandle, *pEventHandler); - *pResult = ConvertToArgSlot(result); + *pResult = InvokeArgSlotMethodWithOneArg(eventProvider, methodHandle, *pEventHandler); } catch (Exception ex) { @@ -1618,30 +1665,6 @@ private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComOb } } - [SupportedOSPlatform("windows")] - // Convert a managed primitive return value into raw ARG_SLOT bits. - // For signed integral inputs, unchecked casts preserve the original two's-complement bit pattern. - private static ulong ConvertToArgSlot(object? value) - { - return value switch - { - null => 0, - IntPtr pointer => (ulong)(nuint)pointer, - UIntPtr pointer => (ulong)(nuint)pointer, - bool boolean => boolean ? 1UL : 0UL, - char character => character, - byte number => number, - sbyte number => unchecked((ulong)number), - short number => unchecked((ulong)number), - ushort number => number, - int number => unchecked((ulong)number), - uint number => number, - long number => unchecked((ulong)number), - ulong number => number, - _ => throw new NotSupportedException() - }; - } - [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] private static unsafe void GetIEnumeratorToEnumVariantMarshaler(object* pResult, Exception* pException) From 73975538d7051da6ce2f5fbe5eceb1200b8fb1ec Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sun, 15 Mar 2026 08:37:02 +0000 Subject: [PATCH 11/11] Simplify stuff --- .../src/System/StubHelpers.cs | 63 ++++++------------- src/coreclr/vm/clrtocomcall.cpp | 1 + src/coreclr/vm/comconnectionpoints.cpp | 8 ++- src/coreclr/vm/corelib.h | 2 +- src/coreclr/vm/metasig.h | 1 + 5 files changed, 28 insertions(+), 47 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index da2e53aa9df29b..902cf48c558728 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1535,44 +1535,11 @@ private static unsafe void CallICustomQueryInterface(ICustomQueryInterface* pObj } } - [SupportedOSPlatform("windows")] - private static Signature GetMethodSignature(RuntimeMethodHandle methodHandle) + private static unsafe ulong InvokeArgSlotMethodWithOneArg(object target, RuntimeMethodHandle methodHandle, nint methodEntryPoint, object? arg0) { IRuntimeMethodInfo methodInfo = methodHandle.GetMethodInfo(); - return new Signature(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); - } - - [SupportedOSPlatform("windows")] - private static unsafe void InvokeDelegateConstructor(object delegateInstance, RuntimeMethodHandle methodHandle, object? target, nuint methodCode, bool useUIntPtrCtor) - { - nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); - Debug.Assert(methodEntryPoint != 0); - - if (useUIntPtrCtor) - { - ((delegate*)methodEntryPoint)(delegateInstance, target, methodCode); - } - else - { - ((delegate*)methodEntryPoint)(delegateInstance, target, (nint)methodCode); - } - } - - [SupportedOSPlatform("windows")] - private static unsafe void InvokeVoidMethodWithOneArg(object target, RuntimeMethodHandle methodHandle, object? arg0) - { - nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); - Debug.Assert(methodEntryPoint != 0); - - ((delegate*)methodEntryPoint)(target, arg0); - } - - [SupportedOSPlatform("windows")] - private static unsafe ulong InvokeArgSlotMethodWithOneArg(object target, RuntimeMethodHandle methodHandle, object? arg0) - { - Signature signature = GetMethodSignature(methodHandle); + Signature signature = new(methodInfo, RuntimeMethodHandle.GetDeclaringType(methodInfo)); RuntimeType returnType = signature.ReturnType; - nint methodEntryPoint = (nint)methodHandle.GetFunctionPointer(); Debug.Assert(methodEntryPoint != 0); if (returnType == typeof(void)) @@ -1623,9 +1590,9 @@ private static unsafe ulong InvokeArgSlotMethodWithOneArg(object target, Runtime [UnmanagedCallersOnly] private static unsafe void InvokeConnectionPointProviderMethod( object* pProvider, - IntPtr pProviderMethodDesc, + IntPtr pProviderMethodPtr, object* pDelegate, - IntPtr pDelegateCtorMethodDesc, + IntPtr pDelegateCtorMethodPtr, object* pSubscriber, IntPtr pEventMethodCodePtr, bool useUIntPtrCtor, @@ -1633,12 +1600,22 @@ private static unsafe void InvokeConnectionPointProviderMethod( { try { - RuntimeMethodHandle delegateCtorMethodHandle = RuntimeMethodHandle.FromIntPtr(pDelegateCtorMethodDesc); + nint delegateCtorMethodEntryPoint = (nint)pDelegateCtorMethodPtr; + Debug.Assert(delegateCtorMethodEntryPoint != 0); + // Construct the delegate before invoking the provider method. - InvokeDelegateConstructor(*pDelegate, delegateCtorMethodHandle, *pSubscriber, (nuint)pEventMethodCodePtr, useUIntPtrCtor); + if (useUIntPtrCtor) + { + ((delegate*)delegateCtorMethodEntryPoint)(*pDelegate, *pSubscriber, (nuint)pEventMethodCodePtr); + } + else + { + ((delegate*)delegateCtorMethodEntryPoint)(*pDelegate, *pSubscriber, (nint)pEventMethodCodePtr); + } - RuntimeMethodHandle providerMethodHandle = RuntimeMethodHandle.FromIntPtr(pProviderMethodDesc); - InvokeVoidMethodWithOneArg(*pProvider, providerMethodHandle, *pDelegate); + nint providerMethodEntryPoint = (nint)pProviderMethodPtr; + Debug.Assert(providerMethodEntryPoint != 0); + ((delegate*)providerMethodEntryPoint)(*pProvider, *pDelegate); } catch (Exception ex) { @@ -1651,13 +1628,13 @@ private static unsafe void InvokeConnectionPointProviderMethod( [UnmanagedCallersOnly] // pResult is an unmanaged ARG_SLOT* (see vm/callhelpers.h). ARG_SLOT is always 8 bytes, // so we use ulong purely as a fixed-width bit container, not for numeric semantics. - private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, Delegate* pEventHandler, ulong* pResult, Exception* pException) + private static unsafe void InvokeClrToComEventProviderMethod(__ComObject* pComObject, RuntimeType* pProviderType, IntPtr pMethodDesc, IntPtr pMethodEntryPoint, Delegate* pEventHandler, ulong* pResult, Exception* pException) { try { object eventProvider = pComObject->GetEventProvider(*pProviderType); RuntimeMethodHandle methodHandle = RuntimeMethodHandle.FromIntPtr(pMethodDesc); - *pResult = InvokeArgSlotMethodWithOneArg(eventProvider, methodHandle, *pEventHandler); + *pResult = InvokeArgSlotMethodWithOneArg(eventProvider, methodHandle, (nint)pMethodEntryPoint, *pEventHandler); } catch (Exception ex) { diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp index 4b105532d91aff..a6e3f0a4c07b55 100644 --- a/src/coreclr/vm/clrtocomcall.cpp +++ b/src/coreclr/vm/clrtocomcall.cpp @@ -327,6 +327,7 @@ UINT32 CLRToCOMEventCallWorker(CLRToCOMMethodFrame* pFrame, CLRToCOMCallMethodDe &gc.ThisObj, &gc.EventProviderTypeObj, (INT_PTR)pEvProvMD, + (INT_PTR)pEvProvMD->GetMultiCallableAddrOfCode(), &EventHandlerObj, &eventProviderResult); diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index c9879e5c97c4cb..b90147c64efdc3 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -553,7 +553,9 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // The loader is responsible for only accepting well-formed delegate classes. _ASSERTE(pDlgCtorMD); - // Make sure we activate the assembly containing the target method desc + // Make sure we activate assemblies containing target method descs. + pProvMethodDesc->EnsureActive(); + pDlgCtorMD->EnsureActive(); pEventMethodDesc->EnsureActive(); // Allocate an object based on the method table of the delegate class. @@ -566,9 +568,9 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // Construct the delegate and invoke the provider method in one helper. invokeConnectionPointProviderMethod.InvokeThrowing( &pProvider, - (INT_PTR)pProvMethodDesc, + (INT_PTR)pProvMethodDesc->GetMultiCallableAddrOfCode(), &pDelegate, - (INT_PTR)pDlgCtorMD, + (INT_PTR)pDlgCtorMD->GetMultiCallableAddrOfCode(), &pSubscriber, (INT_PTR)pEventMethodDesc->GetMultiCallableAddrOfCode(), CLR_BOOL_ARG(useUIntPtrCtor)); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ed8062366f7703..ff05596ee2e635 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1050,7 +1050,7 @@ DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, G DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrInt_PtrException_RetVoid) DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, SM_PtrObj_IntPtr_PtrObj_IntPtr_PtrObj_IntPtr_Bool_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, INVOKE_CLR_TO_COM_EVENT_PROVIDER_METHOD, InvokeClrToComEventProviderMethod, SM_PtrComObject_PtrClass_IntPtr_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid) #endif // FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, CHECK_STRING_LENGTH, CheckStringLength, SM_Int_RetVoid) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 7c4551244f5910..294e7cbbceb472 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -437,6 +437,7 @@ DEFINE_METASIG_T(SM(PtrResolver_Int_PtrStr_PtrException_RetVoid, P(C(RESOLVER)) DEFINE_METASIG_T(SM(PtrClass_PtrStr_Int_PtrObj_PtrArrObj_PtrArrBool_PtrArrInt_PtrArrType_PtrType_PtrObj_PtrException_RetVoid, P(C(CLASS)) P(s) i P(j) P(a(j)) P(a(F)) P(a(i)) P(a(C(TYPE))) P(C(TYPE)) P(j) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrComObject_PtrClass_PtrObj_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) P(j) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrComObject_PtrClass_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) I P(C(DELEGATE)) P(L) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrComObject_PtrClass_IntPtr_IntPtr_PtrDelegate_PtrULong_PtrException_RetVoid, P(C(COM_OBJECT)) P(C(CLASS)) I I P(C(DELEGATE)) P(L) P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_IntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) I P(C(EXCEPTION)), v)) DEFINE_METASIG_T(SM(PtrLicenseInteropProxy_PtrType_PtrBool_PtrIntPtr_PtrException_RetVoid, P(C(LICENSE_INTEROP_PROXY)) P(C(TYPE)) P(F) P(I) P(C(EXCEPTION)), v)) #endif // FEATURE_COMINTEROP