-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Opening for discussion per #124303 (comment). @AaronRobinsonMSFT
Currently, the IDispatch support relies heavily on managed reflection stack:
runtime/src/coreclr/vm/dispatchinfo.cpp
Lines 1592 to 1794 in 1969a31
| switch (MemberType) | |
| { | |
| case Field: | |
| { | |
| // Make sure this invoke is actually for a property put or get. | |
| if (wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET)) | |
| { | |
| // Do some more validation now that we know the type of the invocation. | |
| if (NumNamedArgs != 0) | |
| COMPlusThrowHR(DISP_E_NONAMEDARGS); | |
| if (NumArgs != 0) | |
| COMPlusThrowHR(DISP_E_BADPARAMCOUNT); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetFieldInfoMD(METHOD__FIELD_INFO__GET_VALUE, pObjs->MemberInfo->GetTypeHandle()); | |
| MethodDescCallSite getValue(pMD, &pObjs->MemberInfo); | |
| // Prepare the arguments that will be passed to Invoke. | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->MemberInfo), | |
| ObjToArgSlot(pObjs->Target), | |
| }; | |
| // Do the actual method invocation. | |
| pObjs->RetVal = getValue.Call_RetOBJECTREF(Args); | |
| } | |
| else if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) | |
| { | |
| // Do some more validation now that we know the type of the invocation. | |
| if (NumArgs != 0) | |
| COMPlusThrowHR(DISP_E_BADPARAMCOUNT); | |
| if (NumNamedArgs != 0) | |
| COMPlusThrowHR(DISP_E_NONAMEDARGS); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetFieldInfoMD(METHOD__FIELD_INFO__SET_VALUE, pObjs->MemberInfo->GetTypeHandle()); | |
| MethodDescCallSite setValue(pMD, &pObjs->MemberInfo); | |
| // Prepare the arguments that will be passed to Invoke. | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->MemberInfo), | |
| ObjToArgSlot(pObjs->Target), | |
| ObjToArgSlot(pObjs->PropVal), | |
| (ARG_SLOT) BindingFlags, | |
| ObjToArgSlot(pObjs->OleAutBinder), | |
| ObjToArgSlot(pObjs->CultureInfo), | |
| }; | |
| // Do the actual method invocation. | |
| setValue.Call(Args); | |
| } | |
| else | |
| { | |
| COMPlusThrowHR(DISP_E_MEMBERNOTFOUND); | |
| } | |
| break; | |
| } | |
| case Property: | |
| { | |
| // Make sure this invoke is actually for a property put or get. | |
| if (wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET)) | |
| { | |
| if (!IsPropertyAccessorVisible(false, &pObjs->MemberInfo)) | |
| COMPlusThrowHR(DISP_E_MEMBERNOTFOUND); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetPropertyInfoMD(METHOD__PROPERTY__GET_VALUE, pObjs->MemberInfo->GetTypeHandle()); | |
| MethodDescCallSite getValue(pMD, &pObjs->MemberInfo); | |
| // Prepare the arguments that will be passed to GetValue(). | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->MemberInfo), | |
| ObjToArgSlot(pObjs->Target), | |
| (ARG_SLOT) BindingFlags, | |
| ObjToArgSlot(pObjs->OleAutBinder), | |
| ObjToArgSlot(pObjs->ParamArray), | |
| ObjToArgSlot(pObjs->CultureInfo), | |
| }; | |
| // Do the actual method invocation. | |
| pObjs->RetVal = getValue.Call_RetOBJECTREF(Args); | |
| } | |
| else if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) | |
| { | |
| if (!IsPropertyAccessorVisible(true, &pObjs->MemberInfo)) | |
| COMPlusThrowHR(DISP_E_MEMBERNOTFOUND); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetPropertyInfoMD(METHOD__PROPERTY__SET_VALUE, pObjs->MemberInfo->GetTypeHandle()); | |
| MethodDescCallSite setValue(pMD, &pObjs->MemberInfo); | |
| // Prepare the arguments that will be passed to SetValue(). | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->MemberInfo), | |
| ObjToArgSlot(pObjs->Target), | |
| ObjToArgSlot(pObjs->PropVal), | |
| (ARG_SLOT) BindingFlags, | |
| ObjToArgSlot(pObjs->OleAutBinder), | |
| ObjToArgSlot(pObjs->ParamArray), | |
| ObjToArgSlot(pObjs->CultureInfo), | |
| }; | |
| // Do the actual method invocation. | |
| setValue.Call(Args); | |
| } | |
| else | |
| { | |
| COMPlusThrowHR(DISP_E_MEMBERNOTFOUND); | |
| } | |
| break; | |
| } | |
| case Method: | |
| { | |
| // Make sure this invoke is actually for a method. We also allow | |
| // prop gets since it is harmless and it allows the user a bit | |
| // more freedom. | |
| if (!(wFlags & (DISPATCH_METHOD | DISPATCH_PROPERTYGET))) | |
| COMPlusThrowHR(DISP_E_MEMBERNOTFOUND); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetMethodInfoMD(METHOD__METHOD__INVOKE, pObjs->MemberInfo->GetTypeHandle()); | |
| MethodDescCallSite invoke(pMD, &pObjs->MemberInfo); | |
| // Prepare the arguments that will be passed to Invoke. | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->MemberInfo), | |
| ObjToArgSlot(pObjs->Target), | |
| (ARG_SLOT) BindingFlags, | |
| ObjToArgSlot(pObjs->OleAutBinder), | |
| ObjToArgSlot(pObjs->ParamArray), | |
| ObjToArgSlot(pObjs->CultureInfo), | |
| }; | |
| // Do the actual method invocation. | |
| pObjs->RetVal = invoke.Call_RetOBJECTREF(Args); | |
| break; | |
| } | |
| default: | |
| { | |
| COMPlusThrowHR(E_UNEXPECTED); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| // Convert the LCID into a CultureInfo. | |
| GetCultureInfoForLCID(lcid, &pObjs->CultureInfo); | |
| pObjs->ReflectionObj = GetReflectionObject(); | |
| // Retrieve the method descriptor that will be called on. | |
| MethodDesc *pMD = GetInvokeMemberMD(); | |
| MethodDescCallSite invokeMember(pMD, &pObjs->ReflectionObj); | |
| // Allocate the string that will contain the name of the member. | |
| if (!pDispMemberInfo) | |
| { | |
| WCHAR strTmp[64]; | |
| _snwprintf_s(strTmp, ARRAY_SIZE(strTmp), _TRUNCATE, DISPID_NAME_FORMAT_STRING, id); | |
| pObjs->MemberName = (OBJECTREF)StringObject::NewString(strTmp); | |
| } | |
| else | |
| { | |
| pObjs->MemberName = (OBJECTREF)StringObject::NewString(pDispMemberInfo->GetName().GetUnicode()); | |
| } | |
| // If there are named arguments, then set up the array of named arguments | |
| // to pass to InvokeMember. | |
| if (NumNamedArgs > 0) | |
| SetUpNamedParamArray(pDispMemberInfo, pSrcArgNames, NumNamedArgs, &pObjs->NamedArgArray); | |
| // If this is a PROPUT or a PROPPUTREF then we need to add the value | |
| // being set as the last argument in the argument array. | |
| if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) | |
| pObjs->ParamArray->SetAt(NumParams, pObjs->PropVal); | |
| // Prepare the arguments that will be passed to Invoke. | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(pObjs->ReflectionObj), | |
| ObjToArgSlot(pObjs->MemberName), | |
| (ARG_SLOT) BindingFlags, | |
| ObjToArgSlot(pObjs->OleAutBinder), | |
| ObjToArgSlot(pObjs->Target), | |
| ObjToArgSlot(pObjs->ParamArray), | |
| ObjToArgSlot(NULL), // @TODO(DM): Look into setting the byref modifiers. | |
| ObjToArgSlot(pObjs->CultureInfo), | |
| ObjToArgSlot(pObjs->NamedArgArray), | |
| }; | |
| // Do the actual method invocation. | |
| pObjs->RetVal = invokeMember.Call_RetOBJECTREF(Args); | |
| } |
runtime/src/coreclr/vm/dispatchinfo.cpp
Lines 510 to 568 in 1969a31
| LPWSTR DispatchMemberInfo::GetMemberName(OBJECTREF MemberInfoObj, ComMTMemberInfoMap *pMemberMap) | |
| { | |
| CONTRACT (LPWSTR) | |
| { | |
| THROWS; | |
| GC_TRIGGERS; | |
| MODE_COOPERATIVE; | |
| INJECT_FAULT(COMPlusThrowOM()); | |
| PRECONDITION(MemberInfoObj != NULL); | |
| PRECONDITION(CheckPointer(pMemberMap, NULL_OK)); | |
| POSTCONDITION(CheckPointer(RETVAL)); | |
| } | |
| CONTRACT_END; | |
| NewArrayHolder<WCHAR> strMemberName = NULL; | |
| ComMTMethodProps *pMemberProps = NULL; | |
| GCPROTECT_BEGIN(MemberInfoObj); | |
| { | |
| // Get the member's properties. | |
| pMemberProps = GetMemberProps(MemberInfoObj, pMemberMap); | |
| // If we managed to get the member's properties then extract the name. | |
| if (pMemberProps) | |
| { | |
| int MemberNameLen = (INT)u16_strlen(pMemberProps->pName); | |
| strMemberName = new WCHAR[MemberNameLen + 1]; | |
| memcpy(strMemberName, pMemberProps->pName, (MemberNameLen + 1) * sizeof(WCHAR)); | |
| } | |
| else | |
| { | |
| // Retrieve the Get method for the Name property. | |
| MethodDesc *pMD = MemberLoader::FindPropertyMethod(MemberInfoObj->GetMethodTable(), MEMBER_INFO_NAME_PROP, PropertyGet); | |
| _ASSERTE(pMD && "Unable to find getter method for property MemberInfo::Name"); | |
| MethodDescCallSite propGet(pMD, &MemberInfoObj); | |
| // Prepare the arguments. | |
| ARG_SLOT Args[] = | |
| { | |
| ObjToArgSlot(MemberInfoObj) | |
| }; | |
| // Retrieve the value of the Name property. | |
| STRINGREF strObj = propGet.Call_RetSTRINGREF(Args); | |
| _ASSERTE(strObj != NULL); | |
| // Copy the name into the buffer we will return. | |
| int MemberNameLen = strObj->GetStringLength(); | |
| strMemberName = new WCHAR[strObj->GetStringLength() + 1]; | |
| memcpy(strMemberName, strObj->GetBuffer(), MemberNameLen * sizeof(WCHAR)); | |
| strMemberName[MemberNameLen] = 0; | |
| } | |
| } | |
| GCPROTECT_END(); | |
| strMemberName.SuppressRelease(); | |
| RETURN strMemberName; | |
| } |
The majority of code is manipulating managed objects in native code. The proposal is to convert the managed-manipulating code to managed.
The scope will include:
DispatchInfo::InvokeMemberWorker: this is the core member that manipulates managed reflection types intensively.DispatchMemberInfo: it uses managedMemberInfoandParameterInfoto represent parameter information. The native signature parsing part is shared withMarshalInfoand should be kept native.- Most of
DispatchInfo: it uses managed reflection stack to retrieve member list, with manual synchronization etc. - Overrides of
DispParamMarshaler: most are invoking managed functions or custom marshalers. SafeArray and VT_RECORD will be kept native.
The parameter marshal and coerce logic will be kept as-is, with some code written in plain transcribed managed code.
After the conversion, the central logic of IDispatch support would be managed reflection code, with native calls for pieces unsuitable for managed code.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status