1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // File: stubhelpers.cpp
14 #include "stubhelpers.h"
15 #include "jitinterface.h"
16 #include "dllimport.h"
17 #include "fieldmarshaler.h"
18 #include "comdelegate.h"
19 #include "eventtrace.h"
20 #include "comdatetime.h"
21 #include "gcheaputilities.h"
22 #include "interoputil.h"
24 #ifdef FEATURE_COMINTEROP
26 #include "olecontexthelpers.h"
27 #include "runtimecallablewrapper.h"
28 #include "comcallablewrapper.h"
29 #include "clrtocomcall.h"
30 #include "cominterfacemarshaler.h"
31 #include "winrttypenameconverter.h"
36 CQuickArray<StubHelpers::ByrefValidationEntry> StubHelpers::s_ByrefValidationEntries;
37 SIZE_T StubHelpers::s_ByrefValidationIndex = 0;
38 CrstStatic StubHelpers::s_ByrefValidationLock;
41 void StubHelpers::Init()
44 s_ByrefValidationLock.Init(CrstPinnedByrefValidation);
48 void StubHelpers::ValidateObjectInternal(Object *pObjUNSAFE, BOOL fValidateNextObj)
59 _ASSERTE(GCHeapUtilities::GetGCHeap()->RuntimeStructuresValid());
61 // validate the object - there's no need to validate next object's
62 // header since we validate the next object explicitly below
63 pObjUNSAFE->Validate(/*bDeep=*/ TRUE, /*bVerifyNextHeader=*/ FALSE, /*bVerifySyncBlock=*/ TRUE);
65 // and the next object as required
68 Object *nextObj = GCHeapUtilities::GetGCHeap()->NextObj(pObjUNSAFE);
71 // Note that the MethodTable of the object (i.e. the pointer at offset 0) can change from
72 // g_pFreeObjectMethodTable to NULL, from NULL to <legal-value>, or possibly also from
73 // g_pFreeObjectMethodTable to <legal-value> concurrently while executing this function.
74 // Once <legal-value> is seen, we believe that the object should pass the Validate check.
75 // We have to be careful and read the pointer only once to avoid "phantom reads".
76 MethodTable *pMT = VolatileLoad(nextObj->GetMethodTablePtr());
77 if (pMT != NULL && pMT != g_pFreeObjectMethodTable)
79 // do *not* verify the next object's syncblock - the next object is not guaranteed to
80 // be "alive" so the finalizer thread may have already released its syncblock
81 nextObj->Validate(/*bDeep=*/ TRUE, /*bVerifyNextHeader=*/ FALSE, /*bVerifySyncBlock=*/ FALSE);
88 MethodDesc *StubHelpers::ResolveInteropMethod(Object *pThisUNSAFE, MethodDesc *pMD)
92 if (pMD == NULL && pThisUNSAFE != NULL)
94 // if this is a call via delegate, get its Invoke method
95 MethodTable *pMT = pThisUNSAFE->GetMethodTable();
97 _ASSERTE(pMT->IsDelegate());
98 return ((DelegateEEClass *)pMT->GetClass())->GetInvokeMethod();
104 void StubHelpers::FormatValidationMessage(MethodDesc *pMD, SString &ssErrorString)
114 ssErrorString.Append(W("Detected managed heap corruption, likely culprit is interop call through "));
118 // the only case where we don't have interop MD is CALLI
119 ssErrorString.Append(W("CALLI."));
123 ssErrorString.Append(W("method '"));
125 StackSString ssClassName;
126 pMD->GetMethodTable()->_GetFullyQualifiedNameForClass(ssClassName);
128 ssErrorString.Append(ssClassName);
129 ssErrorString.Append(NAMESPACE_SEPARATOR_CHAR);
130 ssErrorString.AppendUTF8(pMD->GetName());
132 ssErrorString.Append(W("'."));
137 void StubHelpers::ProcessByrefValidationList()
147 StackSString errorString;
148 ByrefValidationEntry entry = { NULL, NULL };
152 AVInRuntimeImplOkayHolder AVOkay;
154 // Process all byref validation entries we have saved since the last GC. Note that EE is suspended at
155 // this point so we don't have to take locks and we can safely call code:GCHeap.GetContainingObject.
156 for (SIZE_T i = 0; i < s_ByrefValidationIndex; i++)
158 entry = s_ByrefValidationEntries[i];
160 Object *pObjUNSAFE = GCHeapUtilities::GetGCHeap()->GetContainingObject(entry.pByref, false);
161 ValidateObjectInternal(pObjUNSAFE, TRUE);
168 FormatValidationMessage(entry.pMD, errorString);
169 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
173 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
175 EX_END_CATCH_UNREACHABLE;
177 EX_END_CATCH_UNREACHABLE;
179 s_ByrefValidationIndex = 0;
182 #endif // VERIFY_HEAP
184 FCIMPL1_V(double, StubHelpers::DateMarshaler__ConvertToNative, INT64 managedDate)
189 HELPER_METHOD_FRAME_BEGIN_RET_0();
190 retval = COMDateTime::TicksToDoubleDate(managedDate);
191 HELPER_METHOD_FRAME_END();
196 FCIMPL1_V(INT64, StubHelpers::DateMarshaler__ConvertToManaged, double nativeDate)
201 HELPER_METHOD_FRAME_BEGIN_RET_0();
202 retval = COMDateTime::DoubleDateToTicks(nativeDate);
203 HELPER_METHOD_FRAME_END();
208 FCIMPL4(void, StubHelpers::ValueClassMarshaler__ConvertToNative, LPVOID pDest, LPVOID pSrc, MethodTable* pMT, OBJECTREF *ppCleanupWorkListOnStack)
212 HELPER_METHOD_FRAME_BEGIN_0();
213 FmtValueTypeUpdateNative(&pSrc, pMT, (BYTE*)pDest, ppCleanupWorkListOnStack);
214 HELPER_METHOD_FRAME_END();
218 FCIMPL3(void, StubHelpers::ValueClassMarshaler__ConvertToManaged, LPVOID pDest, LPVOID pSrc, MethodTable* pMT)
222 HELPER_METHOD_FRAME_BEGIN_0();
223 FmtValueTypeUpdateCLR(&pDest, pMT, (BYTE*)pSrc);
224 HELPER_METHOD_FRAME_END_POLL();
228 FCIMPL2(void, StubHelpers::ValueClassMarshaler__ClearNative, LPVOID pDest, MethodTable* pMT)
232 HELPER_METHOD_FRAME_BEGIN_0();
233 FmtClassDestroyNative(pDest, pMT);
234 HELPER_METHOD_FRAME_END_POLL();
238 #ifdef FEATURE_COMINTEROP
240 FORCEINLINE static void GetCOMIPFromRCW_ClearFP()
242 LIMITED_METHOD_CONTRACT;
245 // As per ASURT 146699 we need to clear FP state before calling to COM
246 // the following sequence was previously generated to compiled ML stubs
247 // and is faster than _clearfp().
256 #endif // _TARGET_X86_
259 FORCEINLINE static SOleTlsData *GetOrCreateOleTlsData()
261 LIMITED_METHOD_CONTRACT;
263 SOleTlsData *pOleTlsData;
265 // This saves 1 memory instruction over NtCurretTeb()->ReservedForOle because
266 // NtCurrentTeb() reads _TEB.NtTib.Self which is the same as what FS:0 already
268 pOleTlsData = (SOleTlsData *)(ULONG_PTR)__readfsdword(offsetof(TEB, ReservedForOle));
269 #else // _TARGET_X86_
270 pOleTlsData = (SOleTlsData *)NtCurrentTeb()->ReservedForOle;
271 #endif // _TARGET_X86_
272 if (pOleTlsData == NULL)
274 pOleTlsData = (SOleTlsData *)SetupOleContext();
279 FORCEINLINE static void *GetCOMIPFromRCW_GetTargetNoInterception(IUnknown *pUnk, ComPlusCallInfo *pComInfo)
281 LIMITED_METHOD_CONTRACT;
284 _ASSERTE(pComInfo->m_pInterceptStub == NULL || pComInfo->m_pInterceptStub == (LPVOID)-1);
285 _ASSERTE(!pComInfo->HasCopyCtorArgs());
286 #endif // _TARGET_X86_
287 _ASSERTE(!NDirect::IsHostHookEnabled());
289 LPVOID *lpVtbl = *(LPVOID **)pUnk;
290 return lpVtbl[pComInfo->m_cachedComSlot];
293 FORCEINLINE static IUnknown *GetCOMIPFromRCW_GetIUnknownFromRCWCache(RCW *pRCW, MethodTable * pItfMT)
295 LIMITED_METHOD_CONTRACT;
297 // The code in this helper is the "fast path" that used to be generated directly
298 // to compiled ML stubs. The idea is to aim for an efficient RCW cache hit.
299 SOleTlsData * pOleTlsData = GetOrCreateOleTlsData();
301 // test for free-threaded after testing for context match to optimize for apartment-bound objects
302 if (pOleTlsData->pCurrentCtx == pRCW->GetWrapperCtxCookie() || pRCW->IsFreeThreaded())
304 for (int i = 0; i < INTERFACE_ENTRY_CACHE_SIZE; i++)
306 if (pRCW->m_aInterfaceEntries[i].m_pMT == pItfMT)
308 return pRCW->m_aInterfaceEntries[i].m_pUnknown;
313 // also search the auxiliary cache if it's available
314 RCWAuxiliaryData *pAuxData = pRCW->m_pAuxiliaryData;
315 if (pAuxData != NULL)
317 LPVOID pCtxCookie = (pRCW->IsFreeThreaded() ? NULL : pOleTlsData->pCurrentCtx);
318 return pAuxData->FindInterfacePointer(pItfMT, pCtxCookie);
324 // Like GetCOMIPFromRCW_GetIUnknownFromRCWCache but also computes the target. This is a couple of instructions
325 // faster than GetCOMIPFromRCW_GetIUnknownFromRCWCache + GetCOMIPFromRCW_GetTargetNoInterception.
326 FORCEINLINE static IUnknown *GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(RCW *pRCW, ComPlusCallInfo *pComInfo, void **ppTarget)
328 LIMITED_METHOD_CONTRACT;
330 // The code in this helper is the "fast path" that used to be generated directly
331 // to compiled ML stubs. The idea is to aim for an efficient RCW cache hit.
332 SOleTlsData *pOleTlsData = GetOrCreateOleTlsData();
333 MethodTable *pItfMT = pComInfo->m_pInterfaceMT;
335 // test for free-threaded after testing for context match to optimize for apartment-bound objects
336 if (pOleTlsData->pCurrentCtx == pRCW->GetWrapperCtxCookie() || pRCW->IsFreeThreaded())
338 for (int i = 0; i < INTERFACE_ENTRY_CACHE_SIZE; i++)
340 if (pRCW->m_aInterfaceEntries[i].m_pMT == pItfMT)
342 IUnknown *pUnk = pRCW->m_aInterfaceEntries[i].m_pUnknown;
343 _ASSERTE(pUnk != NULL);
344 *ppTarget = GetCOMIPFromRCW_GetTargetNoInterception(pUnk, pComInfo);
350 // also search the auxiliary cache if it's available
351 RCWAuxiliaryData *pAuxData = pRCW->m_pAuxiliaryData;
352 if (pAuxData != NULL)
354 LPVOID pCtxCookie = (pRCW->IsFreeThreaded() ? NULL : pOleTlsData->pCurrentCtx);
356 IUnknown *pUnk = pAuxData->FindInterfacePointer(pItfMT, pCtxCookie);
359 *ppTarget = GetCOMIPFromRCW_GetTargetNoInterception(pUnk, pComInfo);
367 FORCEINLINE static void *GetCOMIPFromRCW_GetTarget(IUnknown *pUnk, ComPlusCallInfo *pComInfo)
369 LIMITED_METHOD_CONTRACT;
372 LPVOID *lpVtbl = *(LPVOID **)pUnk;
373 return lpVtbl[pComInfo->m_cachedComSlot];
376 NOINLINE static IUnknown* GetCOMIPFromRCWHelper(LPVOID pFCall, OBJECTREF pSrc, MethodDesc* pMD, void **ppTarget)
378 FC_INNER_PROLOG(pFCall);
380 IUnknown *pIntf = NULL;
382 // This is only called in IL stubs which are in CER, so we don't need to worry about ThreadAbort
383 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT|Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, pSrc);
385 SafeComHolder<IUnknown> pRetUnk;
387 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
388 pRetUnk = ComObject::GetComIPFromRCWThrowing(&pSrc, pComInfo->m_pInterfaceMT);
390 if (pFCall == StubHelpers::GetCOMIPFromRCW_WinRT ||
391 pFCall == StubHelpers::GetCOMIPFromRCW_WinRTSharedGeneric ||
392 pFCall == StubHelpers::GetCOMIPFromRCW_WinRTDelegate)
398 *ppTarget = GetCOMIPFromRCW_GetTarget(pRetUnk, pComInfo);
399 _ASSERTE(*ppTarget != NULL);
401 GetCOMIPFromRCW_ClearFP();
403 pIntf = pRetUnk.Extract();
405 // No exception will be thrown here (including thread abort as it is delayed in IL stubs)
406 HELPER_METHOD_FRAME_END();
412 //==================================================================================================================
413 // The GetCOMIPFromRCW helper exists in four specialized versions to optimize CLR->COM perf. Please be careful when
414 // changing this code as one of these methods is executed as part of every CLR->COM call so every instruction counts.
415 //==================================================================================================================
418 #include <optsmallperfcritical.h>
420 // This helper can handle any CLR->COM call (classic COM, WinRT, WinRT delegate, WinRT generic), it supports hosting,
421 // and clears FP state on x86 for compatibility with VB6.
422 FCIMPL4(IUnknown*, StubHelpers::GetCOMIPFromRCW, Object* pSrcUNSAFE, MethodDesc* pMD, void **ppTarget, CLR_BOOL* pfNeedsRelease)
427 PRECONDITION(pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl());
431 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
432 *pfNeedsRelease = false;
434 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
435 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
439 IUnknown * pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache(pRCW, pComInfo->m_pInterfaceMT);
442 *ppTarget = GetCOMIPFromRCW_GetTarget(pUnk, pComInfo);
443 if (*ppTarget != NULL)
445 GetCOMIPFromRCW_ClearFP();
451 /* if we didn't find the COM interface pointer in the cache we will have to erect an HMF */
452 *pfNeedsRelease = true;
453 FC_INNER_RETURN(IUnknown*, GetCOMIPFromRCWHelper(StubHelpers::GetCOMIPFromRCW, pSrc, pMD, ppTarget));
457 // This helper can handle only non-generic WinRT calls, does not support hosting/interception, and does not clear FP state.
458 FCIMPL3(IUnknown*, StubHelpers::GetCOMIPFromRCW_WinRT, Object* pSrcUNSAFE, MethodDesc* pMD, void** ppTarget)
463 PRECONDITION(pMD->IsComPlusCall());
467 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
469 ComPlusCallInfo *pComInfo = ((ComPlusCallMethodDesc *)pMD)->m_pComPlusCallInfo;
470 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
473 IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
480 /* if we didn't find the COM interface pointer in the cache we will have to erect an HMF */
481 FC_INNER_RETURN(IUnknown*, GetCOMIPFromRCWHelper(StubHelpers::GetCOMIPFromRCW_WinRT, pSrc, pMD, ppTarget));
485 // This helper can handle only generic WinRT calls, does not support hosting, and does not clear FP state.
486 FCIMPL3(IUnknown*, StubHelpers::GetCOMIPFromRCW_WinRTSharedGeneric, Object* pSrcUNSAFE, MethodDesc* pMD, void** ppTarget)
491 PRECONDITION(pMD->IsGenericComPlusCall());
495 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
497 ComPlusCallInfo *pComInfo = pMD->AsInstantiatedMethodDesc()->IMD_GetComPlusCallInfo();
498 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
501 IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
508 /* if we didn't find the COM interface pointer in the cache we will have to erect an HMF */
509 FC_INNER_RETURN(IUnknown*, GetCOMIPFromRCWHelper(StubHelpers::GetCOMIPFromRCW_WinRTSharedGeneric, pSrc, pMD, ppTarget));
513 // This helper can handle only delegate WinRT calls, does not support hosting, and does not clear FP state.
514 FCIMPL3(IUnknown*, StubHelpers::GetCOMIPFromRCW_WinRTDelegate, Object* pSrcUNSAFE, MethodDesc* pMD, void** ppTarget)
519 PRECONDITION(pMD->IsEEImpl());
523 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
525 ComPlusCallInfo *pComInfo = ((DelegateEEClass *)pMD->GetClass())->m_pComPlusCallInfo;
526 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
529 IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
536 /* if we didn't find the COM interface pointer in the cache we will have to erect an HMF */
537 FC_INNER_RETURN(IUnknown*, GetCOMIPFromRCWHelper(StubHelpers::GetCOMIPFromRCW_WinRTDelegate, pSrc, pMD, ppTarget));
541 #include <optdefault.h>
544 NOINLINE static FC_BOOL_RET ShouldCallWinRTInterfaceHelper(RCW *pRCW, MethodTable *pItfMT)
546 FC_INNER_PROLOG(StubHelpers::ShouldCallWinRTInterface);
550 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
552 // call the GC-triggering version
553 result = pRCW->SupportsWinRTInteropInterface(pItfMT);
555 HELPER_METHOD_FRAME_END();
558 FC_RETURN_BOOL(result);
561 FCIMPL2(FC_BOOL_RET, StubHelpers::ShouldCallWinRTInterface, Object *pSrcUNSAFE, MethodDesc *pMD)
565 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
567 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
568 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
571 // Pretend that we are not redirected WinRT type
572 // We'll throw InvalidComObjectException later in GetComIPFromRCW
576 TypeHandle::CastResult result = pRCW->SupportsWinRTInteropInterfaceNoGC(pComInfo->m_pInterfaceMT);
579 case TypeHandle::CanCast: FC_RETURN_BOOL(true);
580 case TypeHandle::CannotCast: FC_RETURN_BOOL(false);
583 FC_INNER_RETURN(FC_BOOL_RET, ShouldCallWinRTInterfaceHelper(pRCW, pComInfo->m_pInterfaceMT));
587 NOINLINE static DelegateObject *GetTargetForAmbiguousVariantCallHelper(RCW *pRCW, MethodTable *pMT, BOOL fIsEnumerable, CLR_BOOL *pfUseString)
589 FC_INNER_PROLOG(StubHelpers::GetTargetForAmbiguousVariantCall);
591 DelegateObject *pRetVal = NULL;
593 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
595 // Note that if the call succeeds, it will set the right OBJECTHANDLE/flags on the RCW so we won't have to do this
596 // next time. If the call fails, we don't care because it is an error and an exception will be thrown later.
597 SafeComHolder<IUnknown> pUnk = pRCW->GetComIPFromRCW(pMT);
599 WinRTInterfaceRedirector::WinRTLegalStructureBaseType baseType = WinRTInterfaceRedirector::GetStructureBaseType(pMT->GetInstantiation());
601 BOOL fUseString = FALSE;
603 pRetVal = (DelegateObject *)OBJECTREFToObject(pRCW->GetTargetForAmbiguousVariantCall(fIsEnumerable, baseType, &fUseString, &fUseT));
605 *pfUseString = !!fUseString;
607 HELPER_METHOD_FRAME_END();
613 // Performs a run-time check to see how an ambiguous variant call on an RCW should be handled. Returns a delegate which should
614 // be called, or sets *pfUseString to true which means that the caller should use the <string> instantiation. If NULL is returned
615 // and *pfUseString is false, the caller should attempt to handle the call as usual.
616 FCIMPL3(DelegateObject*, StubHelpers::GetTargetForAmbiguousVariantCall, Object *pSrcUNSAFE, MethodTable *pMT, CLR_BOOL *pfUseString)
620 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
622 RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
625 // ignore this - the call we'll attempt to make later will throw the right exception
626 *pfUseString = false;
630 BOOL fIsEnumerable = pMT->HasSameTypeDefAs(MscorlibBinder::GetExistingClass(CLASS__IENUMERABLEGENERIC));
631 _ASSERTE(fIsEnumerable || pMT->HasSameTypeDefAs(MscorlibBinder::GetExistingClass(CLASS__IREADONLYLISTGENERIC)));
633 WinRTInterfaceRedirector::WinRTLegalStructureBaseType baseType = WinRTInterfaceRedirector::GetStructureBaseType(pMT->GetInstantiation());
635 BOOL fUseString = FALSE;
637 DelegateObject *pRetVal = (DelegateObject *)OBJECTREFToObject(pRCW->GetTargetForAmbiguousVariantCall(fIsEnumerable, baseType, &fUseString, &fUseT));
639 if (pRetVal != NULL || fUseT || fUseString)
641 *pfUseString = !!fUseString;
645 // we haven't seen QI for the interface yet, trigger it now
646 FC_INNER_RETURN(DelegateObject*, GetTargetForAmbiguousVariantCallHelper(pRCW, pMT, fIsEnumerable, pfUseString));
650 FCIMPL2(void, StubHelpers::ObjectMarshaler__ConvertToNative, Object* pSrcUNSAFE, VARIANT* pDest)
654 OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
656 HELPER_METHOD_FRAME_BEGIN_1(pSrc);
657 if (pDest->vt & VT_BYREF)
659 OleVariant::MarshalOleRefVariantForObject(&pSrc, pDest);
663 OleVariant::MarshalOleVariantForObject(&pSrc, pDest);
665 HELPER_METHOD_FRAME_END();
669 FCIMPL1(Object*, StubHelpers::ObjectMarshaler__ConvertToManaged, VARIANT* pSrc)
673 OBJECTREF retVal = NULL;
674 HELPER_METHOD_FRAME_BEGIN_RET_1(retVal);
675 // The IL stub is going to call ObjectMarshaler__ClearNative() afterwards.
676 // If it doesn't it's a bug in ILObjectMarshaler.
677 OleVariant::MarshalObjectForOleVariant(pSrc, &retVal);
678 HELPER_METHOD_FRAME_END();
680 return OBJECTREFToObject(retVal);
684 FCIMPL1(void, StubHelpers::ObjectMarshaler__ClearNative, VARIANT* pSrc)
688 HELPER_METHOD_FRAME_BEGIN_0();
689 SafeVariantClear(pSrc);
690 HELPER_METHOD_FRAME_END();
694 #include <optsmallperfcritical.h>
695 FCIMPL4(IUnknown*, StubHelpers::InterfaceMarshaler__ConvertToNative, Object* pObjUNSAFE, MethodTable* pItfMT, MethodTable* pClsMT, DWORD dwFlags)
699 if (NULL == pObjUNSAFE)
704 IUnknown *pIntf = NULL;
705 OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
707 // This is only called in IL stubs which are in CER, so we don't need to worry about ThreadAbort
708 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pObj);
710 pIntf = MarshalObjectToInterface(&pObj, pItfMT, pClsMT, dwFlags);
712 // No exception will be thrown here (including thread abort as it is delayed in IL stubs)
713 HELPER_METHOD_FRAME_END();
719 FCIMPL4(Object*, StubHelpers::InterfaceMarshaler__ConvertToManaged, IUnknown **ppUnk, MethodTable *pItfMT, MethodTable *pClsMT, DWORD dwFlags)
728 OBJECTREF pObj = NULL;
729 HELPER_METHOD_FRAME_BEGIN_RET_1(pObj);
731 UnmarshalObjectFromInterface(&pObj, ppUnk, pItfMT, pClsMT, dwFlags);
733 HELPER_METHOD_FRAME_END();
735 return OBJECTREFToObject(pObj);
739 void QCALLTYPE StubHelpers::InterfaceMarshaler__ClearNative(IUnknown * pUnk)
743 BEGIN_QCALL_SO_TOLERANT;
745 ULONG cbRef = SafeReleasePreemp(pUnk);
746 LogInteropRelease(pUnk, cbRef, "InterfaceMarshalerBase::ClearNative: In/Out release");
748 END_QCALL_SO_TOLERANT;
750 #include <optdefault.h>
755 FCIMPL1(StringObject*, StubHelpers::UriMarshaler__GetRawUriFromNative, ABI::Windows::Foundation::IUriRuntimeClass* pIUriRC)
764 STRINGREF strRef = NULL;
765 UINT32 cchRawUri = 0;
766 LPCWSTR pwszRawUri = NULL;
768 HELPER_METHOD_FRAME_BEGIN_RET_1(strRef);
770 WinRtString hsRawUriName;
775 // Get the RawUri string from the WinRT URI object
776 IfFailThrow(pIUriRC->get_RawUri(hsRawUriName.Address()));
778 pwszRawUri = hsRawUriName.GetRawBuffer(&cchRawUri);
781 strRef = StringObject::NewString(pwszRawUri, cchRawUri);
783 HELPER_METHOD_FRAME_END();
785 return STRINGREFToObject(strRef);
789 FCIMPL2(IUnknown*, StubHelpers::UriMarshaler__CreateNativeUriInstance, WCHAR* pRawUri, UINT strLen)
793 PRECONDITION(CheckPointer(pRawUri));
797 ABI::Windows::Foundation::IUriRuntimeClass* pIUriRC = NULL;
799 HELPER_METHOD_FRAME_BEGIN_RET_0();
802 pIUriRC = CreateWinRTUri(pRawUri, strLen);
804 HELPER_METHOD_FRAME_END();
810 ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgs* QCALLTYPE
811 StubHelpers::EventArgsMarshaler__CreateNativeNCCEventArgsInstance
812 (int action, ABI::Windows::UI::Xaml::Interop::IBindableVector *newItem, ABI::Windows::UI::Xaml::Interop::IBindableVector *oldItem, int newIndex, int oldIndex)
816 ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgs *pArgsRC = NULL;
820 EventArgsMarshalingInfo *marshalingInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
821 ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgsFactory *pFactory = marshalingInfo->GetNCCEventArgsFactory();
823 SafeComHolderPreemp<IInspectable> pInner;
825 hr = pFactory->CreateInstanceWithAllParameters(
826 (ABI::Windows::UI::Xaml::Interop::NotifyCollectionChangedAction)action,
827 (ABI::Windows::UI::Xaml::Interop::IBindableVector *)newItem,
828 (ABI::Windows::UI::Xaml::Interop::IBindableVector *)oldItem,
841 ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgs* QCALLTYPE
842 StubHelpers::EventArgsMarshaler__CreateNativePCEventArgsInstance(HSTRING name)
846 ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgs *pArgsRC = NULL;
850 EventArgsMarshalingInfo *marshalingInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
851 ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgsFactory *pFactory = marshalingInfo->GetPCEventArgsFactory();
853 SafeComHolderPreemp<IInspectable> pInner;
855 hr = pFactory->CreateInstance(
867 // A helper to convert an IP to object using special flags.
868 FCIMPL1(Object *, StubHelpers::InterfaceMarshaler__ConvertToManagedWithoutUnboxing, IUnknown *pNative)
872 OBJECTREF oref = NULL;
874 HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
877 // Get a wrapper for pNative
878 // Note that we need to skip WinRT unboxing at this point because
879 // 1. We never know whether GetObjectRefFromComIP went through unboxing path.
880 // For example, user could just pass a IUnknown * to T and we'll happily convert that to T
881 // 2. If for some reason we end up getting something that does not implement IReference<T>,
882 // we'll get a nice message later when we do the cast in CLRIReferenceImpl.UnboxHelper
884 GetObjectRefFromComIP(
887 g_pBaseCOMObject, // Use __ComObject
889 ObjFromComIP::CLASS_IS_HINT | // No cast check - we'll do cast later
890 ObjFromComIP::UNIQUE_OBJECT | // Do not cache the object - To ensure that the unboxing code is called on this object always
891 // and the object is not retrieved from the cache as an __ComObject.
892 // Don't call GetRuntimeClassName - I just want a RCW of __ComObject
893 ObjFromComIP::IGNORE_WINRT_AND_SKIP_UNBOXING // Skip unboxing
896 HELPER_METHOD_FRAME_END();
898 return OBJECTREFToObject(oref);
902 FCIMPL2(StringObject *, StubHelpers::WinRTTypeNameConverter__ConvertToWinRTTypeName,
903 ReflectClassBaseObject *pTypeUNSAFE, CLR_BOOL *pbIsWinRTPrimitive)
908 PRECONDITION(CheckPointer(pTypeUNSAFE));
909 PRECONDITION(CheckPointer(pbIsWinRTPrimitive));
913 REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) pTypeUNSAFE;
914 STRINGREF refString= NULL;
915 HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, refString);
917 SString strWinRTTypeName;
919 if (WinRTTypeNameConverter::AppendWinRTTypeNameForManagedType(
920 refClass->GetType(), // thManagedType
921 strWinRTTypeName, // strWinRTTypeName to append
922 FALSE, // for type conversion, not for GetRuntimeClassName
926 *pbIsWinRTPrimitive = bIsPrimitive;
927 refString = AllocateString(strWinRTTypeName);
931 *pbIsWinRTPrimitive = FALSE;
935 HELPER_METHOD_FRAME_END();
937 return STRINGREFToObject(refString);
941 FCIMPL2(ReflectClassBaseObject *, StubHelpers::WinRTTypeNameConverter__GetTypeFromWinRTTypeName, StringObject *pWinRTTypeNameUNSAFE, CLR_BOOL *pbIsPrimitive)
946 PRECONDITION(CheckPointer(pWinRTTypeNameUNSAFE));
950 OBJECTREF refClass = NULL;
951 STRINGREF refString = ObjectToSTRINGREF(pWinRTTypeNameUNSAFE);
952 HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, refString);
955 TypeHandle th = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(refString->GetBuffer(), &isPrimitive);
956 *pbIsPrimitive = isPrimitive;
958 refClass = th.GetManagedClassObject();
960 HELPER_METHOD_FRAME_END();
962 return (ReflectClassBaseObject *)OBJECTREFToObject(refClass);
966 FCIMPL1(MethodDesc*, StubHelpers::GetDelegateInvokeMethod, DelegateObject *pThisUNSAFE)
970 MethodDesc *pMD = NULL;
972 OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
973 HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
975 MethodTable *pDelMT = pThis->GetMethodTable();
977 pMD = COMDelegate::FindDelegateInvokeMethod(pDelMT);
978 if (pMD->IsSharedByGenericInstantiations())
980 // we need the exact MethodDesc
981 pMD = InstantiatedMethodDesc::FindOrCreateExactClassMethod(pDelMT, pMD);
984 HELPER_METHOD_FRAME_END();
991 // Called from COM-to-CLR factory method stubs to get the return value (the delegating interface pointer
992 // corresponding to the default WinRT interface of the class which we are constructing).
993 FCIMPL2(IInspectable *, StubHelpers::GetWinRTFactoryReturnValue, Object *pThisUNSAFE, PCODE pCtorEntry)
997 IInspectable *pInsp = NULL;
999 OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
1000 HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
1002 // COM-to-CLR stubs use the target method entry point as their stub context
1003 MethodDesc *pCtorMD = Entry2MethodDesc(pCtorEntry, NULL);
1004 MethodTable *pClassMT = pCtorMD->GetMethodTable();
1006 // make sure that we talk to the right CCW
1007 ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(TypeHandle(pClassMT));
1008 CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&pThis, pTemplate);
1010 MethodTable *pDefaultItf = pClassMT->GetDefaultWinRTInterface();
1011 const IID &riid = (pDefaultItf == NULL ? IID_IInspectable : IID_NULL);
1013 pInsp = static_cast<IInspectable *>(ComCallWrapper::GetComIPFromCCW(pWrap, riid, pDefaultItf,
1014 GetComIPFromCCW::CheckVisibility));
1016 HELPER_METHOD_FRAME_END();
1022 // Called from CLR-to-COM factory method stubs to get the outer IInspectable to pass
1023 // to the underlying factory object.
1024 FCIMPL2(IInspectable *, StubHelpers::GetOuterInspectable, Object *pThisUNSAFE, MethodDesc *pCtorMD)
1028 IInspectable *pInsp = NULL;
1030 OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
1032 if (pThis->GetTrueMethodTable() != pCtorMD->GetMethodTable())
1034 // this is a composition scenario
1035 HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
1037 // we don't have the "outer" yet, marshal the object
1038 pInsp = static_cast<IInspectable *>
1039 (MarshalObjectToInterface(&pThis, NULL, NULL, ItfMarshalInfo::ITF_MARSHAL_INSP_ITF | ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF));
1041 HELPER_METHOD_FRAME_END();
1048 #ifdef MDA_SUPPORTED
1049 FCIMPL2(ExceptionObject*, StubHelpers::TriggerExceptionSwallowedMDA, ExceptionObject* pExceptionUNSAFE, PCODE pManagedTarget)
1052 OBJECTREF pException = ObjectToOBJECTREF(pExceptionUNSAFE);
1053 HELPER_METHOD_FRAME_BEGIN_RET_1(pException);
1055 // COM-to-CLR stubs use the target method entry point as their stub context
1056 MethodDesc * pMD = Entry2MethodDesc(pManagedTarget, NULL);
1058 MDA_TRIGGER_ASSISTANT(ExceptionSwallowedOnCallFromCom, ReportViolation(pMD, &pException));
1060 HELPER_METHOD_FRAME_END();
1061 return (ExceptionObject*)OBJECTREFToObject(pException);
1064 #endif // MDA_SUPPORTED
1066 #endif // FEATURE_COMINTEROP
1068 FCIMPL0(void, StubHelpers::SetLastError)
1070 // Make sure this is the first thing we do after returning from the target, as almost everything can cause the last error to get trashed
1071 DWORD lastError = ::GetLastError();
1075 GetThread()->m_dwLastError = lastError;
1079 FCIMPL0(void, StubHelpers::ClearLastError)
1087 FCIMPL1(FC_BOOL_RET, StubHelpers::IsQCall, NDirectMethodDesc* pNMD)
1090 FC_RETURN_BOOL(pNMD->IsQCall());
1094 NOINLINE static void InitDeclaringTypeHelper(MethodTable *pMT)
1096 FC_INNER_PROLOG(StubHelpers::InitDeclaringType);
1098 HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
1099 pMT->CheckRunClassInitThrowing();
1100 HELPER_METHOD_FRAME_END();
1105 // Triggers cctor of pNMD's declarer, similar to code:JIT_InitClass.
1106 #include <optsmallperfcritical.h>
1107 FCIMPL1(void, StubHelpers::InitDeclaringType, NDirectMethodDesc* pNMD)
1111 MethodTable *pMT = pNMD->GetMethodTable();
1112 _ASSERTE(!pMT->IsClassPreInited());
1114 if (pMT->GetDomainLocalModule()->IsClassInitialized(pMT))
1117 FC_INNER_RETURN_VOID(InitDeclaringTypeHelper(pMT));
1120 #include <optdefault.h>
1122 FCIMPL1(void*, StubHelpers::GetNDirectTarget, NDirectMethodDesc* pNMD)
1127 return pNMD->GetNDirectTarget();
1131 FCIMPL2(void*, StubHelpers::GetDelegateTarget, DelegateObject *pThisUNSAFE, UINT_PTR *ppStubArg)
1133 PCODE pEntryPoint = NULL;
1136 BEGIN_PRESERVE_LAST_ERROR;
1142 PRECONDITION(CheckPointer(pThisUNSAFE));
1146 DELEGATEREF orefThis = (DELEGATEREF)ObjectToOBJECTREF(pThisUNSAFE);
1148 #if defined(_TARGET_X86_)
1149 // On x86 we wrap the call with a thunk that handles host notifications.
1150 SyncBlock *pSyncBlock = orefThis->PassiveGetSyncBlock();
1151 if (pSyncBlock != NULL)
1153 InteropSyncBlockInfo *pInteropInfo = pSyncBlock->GetInteropInfoNoCreate();
1154 if (pInteropInfo != NULL)
1156 // we return entry point to a stub that wraps the real target
1157 Stub *pInterceptStub = pInteropInfo->GetInterceptStub();
1158 if (pInterceptStub != NULL)
1160 pEntryPoint = pInterceptStub->GetEntryPoint();
1164 #endif // _TARGET_X86_
1167 UINT_PTR target = (UINT_PTR)orefThis->GetMethodPtrAux();
1169 // The lowest bit is used to distinguish between MD and target on 64-bit.
1170 target = (target << 1) | 1;
1172 // On 64-bit we pass the real target to the stub-for-host through this out argument,
1173 // see IL code gen in NDirectStubLinker::DoNDirect for details.
1174 *ppStubArg = target;
1176 #elif defined(_TARGET_ARM_)
1177 // @ARMTODO: Nothing to do for ARM yet since we don't support the hosted path.
1178 #endif // _WIN64, _TARGET_ARM_
1180 if (pEntryPoint == NULL)
1182 pEntryPoint = orefThis->GetMethodPtrAux();
1186 END_PRESERVE_LAST_ERROR;
1189 return (PVOID)pEntryPoint;
1195 FCIMPL2(void, StubHelpers::ThrowInteropParamException, UINT resID, UINT paramIdx)
1199 HELPER_METHOD_FRAME_BEGIN_0();
1200 ::ThrowInteropParamException(resID, paramIdx);
1201 HELPER_METHOD_FRAME_END();
1205 #ifdef FEATURE_COMINTEROP
1206 FCIMPL1(void, StubHelpers::StubRegisterRCW, Object *unsafe_pThis)
1210 OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1211 HELPER_METHOD_FRAME_BEGIN_1(oref);
1213 #if defined(_DEBUG) && defined(FEATURE_MDA)
1214 // Make sure that we only get here because the MDA is turned on.
1215 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
1216 _ASSERTE(mda != NULL);
1219 // RegisterRCW may throw OOM in which case we need to decrement the refcount on the RCW
1220 class RCWDecrementUseCountHolder
1225 RCWDecrementUseCountHolder(RCW *pRCW)
1227 LIMITED_METHOD_CONTRACT;
1231 ~RCWDecrementUseCountHolder()
1233 WRAPPER_NO_CONTRACT;
1236 m_pRCW->DecrementUseCount();
1241 RCWDecrementUseCountHolder holder(oref->GetSyncBlock()->GetInteropInfoNoCreate()->GetRCWAndIncrementUseCount());
1242 if (holder.m_pRCW == NULL)
1244 COMPlusThrow(kInvalidComObjectException, IDS_EE_COM_OBJECT_NO_LONGER_HAS_WRAPPER);
1247 GET_THREAD()->RegisterRCW(holder.m_pRCW);
1249 // if we made it here, suppress the DecrementUseCount call
1250 holder.m_pRCW = NULL;
1252 HELPER_METHOD_FRAME_END();
1256 FCIMPL1(void, StubHelpers::StubUnregisterRCW, Object *unsafe_pThis)
1260 OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1261 HELPER_METHOD_FRAME_BEGIN_1(oref);
1263 #if defined(_DEBUG) && defined(FEATURE_MDA)
1264 // Make sure that we only get here because the MDA is turned on.
1265 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
1266 _ASSERTE(mda != NULL);
1269 RCW *pRCW = GET_THREAD()->UnregisterRCW(INDEBUG(oref->GetSyncBlock()));
1273 // Thread::RegisterRCW incremented the use count, decrement it now
1274 pRCW->DecrementUseCount();
1277 HELPER_METHOD_FRAME_END();
1281 class COMInterfaceMarshalerCallback : public ICOMInterfaceMarshalerCallback
1284 COMInterfaceMarshalerCallback(Thread *pThread, LPVOID pCtxCookie)
1294 _ASSERTE(pThread != NULL);
1295 _ASSERTE(pCtxCookie != NULL);
1297 m_bIsFreeThreaded = false;
1298 m_pThread = pThread;
1299 m_pCtxCookie = pCtxCookie;
1301 m_bIsDCOMProxy = false;
1304 virtual void OnRCWCreated(RCW *pRCW)
1306 LIMITED_METHOD_CONTRACT;
1308 _ASSERTE(pRCW != NULL);
1310 if (pRCW->IsFreeThreaded())
1311 m_bIsFreeThreaded = true;
1313 if (pRCW->IsDCOMProxy())
1314 m_bIsDCOMProxy = true;
1317 // Return true if ComInterfaceMarshaler should use this RCW
1318 // Return false if ComInterfaceMarshaler should just skip this RCW and proceed
1319 // to create a duplicate one instead
1320 virtual bool ShouldUseThisRCW(RCW *pRCW)
1322 LIMITED_METHOD_CONTRACT;
1324 _ASSERTE(pRCW->SupportsIInspectable());
1326 // Is this a free threaded RCW or a context-bound RCW created in the same context
1327 if (pRCW->IsFreeThreaded() ||
1328 pRCW->GetWrapperCtxCookie() == m_pCtxCookie)
1335 // Now we get back a WinRT factory RCW created in a different context. This means the
1336 // factory is a singleton, and the returned IActivationFactory could be either one of
1338 // 1) A raw pointer, and it acts like a free threaded object
1339 // 2) A proxy that is used across different contexts. It might maintain a list of contexts
1340 // that it is marshaled to, and will fail to be called if it is not marshaled to this
1343 // In this case, it is unsafe to use this RCW in this context and we should proceed
1344 // to create a duplicated one instead. It might make sense to have a context-sensitive
1345 // RCW cache but I don't think this case will be common enough to justify it
1351 virtual void OnRCWCacheHit(RCW *pRCW)
1353 LIMITED_METHOD_CONTRACT;
1355 if (pRCW->IsFreeThreaded())
1356 m_bIsFreeThreaded = true;
1358 if (pRCW->IsDCOMProxy())
1359 m_bIsDCOMProxy = true;
1362 bool IsFreeThreaded()
1364 LIMITED_METHOD_CONTRACT;
1366 return m_bIsFreeThreaded;
1371 LIMITED_METHOD_CONTRACT;
1373 return m_bIsDCOMProxy;
1377 Thread *m_pThread; // Current thread
1378 LPVOID m_pCtxCookie; // Current context cookie
1379 bool m_bIsFreeThreaded; // Whether we got back the RCW from a different context
1380 bool m_bIsDCOMProxy; // Is this a proxy to an object in a different process
1384 // Retrieve cached WinRT factory RCW or create a new one, according to the MethodDesc of the .ctor
1386 FCIMPL1(Object*, StubHelpers::GetWinRTFactoryObject, MethodDesc *pCMD)
1390 OBJECTREF refFactory = NULL;
1392 HELPER_METHOD_FRAME_BEGIN_RET_1(refFactory);
1394 MethodTable *pMTOfTypeToCreate = pCMD->GetMethodTable();
1395 AppDomain *pDomain = GetAppDomain();
1398 // Look up cached WinRT factory according to type to create + current context cookie
1399 // For each type in AppDomain, we cache only the last WinRT factory object
1400 // We don't cache factory per context in order to avoid explosion of objects if there are
1401 // multiple STA apartments
1403 // Note that if cached WinRT factory is FTM, we'll get it back regardless of the supplied cookie
1405 LPVOID lpCtxCookie = GetCurrentCtxCookie();
1406 refFactory = pDomain->LookupWinRTFactoryObject(pMTOfTypeToCreate, lpCtxCookie);
1407 if (refFactory == NULL)
1410 // Didn't find a cached factory that matches the context
1411 // Time to create a new factory and wrap it in a RCW
1415 // Creates a callback to checks for singleton WinRT factory during RCW creation
1417 // If we get back an existing RCW from a different context, this callback
1418 // will make the RCW a context-agile (but not free-threaded) RCW. Being context-agile
1419 // in this case means RCW will not make any context transition. As long as we are only
1420 // calling this RCW from where we got it back (using IInspectable* as identity), we should
1421 // be fine (as we are supposed to call that pointer directly anyway)
1423 // See code:COMInterfaceMarshalerCallback for more details
1425 COMInterfaceMarshalerCallback callback(GET_THREAD(), lpCtxCookie);
1428 // Get the activation factory instance for this WinRT type and create a RCW for it
1430 GetNativeWinRTFactoryObject(
1433 ComPlusCallInfo::FromMethodDesc(pCMD)->m_pInterfaceMT, // Factory interface
1434 FALSE, // Don't need a unique RCW
1435 // it is only needed in WindowsRuntimeMarshal.GetActivationFactory API
1440 // If this is free-threaded factory RCW, set lpCtxCookie = NULL, which means
1441 // this RCW can be used anywhere
1442 // Otherwise, we can only use this RCW from current thread
1444 if (callback.IsFreeThreaded())
1447 // Cache the result in the AD-wide cache, unless this is a proxy to a DCOM object on Apollo. In the
1448 // Apollo app model, out of process WinRT servers can have lifetimes independent of the application,
1449 // and the cache may wind up with stale pointers if we save proxies to OOP factories. In addition,
1450 // their app model is such that OOP WinRT objects cannot rely on having static state as they can be
1451 // forcibly terminated at any point. Therefore, not caching an OOP WinRT factory object in Apollo
1452 // does not lead to correctness issues.
1454 // This is not the same on the desktop, where OOP objects may contain static state, and therefore
1455 // we need to keep them alive.
1456 #ifdef FEATURE_WINDOWSPHONE
1457 if (!callback.IsDCOMProxy())
1458 #endif // FEATURE_WINDOWSPHONE
1460 pDomain->CacheWinRTFactoryObject(pMTOfTypeToCreate, &refFactory, lpCtxCookie);
1464 HELPER_METHOD_FRAME_END();
1466 return OBJECTREFToObject(refFactory);
1473 #ifdef MDA_SUPPORTED
1474 NOINLINE static void CheckCollectedDelegateMDAHelper(UMEntryThunk *pEntryThunk)
1476 FC_INNER_PROLOG(StubHelpers::CheckCollectedDelegateMDA);
1477 HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
1479 CallbackOnCollectedDelegateHelper(pEntryThunk);
1481 HELPER_METHOD_FRAME_END();
1485 FCIMPL1(void, StubHelpers::CheckCollectedDelegateMDA, LPVOID pEntryThunk)
1490 PRECONDITION(pEntryThunk != NULL);
1494 if (MDA_GET_ASSISTANT(CallbackOnCollectedDelegate) == NULL)
1497 // keep this FCall as fast as possible for the "MDA is off" case
1498 FC_INNER_RETURN_VOID(CheckCollectedDelegateMDAHelper((UMEntryThunk *)pEntryThunk));
1501 #endif // MDA_SUPPORTED
1503 #ifdef PROFILING_SUPPORTED
1504 FCIMPL3(SIZE_T, StubHelpers::ProfilerBeginTransitionCallback, SIZE_T pSecretParam, Thread* pThread, Object* unsafe_pThis)
1508 // We can get here with an ngen image generated with "/prof",
1509 // even if the profiler doesn't want to track transitions.
1510 if (!CORProfilerTrackTransitions())
1515 MethodDesc* pRealMD = NULL;
1517 BEGIN_PRESERVE_LAST_ERROR;
1519 // We must transition to preemptive GC mode before calling out to the profiler,
1520 // and the transition requires us to set up a HMF.
1521 DELEGATEREF dref = (DELEGATEREF)ObjectToOBJECTREF(unsafe_pThis);
1522 HELPER_METHOD_FRAME_BEGIN_RET_1(dref);
1524 bool fReverseInterop = false;
1526 if (NULL == pThread)
1528 // This is our signal for the reverse interop cases.
1529 fReverseInterop = true;
1530 pThread = GET_THREAD();
1531 // the secret param in this casee is the UMEntryThunk
1532 pRealMD = ((UMEntryThunk*)pSecretParam)->GetMethod();
1535 if (pSecretParam == 0)
1537 // Secret param is null. This is the calli pinvoke case or the unmanaged delegate case.
1538 // We have an unmanaged target address but no MD. For the unmanaged delegate case, we can
1539 // still retrieve the MD by looking at the "this" object.
1543 // calli pinvoke case
1548 // unmanaged delegate case
1549 MethodTable* pMT = dref->GetMethodTable();
1550 _ASSERTE(pMT->IsDelegate());
1552 EEClass * pClass = pMT->GetClass();
1553 pRealMD = ((DelegateEEClass*)pClass)->GetInvokeMethod();
1559 // This is either the COM interop or the pinvoke case.
1560 pRealMD = (MethodDesc*)pSecretParam;
1564 GCX_PREEMP_THREAD_EXISTS(pThread);
1566 if (fReverseInterop)
1568 ProfilerUnmanagedToManagedTransitionMD(pRealMD, COR_PRF_TRANSITION_CALL);
1572 ProfilerManagedToUnmanagedTransitionMD(pRealMD, COR_PRF_TRANSITION_CALL);
1576 HELPER_METHOD_FRAME_END();
1578 END_PRESERVE_LAST_ERROR;
1580 return (SIZE_T)pRealMD;
1584 FCIMPL2(void, StubHelpers::ProfilerEndTransitionCallback, MethodDesc* pRealMD, Thread* pThread)
1588 // We can get here with an ngen image generated with "/prof",
1589 // even if the profiler doesn't want to track transitions.
1590 if (!CORProfilerTrackTransitions())
1595 BEGIN_PRESERVE_LAST_ERROR;
1597 // We must transition to preemptive GC mode before calling out to the profiler,
1598 // and the transition requires us to set up a HMF.
1599 HELPER_METHOD_FRAME_BEGIN_0();
1601 bool fReverseInterop = false;
1603 if (NULL == pThread)
1605 // if pThread is null, we are doing reverse interop
1606 pThread = GET_THREAD();
1607 fReverseInterop = true;
1610 GCX_PREEMP_THREAD_EXISTS(pThread);
1612 if (fReverseInterop)
1614 ProfilerManagedToUnmanagedTransitionMD(pRealMD, COR_PRF_TRANSITION_RETURN);
1618 ProfilerUnmanagedToManagedTransitionMD(pRealMD, COR_PRF_TRANSITION_RETURN);
1621 HELPER_METHOD_FRAME_END();
1623 END_PRESERVE_LAST_ERROR;
1626 #endif // PROFILING_SUPPORTED
1628 FCIMPL1(Object*, StubHelpers::GetHRExceptionObject, HRESULT hr)
1632 OBJECTREF oThrowable = NULL;
1634 HELPER_METHOD_FRAME_BEGIN_RET_1(oThrowable);
1636 // GetExceptionForHR uses equivalant logic as COMPlusThrowHR
1637 GetExceptionForHR(hr, &oThrowable);
1639 HELPER_METHOD_FRAME_END();
1641 return OBJECTREFToObject(oThrowable);
1645 #ifdef FEATURE_COMINTEROP
1646 FCIMPL4(Object*, StubHelpers::GetCOMHRExceptionObject, HRESULT hr, MethodDesc *pMD, Object *unsafe_pThis, CLR_BOOL fForWinRT)
1650 OBJECTREF oThrowable = NULL;
1653 OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1655 HELPER_METHOD_FRAME_BEGIN_RET_2(oref, oThrowable);
1657 IErrorInfo *pErrInfo = NULL;
1659 IRestrictedErrorInfo *pResErrorInfo = NULL;
1660 BOOL bHasNonCLRLanguageErrorObject = FALSE;
1664 SafeGetRestrictedErrorInfo(&pResErrorInfo);
1665 if (pResErrorInfo != NULL)
1667 // If we have a restricted error Info lets try and find the corresponding errorInfo,
1668 // bHasNonCLRLanguageErrorObject can be TRUE|FALSE depending on whether we have an associtated LanguageExceptionObject
1669 // and whether it is CLR exceptionObject => bHasNonCLRLanguageErrorObject = FALSE;
1670 // or whether it is a non-CLRExceptionObject => bHasNonCLRLanguageErrorObject = TRUE;
1671 pErrInfo = GetCorrepondingErrorInfo_WinRT(hr, pResErrorInfo, &bHasNonCLRLanguageErrorObject);
1674 if (pErrInfo == NULL && pMD != NULL)
1676 // Retrieve the interface method table.
1677 MethodTable *pItfMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
1679 // Get IUnknown pointer for this interface on this object
1680 IUnknown* pUnk = ComObject::GetComIPFromRCW(&oref, pItfMT);
1683 // Check to see if the component supports error information for this interface.
1685 pItfMT->GetGuid(&ItfIID, TRUE);
1686 pErrInfo = GetSupportedErrorInfo(pUnk, ItfIID, !fForWinRT);
1688 DWORD cbRef = SafeRelease(pUnk);
1689 LogInteropRelease(pUnk, cbRef, "IUnk to QI for ISupportsErrorInfo");
1693 GetExceptionForHR(hr, pErrInfo, !fForWinRT, &oThrowable, pResErrorInfo, bHasNonCLRLanguageErrorObject);
1695 HELPER_METHOD_FRAME_END();
1697 return OBJECTREFToObject(oThrowable);
1700 #endif // FEATURE_COMINTEROP
1702 FCIMPL3(void, StubHelpers::FmtClassUpdateNativeInternal, Object* pObjUNSAFE, BYTE* pbNative, OBJECTREF *ppCleanupWorkListOnStack)
1706 OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
1707 HELPER_METHOD_FRAME_BEGIN_1(pObj);
1709 FmtClassUpdateNative(&pObj, pbNative, ppCleanupWorkListOnStack);
1711 HELPER_METHOD_FRAME_END();
1715 FCIMPL2(void, StubHelpers::FmtClassUpdateCLRInternal, Object* pObjUNSAFE, BYTE* pbNative)
1719 OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
1720 HELPER_METHOD_FRAME_BEGIN_1(pObj);
1722 FmtClassUpdateCLR(&pObj, pbNative);
1724 HELPER_METHOD_FRAME_END();
1728 FCIMPL2(void, StubHelpers::LayoutDestroyNativeInternal, BYTE* pbNative, MethodTable* pMT)
1732 HELPER_METHOD_FRAME_BEGIN_0();
1733 LayoutDestroyNative(pbNative, pMT);
1734 HELPER_METHOD_FRAME_END();
1738 FCIMPL1(Object*, StubHelpers::AllocateInternal, EnregisteredTypeHandle pRegisteredTypeHnd)
1742 TypeHandle typeHnd = TypeHandle::FromPtr(pRegisteredTypeHnd);
1743 OBJECTREF objRet = NULL;
1744 HELPER_METHOD_FRAME_BEGIN_RET_1(objRet);
1746 MethodTable* pMT = typeHnd.GetMethodTable();
1747 objRet = pMT->Allocate();
1749 HELPER_METHOD_FRAME_END();
1751 return OBJECTREFToObject(objRet);
1755 FCIMPL1(void, StubHelpers::DecimalCanonicalizeInternal, DECIMAL *pDec)
1759 if (FAILED(DecimalCanonicalize(pDec)))
1761 FCThrowResVoid(kOverflowException, W("Overflow_Currency"));
1766 FCIMPL1(int, StubHelpers::AnsiStrlen, __in_z char* pszStr)
1770 size_t len = strlen(pszStr);
1772 // the length should have been checked earlier (see StubHelpers.CheckStringLength)
1773 _ASSERTE(FitsInI4(len));
1779 FCIMPL3(void, StubHelpers::MarshalToUnmanagedVaListInternal, va_list va, DWORD cbVaListSize, const VARARGS* pArgIterator)
1783 HELPER_METHOD_FRAME_BEGIN_0();
1784 VARARGS::MarshalToUnmanagedVaList(va, cbVaListSize, pArgIterator);
1785 HELPER_METHOD_FRAME_END();
1789 FCIMPL2(void, StubHelpers::MarshalToManagedVaListInternal, va_list va, VARARGS* pArgIterator)
1793 VARARGS::MarshalToManagedVaList(va, pArgIterator);
1797 FCIMPL3(void, StubHelpers::ValidateObject, Object *pObjUNSAFE, MethodDesc *pMD, Object *pThisUNSAFE)
1802 HELPER_METHOD_FRAME_BEGIN_0();
1804 StackSString errorString;
1807 AVInRuntimeImplOkayHolder AVOkay;
1808 // don't validate the next object if a BGC is in progress. we can race with background
1809 // sweep which could make the next object a Free object underneath us if it's dead.
1810 ValidateObjectInternal(pObjUNSAFE, !(GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress()));
1814 FormatValidationMessage(ResolveInteropMethod(pThisUNSAFE, pMD), errorString);
1815 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
1817 EX_END_CATCH_UNREACHABLE;
1819 HELPER_METHOD_FRAME_END();
1820 #else // VERIFY_HEAP
1822 UNREACHABLE_MSG("No validation support without VERIFY_HEAP");
1823 #endif // VERIFY_HEAP
1827 FCIMPL3(void, StubHelpers::ValidateByref, void *pByref, MethodDesc *pMD, Object *pThisUNSAFE)
1832 // We cannot validate byrefs at this point as code:GCHeap.GetContainingObject could potentially race
1833 // with allocations on other threads. We'll just remember this byref along with the interop MD and
1834 // perform the validation on next GC (see code:StubHelpers.ProcessByrefValidationList).
1836 // Skip byref if is not pointing inside managed heap
1837 if (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pByref))
1841 ByrefValidationEntry entry;
1842 entry.pByref = pByref;
1843 entry.pMD = ResolveInteropMethod(pThisUNSAFE, pMD);
1845 HELPER_METHOD_FRAME_BEGIN_0();
1847 SIZE_T NumOfEntries = 0;
1849 CrstHolder ch(&s_ByrefValidationLock);
1851 if (s_ByrefValidationIndex >= s_ByrefValidationEntries.Size())
1853 // The validation list grows as necessary, for simplicity we never shrink it.
1855 if (!ClrSafeInt<SIZE_T>::multiply(s_ByrefValidationIndex, 2, newSize) ||
1856 !ClrSafeInt<SIZE_T>::addition(newSize, 1, newSize))
1858 ThrowHR(COR_E_OVERFLOW);
1861 s_ByrefValidationEntries.ReSizeThrows(newSize);
1862 _ASSERTE(s_ByrefValidationIndex < s_ByrefValidationEntries.Size());
1865 s_ByrefValidationEntries[s_ByrefValidationIndex] = entry;
1866 NumOfEntries = ++s_ByrefValidationIndex;
1869 if (NumOfEntries > BYREF_VALIDATION_LIST_MAX_SIZE)
1871 // if the list is too big, trigger GC now
1872 GCHeapUtilities::GetGCHeap()->GarbageCollect(0);
1875 HELPER_METHOD_FRAME_END();
1876 #else // VERIFY_HEAP
1878 UNREACHABLE_MSG("No validation support without VERIFY_HEAP");
1879 #endif // VERIFY_HEAP
1883 FCIMPL0(void*, StubHelpers::GetStubContext)
1888 UNREACHABLE_MSG_RET("This is a JIT intrinsic!");
1892 FCIMPL2(void, StubHelpers::LogPinnedArgument, MethodDesc *target, Object *pinnedArg)
1896 SIZE_T managedSize = 0;
1898 if (pinnedArg != NULL)
1900 // Can pass null objects to interop, only check the size if the object is valid.
1901 managedSize = pinnedArg->GetSize();
1906 STRESS_LOG3(LF_STUBS, LL_INFO100, "Managed object %#X with size '%#X' pinned for interop to Method [%pM]\n", pinnedArg, managedSize, target);
1910 STRESS_LOG2(LF_STUBS, LL_INFO100, "Managed object %#X pinned for interop with size '%#X'", pinnedArg, managedSize);
1916 FCIMPL0(void*, StubHelpers::GetStubContextAddr)
1921 UNREACHABLE_MSG("This is a JIT intrinsic!");
1926 #ifdef MDA_SUPPORTED
1927 FCIMPL0(void, StubHelpers::TriggerGCForMDA)
1931 HELPER_METHOD_FRAME_BEGIN_0();
1932 TriggerGCForMDAInternal();
1933 HELPER_METHOD_FRAME_END();
1936 #endif // MDA_SUPPORTED
1938 FCIMPL1(DWORD, StubHelpers::CalcVaListSize, VARARGS *varargs)
1942 return VARARGS::CalcVaListSize(varargs);
1946 #ifdef FEATURE_ARRAYSTUB_AS_IL
1947 NOINLINE static void ArrayTypeCheckSlow(Object* element, PtrArray* arr)
1949 FC_INNER_PROLOG(StubHelpers::ArrayTypeCheck);
1950 HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
1952 if (!ObjIsInstanceOf(element, arr->GetArrayElementTypeHandle()))
1953 COMPlusThrow(kArrayTypeMismatchException);
1955 HELPER_METHOD_FRAME_END();
1960 FCIMPL2(void, StubHelpers::ArrayTypeCheck, Object* element, PtrArray* arr)
1964 if (ObjIsInstanceOfNoGC(element, arr->GetArrayElementTypeHandle()) == TypeHandle::CanCast)
1967 FC_INNER_RETURN_VOID(ArrayTypeCheckSlow(element, arr));
1970 #endif // FEATURE_ARRAYSTUB_AS_IL
1972 #ifdef FEATURE_MULTICASTSTUB_AS_IL
1973 FCIMPL2(void, StubHelpers::MulticastDebuggerTraceHelper, Object* element, INT32 count)
1979 #endif // FEATURE_MULTICASTSTUB_AS_IL