Merge pull request #14619 from briansull/emitter-cleanup
[platform/upstream/coreclr.git] / src / vm / stubhelpers.cpp
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.
4 //
5 // File: stubhelpers.cpp
6 // 
7
8 //
9
10
11 #include "common.h"
12
13 #include "mlinfo.h"
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"
23
24 #ifdef FEATURE_COMINTEROP
25 #include <oletls.h>
26 #include "olecontexthelpers.h"
27 #include "runtimecallablewrapper.h"
28 #include "comcallablewrapper.h"
29 #include "clrtocomcall.h"
30 #include "cominterfacemarshaler.h"
31 #include "winrttypenameconverter.h"
32 #endif
33
34 #ifdef VERIFY_HEAP
35
36 CQuickArray<StubHelpers::ByrefValidationEntry> StubHelpers::s_ByrefValidationEntries;
37 SIZE_T StubHelpers::s_ByrefValidationIndex = 0;
38 CrstStatic StubHelpers::s_ByrefValidationLock;
39
40 // static
41 void StubHelpers::Init()
42 {
43     WRAPPER_NO_CONTRACT;
44     s_ByrefValidationLock.Init(CrstPinnedByrefValidation);
45 }
46
47 // static
48 void StubHelpers::ValidateObjectInternal(Object *pObjUNSAFE, BOOL fValidateNextObj)
49 {
50         CONTRACTL
51         {
52         NOTHROW;
53         GC_NOTRIGGER;
54         MODE_ANY;
55         SO_TOLERANT;
56 }
57         CONTRACTL_END;
58
59         _ASSERTE(GCHeapUtilities::GetGCHeap()->RuntimeStructuresValid());
60
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);
64
65         // and the next object as required
66         if (fValidateNextObj)
67         {
68                 Object *nextObj = GCHeapUtilities::GetGCHeap()->NextObj(pObjUNSAFE);
69                 if (nextObj != NULL)
70                 {
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)
78                         {
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);
82                         }
83                 }
84         }
85 }
86
87 // static
88 MethodDesc *StubHelpers::ResolveInteropMethod(Object *pThisUNSAFE, MethodDesc *pMD)
89 {
90     WRAPPER_NO_CONTRACT;
91
92     if (pMD == NULL && pThisUNSAFE != NULL)
93     {
94         // if this is a call via delegate, get its Invoke method
95         MethodTable *pMT = pThisUNSAFE->GetMethodTable();
96
97         _ASSERTE(pMT->IsDelegate());
98         return ((DelegateEEClass *)pMT->GetClass())->GetInvokeMethod();
99     }
100     return pMD;
101 }
102
103 // static
104 void StubHelpers::FormatValidationMessage(MethodDesc *pMD, SString &ssErrorString)
105 {
106     CONTRACTL
107     {
108         THROWS;
109         GC_NOTRIGGER;
110         MODE_ANY;           
111     }
112     CONTRACTL_END;
113
114     ssErrorString.Append(W("Detected managed heap corruption, likely culprit is interop call through "));
115
116     if (pMD == NULL)
117     {
118         // the only case where we don't have interop MD is CALLI
119         ssErrorString.Append(W("CALLI."));
120     }
121     else
122     {
123         ssErrorString.Append(W("method '"));
124
125         StackSString ssClassName;
126         pMD->GetMethodTable()->_GetFullyQualifiedNameForClass(ssClassName);
127
128         ssErrorString.Append(ssClassName);
129         ssErrorString.Append(NAMESPACE_SEPARATOR_CHAR);
130         ssErrorString.AppendUTF8(pMD->GetName());
131
132         ssErrorString.Append(W("'."));
133     }
134 }
135
136 // static
137 void StubHelpers::ProcessByrefValidationList()
138 {
139     CONTRACTL
140     {
141         NOTHROW;
142         GC_NOTRIGGER;
143         MODE_ANY;           
144     }
145     CONTRACTL_END;
146
147     StackSString errorString;
148     ByrefValidationEntry entry = { NULL, NULL };
149
150     EX_TRY
151     {
152         AVInRuntimeImplOkayHolder AVOkay;
153
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++)
157         {
158             entry = s_ByrefValidationEntries[i];
159
160             Object *pObjUNSAFE = GCHeapUtilities::GetGCHeap()->GetContainingObject(entry.pByref, false);
161             ValidateObjectInternal(pObjUNSAFE, TRUE);
162         }
163     }
164     EX_CATCH
165     {
166         EX_TRY
167         {
168             FormatValidationMessage(entry.pMD, errorString);
169             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
170         }
171         EX_CATCH
172         {
173             EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
174         }
175         EX_END_CATCH_UNREACHABLE;
176     }
177     EX_END_CATCH_UNREACHABLE;
178
179     s_ByrefValidationIndex = 0;
180 }
181
182 #endif // VERIFY_HEAP
183
184 FCIMPL1_V(double, StubHelpers::DateMarshaler__ConvertToNative,  INT64 managedDate)
185 {
186     FCALL_CONTRACT;
187
188     double retval = 0.0;
189     HELPER_METHOD_FRAME_BEGIN_RET_0();
190     retval = COMDateTime::TicksToDoubleDate(managedDate);
191     HELPER_METHOD_FRAME_END();
192     return retval;
193 }
194 FCIMPLEND
195
196 FCIMPL1_V(INT64, StubHelpers::DateMarshaler__ConvertToManaged, double nativeDate)
197 {
198     FCALL_CONTRACT;
199
200     INT64 retval = 0;
201     HELPER_METHOD_FRAME_BEGIN_RET_0();
202     retval = COMDateTime::DoubleDateToTicks(nativeDate);
203     HELPER_METHOD_FRAME_END();
204     return retval;
205 }
206 FCIMPLEND
207
208 FCIMPL4(void, StubHelpers::ValueClassMarshaler__ConvertToNative, LPVOID pDest, LPVOID pSrc, MethodTable* pMT, OBJECTREF *ppCleanupWorkListOnStack)
209 {
210     FCALL_CONTRACT;
211
212     HELPER_METHOD_FRAME_BEGIN_0();
213     FmtValueTypeUpdateNative(&pSrc, pMT, (BYTE*)pDest, ppCleanupWorkListOnStack);
214     HELPER_METHOD_FRAME_END();
215 }
216 FCIMPLEND
217
218 FCIMPL3(void, StubHelpers::ValueClassMarshaler__ConvertToManaged, LPVOID pDest, LPVOID pSrc, MethodTable* pMT)
219 {
220     FCALL_CONTRACT;
221
222     HELPER_METHOD_FRAME_BEGIN_0();
223     FmtValueTypeUpdateCLR(&pDest, pMT, (BYTE*)pSrc);
224     HELPER_METHOD_FRAME_END_POLL();
225 }
226 FCIMPLEND
227
228 FCIMPL2(void, StubHelpers::ValueClassMarshaler__ClearNative, LPVOID pDest, MethodTable* pMT)
229 {
230     FCALL_CONTRACT;
231
232     HELPER_METHOD_FRAME_BEGIN_0();
233     FmtClassDestroyNative(pDest, pMT);
234     HELPER_METHOD_FRAME_END_POLL();
235 }
236 FCIMPLEND
237
238 #ifdef FEATURE_COMINTEROP
239
240 FORCEINLINE static void GetCOMIPFromRCW_ClearFP()
241 {
242     LIMITED_METHOD_CONTRACT;
243
244 #ifdef _TARGET_X86_
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().
248     __asm
249     {
250         fnstsw ax
251         and    eax, 0x3F
252         jz     NoNeedToClear
253         fnclex
254 NoNeedToClear:
255     }
256 #endif // _TARGET_X86_
257 }
258
259 FORCEINLINE static SOleTlsData *GetOrCreateOleTlsData()
260 {
261     LIMITED_METHOD_CONTRACT;
262
263     SOleTlsData *pOleTlsData;
264 #ifdef _TARGET_X86_
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
267     // points to.
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)
273     {
274         pOleTlsData = (SOleTlsData *)SetupOleContext();
275     }
276     return pOleTlsData;
277 }
278
279 FORCEINLINE static void *GetCOMIPFromRCW_GetTargetNoInterception(IUnknown *pUnk, ComPlusCallInfo *pComInfo)
280 {
281     LIMITED_METHOD_CONTRACT;
282
283 #ifdef _TARGET_X86_
284     _ASSERTE(pComInfo->m_pInterceptStub == NULL || pComInfo->m_pInterceptStub == (LPVOID)-1);
285     _ASSERTE(!pComInfo->HasCopyCtorArgs());
286 #endif // _TARGET_X86_
287     _ASSERTE(!NDirect::IsHostHookEnabled());
288
289     LPVOID *lpVtbl = *(LPVOID **)pUnk;
290     return lpVtbl[pComInfo->m_cachedComSlot];
291 }
292
293 FORCEINLINE static IUnknown *GetCOMIPFromRCW_GetIUnknownFromRCWCache(RCW *pRCW, MethodTable * pItfMT)
294 {
295     LIMITED_METHOD_CONTRACT;
296
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();
300     
301     // test for free-threaded after testing for context match to optimize for apartment-bound objects
302     if (pOleTlsData->pCurrentCtx == pRCW->GetWrapperCtxCookie() || pRCW->IsFreeThreaded())
303     {
304         for (int i = 0; i < INTERFACE_ENTRY_CACHE_SIZE; i++)
305         {
306             if (pRCW->m_aInterfaceEntries[i].m_pMT == pItfMT)
307             {
308                 return pRCW->m_aInterfaceEntries[i].m_pUnknown;
309             }
310         }
311     }
312
313     // also search the auxiliary cache if it's available
314     RCWAuxiliaryData *pAuxData = pRCW->m_pAuxiliaryData;
315     if (pAuxData != NULL)
316     {
317         LPVOID pCtxCookie = (pRCW->IsFreeThreaded() ? NULL : pOleTlsData->pCurrentCtx);
318         return pAuxData->FindInterfacePointer(pItfMT, pCtxCookie);
319     }
320
321     return NULL;
322 }
323
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)
327 {
328     LIMITED_METHOD_CONTRACT;
329
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;
334     
335     // test for free-threaded after testing for context match to optimize for apartment-bound objects
336     if (pOleTlsData->pCurrentCtx == pRCW->GetWrapperCtxCookie() || pRCW->IsFreeThreaded())
337     {
338         for (int i = 0; i < INTERFACE_ENTRY_CACHE_SIZE; i++)
339         {
340             if (pRCW->m_aInterfaceEntries[i].m_pMT == pItfMT)
341             {
342                 IUnknown *pUnk = pRCW->m_aInterfaceEntries[i].m_pUnknown;
343                 _ASSERTE(pUnk != NULL);
344                 *ppTarget = GetCOMIPFromRCW_GetTargetNoInterception(pUnk, pComInfo);
345                 return pUnk;
346             }
347         }
348     }
349
350     // also search the auxiliary cache if it's available
351     RCWAuxiliaryData *pAuxData = pRCW->m_pAuxiliaryData;
352     if (pAuxData != NULL)
353     {
354         LPVOID pCtxCookie = (pRCW->IsFreeThreaded() ? NULL : pOleTlsData->pCurrentCtx);
355         
356         IUnknown *pUnk = pAuxData->FindInterfacePointer(pItfMT, pCtxCookie);
357         if (pUnk != NULL)
358         {
359             *ppTarget = GetCOMIPFromRCW_GetTargetNoInterception(pUnk, pComInfo);
360             return pUnk;
361         }
362     }
363
364     return NULL;
365 }
366
367 FORCEINLINE static void *GetCOMIPFromRCW_GetTarget(IUnknown *pUnk, ComPlusCallInfo *pComInfo)
368 {
369     LIMITED_METHOD_CONTRACT;
370
371
372     LPVOID *lpVtbl = *(LPVOID **)pUnk;
373     return lpVtbl[pComInfo->m_cachedComSlot];
374 }
375
376 NOINLINE static IUnknown* GetCOMIPFromRCWHelper(LPVOID pFCall, OBJECTREF pSrc, MethodDesc* pMD, void **ppTarget)
377 {
378     FC_INNER_PROLOG(pFCall);
379
380     IUnknown *pIntf = NULL;
381
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);
384
385     SafeComHolder<IUnknown> pRetUnk;
386
387     ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
388     pRetUnk = ComObject::GetComIPFromRCWThrowing(&pSrc, pComInfo->m_pInterfaceMT);
389
390     if (pFCall == StubHelpers::GetCOMIPFromRCW_WinRT ||
391         pFCall == StubHelpers::GetCOMIPFromRCW_WinRTSharedGeneric ||
392         pFCall == StubHelpers::GetCOMIPFromRCW_WinRTDelegate)
393     {
394         pRetUnk.Release();
395     }
396
397
398     *ppTarget = GetCOMIPFromRCW_GetTarget(pRetUnk, pComInfo);
399     _ASSERTE(*ppTarget != NULL);
400
401     GetCOMIPFromRCW_ClearFP();
402
403     pIntf = pRetUnk.Extract();
404     
405     // No exception will be thrown here (including thread abort as it is delayed in IL stubs)
406     HELPER_METHOD_FRAME_END();
407
408     FC_INNER_EPILOG();
409     return pIntf;
410 }
411
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 //==================================================================================================================
416
417
418 #include <optsmallperfcritical.h>
419
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)
423 {
424     CONTRACTL
425     {
426         FCALL_CHECK;
427         PRECONDITION(pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl());
428     }
429     CONTRACTL_END;
430
431     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
432     *pfNeedsRelease = false;
433
434     ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
435     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
436     if (pRCW != NULL)
437     {
438
439         IUnknown * pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache(pRCW, pComInfo->m_pInterfaceMT);
440         if (pUnk != NULL)
441         {
442             *ppTarget = GetCOMIPFromRCW_GetTarget(pUnk, pComInfo);
443             if (*ppTarget != NULL)
444             {
445                 GetCOMIPFromRCW_ClearFP();
446                 return pUnk;
447             }
448         }
449     }
450
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));
454 }
455 FCIMPLEND
456
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)
459 {
460     CONTRACTL
461     {
462         FCALL_CHECK;
463         PRECONDITION(pMD->IsComPlusCall());
464     }
465     CONTRACTL_END;
466
467     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
468
469     ComPlusCallInfo *pComInfo = ((ComPlusCallMethodDesc *)pMD)->m_pComPlusCallInfo;
470     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
471     if (pRCW != NULL)
472     {
473         IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
474         if (pUnk != NULL)
475         {
476             return pUnk;
477         }
478     }
479
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));
482 }
483 FCIMPLEND
484
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)
487 {
488     CONTRACTL
489     {
490         FCALL_CHECK;
491         PRECONDITION(pMD->IsGenericComPlusCall());
492     }
493     CONTRACTL_END;
494
495     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
496
497     ComPlusCallInfo *pComInfo = pMD->AsInstantiatedMethodDesc()->IMD_GetComPlusCallInfo();
498     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
499     if (pRCW != NULL)
500     {
501         IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
502         if (pUnk != NULL)
503         {
504             return pUnk;
505         }
506     }
507
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));
510 }
511 FCIMPLEND
512
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)
515 {
516     CONTRACTL
517     {
518         FCALL_CHECK;
519         PRECONDITION(pMD->IsEEImpl());
520     }
521     CONTRACTL_END;
522
523     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
524
525     ComPlusCallInfo *pComInfo = ((DelegateEEClass *)pMD->GetClass())->m_pComPlusCallInfo;
526     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
527     if (pRCW != NULL)
528     {
529         IUnknown *pUnk = GetCOMIPFromRCW_GetIUnknownFromRCWCache_NoInterception(pRCW, pComInfo, ppTarget);
530         if (pUnk != NULL)
531         {
532             return pUnk;
533         }
534     }
535
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));
538 }
539 FCIMPLEND
540
541 #include <optdefault.h>
542
543
544 NOINLINE static FC_BOOL_RET ShouldCallWinRTInterfaceHelper(RCW *pRCW, MethodTable *pItfMT)
545 {
546     FC_INNER_PROLOG(StubHelpers::ShouldCallWinRTInterface);
547
548     bool result = false;
549     
550     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
551
552     // call the GC-triggering version
553     result = pRCW->SupportsWinRTInteropInterface(pItfMT);
554
555     HELPER_METHOD_FRAME_END();
556     FC_INNER_EPILOG();
557
558     FC_RETURN_BOOL(result);
559 }
560
561 FCIMPL2(FC_BOOL_RET, StubHelpers::ShouldCallWinRTInterface, Object *pSrcUNSAFE, MethodDesc *pMD)
562 {
563     FCALL_CONTRACT;
564
565     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
566
567     ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
568     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
569     if (pRCW == NULL)
570     {
571         // Pretend that we are not redirected WinRT type
572         // We'll throw InvalidComObjectException later in GetComIPFromRCW
573         return false;
574     }
575
576     TypeHandle::CastResult result = pRCW->SupportsWinRTInteropInterfaceNoGC(pComInfo->m_pInterfaceMT);
577     switch (result)
578     {
579         case TypeHandle::CanCast:    FC_RETURN_BOOL(true);
580         case TypeHandle::CannotCast: FC_RETURN_BOOL(false);
581     }
582
583     FC_INNER_RETURN(FC_BOOL_RET, ShouldCallWinRTInterfaceHelper(pRCW, pComInfo->m_pInterfaceMT));
584 }
585 FCIMPLEND
586
587 NOINLINE static DelegateObject *GetTargetForAmbiguousVariantCallHelper(RCW *pRCW, MethodTable *pMT, BOOL fIsEnumerable, CLR_BOOL *pfUseString)
588 {
589     FC_INNER_PROLOG(StubHelpers::GetTargetForAmbiguousVariantCall);
590
591     DelegateObject *pRetVal = NULL;
592     
593     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
594
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);
598
599     WinRTInterfaceRedirector::WinRTLegalStructureBaseType baseType = WinRTInterfaceRedirector::GetStructureBaseType(pMT->GetInstantiation());
600
601     BOOL fUseString = FALSE;
602     BOOL fUseT = FALSE;
603     pRetVal = (DelegateObject *)OBJECTREFToObject(pRCW->GetTargetForAmbiguousVariantCall(fIsEnumerable, baseType, &fUseString, &fUseT));
604
605     *pfUseString = !!fUseString;
606
607     HELPER_METHOD_FRAME_END();
608     FC_INNER_EPILOG();
609
610     return pRetVal;
611 }
612
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)
617 {
618     FCALL_CONTRACT;
619
620     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
621
622     RCW *pRCW = pSrc->PassiveGetSyncBlock()->GetInteropInfoNoCreate()->GetRawRCW();
623     if (pRCW == NULL)
624     {
625         // ignore this - the call we'll attempt to make later will throw the right exception 
626         *pfUseString = false;
627         return NULL;
628     }
629
630     BOOL fIsEnumerable = pMT->HasSameTypeDefAs(MscorlibBinder::GetExistingClass(CLASS__IENUMERABLEGENERIC));
631     _ASSERTE(fIsEnumerable || pMT->HasSameTypeDefAs(MscorlibBinder::GetExistingClass(CLASS__IREADONLYLISTGENERIC)));
632
633     WinRTInterfaceRedirector::WinRTLegalStructureBaseType baseType = WinRTInterfaceRedirector::GetStructureBaseType(pMT->GetInstantiation());
634
635     BOOL fUseString = FALSE;
636     BOOL fUseT = FALSE;
637     DelegateObject *pRetVal = (DelegateObject *)OBJECTREFToObject(pRCW->GetTargetForAmbiguousVariantCall(fIsEnumerable, baseType, &fUseString, &fUseT));
638
639     if (pRetVal != NULL || fUseT || fUseString)
640     {
641         *pfUseString = !!fUseString;
642         return pRetVal;
643     }
644
645     // we haven't seen QI for the interface yet, trigger it now
646     FC_INNER_RETURN(DelegateObject*, GetTargetForAmbiguousVariantCallHelper(pRCW, pMT, fIsEnumerable, pfUseString));
647 }
648 FCIMPLEND
649
650 FCIMPL2(void, StubHelpers::ObjectMarshaler__ConvertToNative, Object* pSrcUNSAFE, VARIANT* pDest)
651 {
652     FCALL_CONTRACT;
653
654     OBJECTREF pSrc = ObjectToOBJECTREF(pSrcUNSAFE);
655
656     HELPER_METHOD_FRAME_BEGIN_1(pSrc);
657     if (pDest->vt & VT_BYREF)
658     {
659         OleVariant::MarshalOleRefVariantForObject(&pSrc, pDest);
660     }
661     else
662     {
663         OleVariant::MarshalOleVariantForObject(&pSrc, pDest);
664     }
665     HELPER_METHOD_FRAME_END();
666 }
667 FCIMPLEND
668
669 FCIMPL1(Object*, StubHelpers::ObjectMarshaler__ConvertToManaged, VARIANT* pSrc)
670 {
671     FCALL_CONTRACT;
672
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();
679
680     return OBJECTREFToObject(retVal);
681 }
682 FCIMPLEND
683
684 FCIMPL1(void, StubHelpers::ObjectMarshaler__ClearNative, VARIANT* pSrc)
685 {
686     FCALL_CONTRACT;
687
688     HELPER_METHOD_FRAME_BEGIN_0();
689     SafeVariantClear(pSrc);
690     HELPER_METHOD_FRAME_END();
691 }
692 FCIMPLEND
693
694 #include <optsmallperfcritical.h>
695 FCIMPL4(IUnknown*, StubHelpers::InterfaceMarshaler__ConvertToNative, Object* pObjUNSAFE, MethodTable* pItfMT, MethodTable* pClsMT, DWORD dwFlags)
696 {
697     FCALL_CONTRACT;
698
699     if (NULL == pObjUNSAFE)
700     {
701         return NULL;
702     }
703
704     IUnknown *pIntf = NULL;
705     OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
706
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);
709
710     pIntf = MarshalObjectToInterface(&pObj, pItfMT, pClsMT, dwFlags);
711
712     // No exception will be thrown here (including thread abort as it is delayed in IL stubs)
713     HELPER_METHOD_FRAME_END();
714
715     return pIntf;
716 }
717 FCIMPLEND
718
719 FCIMPL4(Object*, StubHelpers::InterfaceMarshaler__ConvertToManaged, IUnknown **ppUnk, MethodTable *pItfMT, MethodTable *pClsMT, DWORD dwFlags)
720 {
721     FCALL_CONTRACT;
722
723     if (NULL == *ppUnk)
724     {
725         return NULL;
726     }
727     
728     OBJECTREF pObj = NULL;
729     HELPER_METHOD_FRAME_BEGIN_RET_1(pObj);
730
731     UnmarshalObjectFromInterface(&pObj, ppUnk, pItfMT, pClsMT, dwFlags);
732
733     HELPER_METHOD_FRAME_END();
734
735     return OBJECTREFToObject(pObj);  
736 }
737 FCIMPLEND
738
739 void QCALLTYPE StubHelpers::InterfaceMarshaler__ClearNative(IUnknown * pUnk)
740 {
741     QCALL_CONTRACT;
742
743     BEGIN_QCALL_SO_TOLERANT;
744
745     ULONG cbRef = SafeReleasePreemp(pUnk);
746     LogInteropRelease(pUnk, cbRef, "InterfaceMarshalerBase::ClearNative: In/Out release");
747
748     END_QCALL_SO_TOLERANT;
749 }
750 #include <optdefault.h>
751
752
753
754
755 FCIMPL1(StringObject*, StubHelpers::UriMarshaler__GetRawUriFromNative, ABI::Windows::Foundation::IUriRuntimeClass* pIUriRC)
756 {
757     FCALL_CONTRACT;
758
759     if (NULL == pIUriRC)
760     {
761         return NULL;
762     }
763
764     STRINGREF strRef = NULL;
765     UINT32 cchRawUri = 0;
766     LPCWSTR pwszRawUri = NULL;
767
768     HELPER_METHOD_FRAME_BEGIN_RET_1(strRef);
769
770     WinRtString hsRawUriName;
771
772     {
773         GCX_PREEMP();
774
775         // Get the RawUri string from the WinRT URI object
776         IfFailThrow(pIUriRC->get_RawUri(hsRawUriName.Address()));
777
778         pwszRawUri = hsRawUriName.GetRawBuffer(&cchRawUri);
779     }
780
781     strRef = StringObject::NewString(pwszRawUri, cchRawUri);
782
783     HELPER_METHOD_FRAME_END();
784
785     return STRINGREFToObject(strRef);
786 }
787 FCIMPLEND
788
789 FCIMPL2(IUnknown*, StubHelpers::UriMarshaler__CreateNativeUriInstance, WCHAR* pRawUri, UINT strLen)
790 {
791     CONTRACTL {
792         FCALL_CHECK;
793         PRECONDITION(CheckPointer(pRawUri));
794     }
795     CONTRACTL_END;
796
797     ABI::Windows::Foundation::IUriRuntimeClass* pIUriRC = NULL;
798
799     HELPER_METHOD_FRAME_BEGIN_RET_0();
800
801     GCX_PREEMP();
802     pIUriRC = CreateWinRTUri(pRawUri, strLen);
803
804     HELPER_METHOD_FRAME_END();
805
806     return pIUriRC;
807 }
808 FCIMPLEND
809
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)
813 {
814     QCALL_CONTRACT;
815
816    ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgs *pArgsRC = NULL;
817
818     BEGIN_QCALL;
819
820     EventArgsMarshalingInfo *marshalingInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
821     ABI::Windows::UI::Xaml::Interop::INotifyCollectionChangedEventArgsFactory *pFactory = marshalingInfo->GetNCCEventArgsFactory();
822
823     SafeComHolderPreemp<IInspectable> pInner;
824     HRESULT hr;
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,
829         newIndex,
830         oldIndex,
831         NULL,
832         &pInner,
833         &pArgsRC);
834     IfFailThrow(hr);
835
836     END_QCALL;
837
838     return pArgsRC;
839 }
840
841 ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgs* QCALLTYPE 
842         StubHelpers::EventArgsMarshaler__CreateNativePCEventArgsInstance(HSTRING name)
843 {
844     QCALL_CONTRACT;
845
846     ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgs *pArgsRC = NULL;
847
848     BEGIN_QCALL;
849
850     EventArgsMarshalingInfo *marshalingInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
851     ABI::Windows::UI::Xaml::Data::IPropertyChangedEventArgsFactory *pFactory = marshalingInfo->GetPCEventArgsFactory();
852
853     SafeComHolderPreemp<IInspectable> pInner;
854     HRESULT hr;
855     hr = pFactory->CreateInstance(
856         name,
857         NULL,
858         &pInner,
859         &pArgsRC);
860     IfFailThrow(hr);
861
862     END_QCALL;
863
864     return pArgsRC;
865 }
866
867 // A helper to convert an IP to object using special flags.
868 FCIMPL1(Object *, StubHelpers::InterfaceMarshaler__ConvertToManagedWithoutUnboxing, IUnknown *pNative)
869 {
870     FCALL_CONTRACT;
871
872     OBJECTREF oref = NULL;
873
874     HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
875
876     //
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
883     //
884     GetObjectRefFromComIP(
885         &oref,
886         pNative,                                        // pUnk
887         g_pBaseCOMObject,                               // Use __ComObject
888         NULL,                                           // pItfMT
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
894         );
895         
896     HELPER_METHOD_FRAME_END();
897
898     return OBJECTREFToObject(oref);
899 }
900 FCIMPLEND
901
902 FCIMPL2(StringObject *, StubHelpers::WinRTTypeNameConverter__ConvertToWinRTTypeName, 
903     ReflectClassBaseObject *pTypeUNSAFE, CLR_BOOL *pbIsWinRTPrimitive)
904 {
905     CONTRACTL
906     {
907         FCALL_CHECK;
908         PRECONDITION(CheckPointer(pTypeUNSAFE));
909         PRECONDITION(CheckPointer(pbIsWinRTPrimitive));
910     }
911     CONTRACTL_END;
912
913     REFLECTCLASSBASEREF refClass = (REFLECTCLASSBASEREF) pTypeUNSAFE;
914     STRINGREF refString= NULL;
915     HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, refString);
916
917     SString strWinRTTypeName;    
918     bool bIsPrimitive;
919     if (WinRTTypeNameConverter::AppendWinRTTypeNameForManagedType(
920         refClass->GetType(),    // thManagedType
921         strWinRTTypeName,       // strWinRTTypeName to append
922         FALSE,                  // for type conversion, not for GetRuntimeClassName
923         &bIsPrimitive
924         ))
925     {
926         *pbIsWinRTPrimitive = bIsPrimitive;
927         refString = AllocateString(strWinRTTypeName);
928     }
929     else
930     {
931         *pbIsWinRTPrimitive = FALSE;
932         refString = NULL;
933     }
934
935     HELPER_METHOD_FRAME_END();
936
937     return STRINGREFToObject(refString);
938 }
939 FCIMPLEND
940
941 FCIMPL2(ReflectClassBaseObject *, StubHelpers::WinRTTypeNameConverter__GetTypeFromWinRTTypeName, StringObject *pWinRTTypeNameUNSAFE, CLR_BOOL *pbIsPrimitive)
942 {
943     CONTRACTL
944     {
945         FCALL_CHECK;
946         PRECONDITION(CheckPointer(pWinRTTypeNameUNSAFE));
947     }
948     CONTRACTL_END;
949
950     OBJECTREF refClass = NULL;
951     STRINGREF refString = ObjectToSTRINGREF(pWinRTTypeNameUNSAFE);
952     HELPER_METHOD_FRAME_BEGIN_RET_2(refClass, refString);
953
954     bool isPrimitive;
955     TypeHandle th = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(refString->GetBuffer(), &isPrimitive);
956     *pbIsPrimitive = isPrimitive;
957     
958     refClass = th.GetManagedClassObject();
959     
960     HELPER_METHOD_FRAME_END();
961
962     return (ReflectClassBaseObject *)OBJECTREFToObject(refClass);    
963 }
964 FCIMPLEND
965
966 FCIMPL1(MethodDesc*, StubHelpers::GetDelegateInvokeMethod, DelegateObject *pThisUNSAFE)
967 {
968     FCALL_CONTRACT;
969
970     MethodDesc *pMD = NULL;
971     
972     OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
973     HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
974
975     MethodTable *pDelMT = pThis->GetMethodTable();
976
977     pMD = COMDelegate::FindDelegateInvokeMethod(pDelMT);
978     if (pMD->IsSharedByGenericInstantiations())
979     {
980         // we need the exact MethodDesc
981         pMD = InstantiatedMethodDesc::FindOrCreateExactClassMethod(pDelMT, pMD);
982     }
983
984     HELPER_METHOD_FRAME_END();
985
986     _ASSERTE(pMD);
987     return pMD;
988 }
989 FCIMPLEND
990
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)
994 {
995     FCALL_CONTRACT;
996
997     IInspectable *pInsp = NULL;
998
999     OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
1000     HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
1001
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();
1005
1006     // make sure that we talk to the right CCW
1007     ComCallWrapperTemplate *pTemplate = ComCallWrapperTemplate::GetTemplate(TypeHandle(pClassMT));
1008     CCWHolder pWrap = ComCallWrapper::InlineGetWrapper(&pThis, pTemplate);
1009
1010     MethodTable *pDefaultItf = pClassMT->GetDefaultWinRTInterface();
1011     const IID &riid = (pDefaultItf == NULL ? IID_IInspectable : IID_NULL);
1012     
1013     pInsp = static_cast<IInspectable *>(ComCallWrapper::GetComIPFromCCW(pWrap, riid, pDefaultItf, 
1014         GetComIPFromCCW::CheckVisibility));
1015
1016     HELPER_METHOD_FRAME_END();
1017
1018     return pInsp;
1019 }
1020 FCIMPLEND
1021
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)
1025 {
1026     FCALL_CONTRACT;
1027
1028     IInspectable *pInsp = NULL;
1029
1030     OBJECTREF pThis = ObjectToOBJECTREF(pThisUNSAFE);
1031
1032     if (pThis->GetTrueMethodTable() != pCtorMD->GetMethodTable())
1033     {
1034         // this is a composition scenario
1035         HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
1036
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));
1040
1041         HELPER_METHOD_FRAME_END();
1042     }
1043
1044     return pInsp;
1045 }
1046 FCIMPLEND
1047
1048 #ifdef MDA_SUPPORTED
1049 FCIMPL2(ExceptionObject*, StubHelpers::TriggerExceptionSwallowedMDA, ExceptionObject* pExceptionUNSAFE, PCODE pManagedTarget)
1050 {
1051     FCALL_CONTRACT;
1052     OBJECTREF pException = ObjectToOBJECTREF(pExceptionUNSAFE);
1053     HELPER_METHOD_FRAME_BEGIN_RET_1(pException);
1054
1055     // COM-to-CLR stubs use the target method entry point as their stub context
1056     MethodDesc * pMD = Entry2MethodDesc(pManagedTarget, NULL);
1057
1058     MDA_TRIGGER_ASSISTANT(ExceptionSwallowedOnCallFromCom, ReportViolation(pMD, &pException));
1059
1060     HELPER_METHOD_FRAME_END();
1061     return (ExceptionObject*)OBJECTREFToObject(pException);
1062 }
1063 FCIMPLEND
1064 #endif // MDA_SUPPORTED
1065
1066 #endif // FEATURE_COMINTEROP
1067
1068 FCIMPL0(void, StubHelpers::SetLastError)
1069 {
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();
1072
1073     FCALL_CONTRACT;
1074
1075     GetThread()->m_dwLastError = lastError;
1076 }
1077 FCIMPLEND
1078
1079 FCIMPL0(void, StubHelpers::ClearLastError)
1080 {
1081     FCALL_CONTRACT;
1082
1083     ::SetLastError(0);
1084 }
1085 FCIMPLEND
1086
1087 FCIMPL1(FC_BOOL_RET, StubHelpers::IsQCall, NDirectMethodDesc* pNMD)
1088 {
1089     FCALL_CONTRACT;
1090     FC_RETURN_BOOL(pNMD->IsQCall());
1091 }
1092 FCIMPLEND
1093
1094 NOINLINE static void InitDeclaringTypeHelper(MethodTable *pMT)
1095 {
1096     FC_INNER_PROLOG(StubHelpers::InitDeclaringType);
1097
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();
1101
1102     FC_INNER_EPILOG();
1103 }
1104
1105 // Triggers cctor of pNMD's declarer, similar to code:JIT_InitClass.
1106 #include <optsmallperfcritical.h>
1107 FCIMPL1(void, StubHelpers::InitDeclaringType, NDirectMethodDesc* pNMD)
1108 {
1109     FCALL_CONTRACT;
1110
1111     MethodTable *pMT = pNMD->GetMethodTable();
1112     _ASSERTE(!pMT->IsClassPreInited());
1113
1114     if (pMT->GetDomainLocalModule()->IsClassInitialized(pMT))
1115         return;
1116
1117     FC_INNER_RETURN_VOID(InitDeclaringTypeHelper(pMT));
1118 }
1119 FCIMPLEND
1120 #include <optdefault.h>
1121
1122 FCIMPL1(void*, StubHelpers::GetNDirectTarget, NDirectMethodDesc* pNMD)
1123 {
1124     FCALL_CONTRACT;
1125
1126     FCUnique(0xa2);
1127     return pNMD->GetNDirectTarget();
1128 }
1129 FCIMPLEND
1130
1131 FCIMPL2(void*, StubHelpers::GetDelegateTarget, DelegateObject *pThisUNSAFE, UINT_PTR *ppStubArg)
1132 {
1133     PCODE pEntryPoint = NULL;
1134
1135 #ifdef _DEBUG
1136     BEGIN_PRESERVE_LAST_ERROR;
1137 #endif
1138
1139     CONTRACTL
1140     {
1141         FCALL_CHECK;
1142         PRECONDITION(CheckPointer(pThisUNSAFE));
1143     }
1144     CONTRACTL_END;
1145
1146     DELEGATEREF orefThis = (DELEGATEREF)ObjectToOBJECTREF(pThisUNSAFE);
1147
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)
1152     {
1153         InteropSyncBlockInfo *pInteropInfo = pSyncBlock->GetInteropInfoNoCreate();
1154         if (pInteropInfo != NULL)
1155         {
1156             // we return entry point to a stub that wraps the real target
1157             Stub *pInterceptStub = pInteropInfo->GetInterceptStub();
1158             if (pInterceptStub != NULL)
1159             {
1160                 pEntryPoint = pInterceptStub->GetEntryPoint();
1161             }
1162         }
1163     }
1164 #endif // _TARGET_X86_
1165
1166 #if defined(_WIN64)
1167     UINT_PTR target = (UINT_PTR)orefThis->GetMethodPtrAux();
1168
1169     // The lowest bit is used to distinguish between MD and target on 64-bit.
1170     target = (target << 1) | 1;
1171
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;
1175
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_
1179
1180     if (pEntryPoint == NULL)
1181     {
1182         pEntryPoint = orefThis->GetMethodPtrAux();
1183     }
1184
1185 #ifdef _DEBUG
1186     END_PRESERVE_LAST_ERROR;
1187 #endif
1188
1189     return (PVOID)pEntryPoint;
1190 }
1191 FCIMPLEND
1192
1193
1194
1195 FCIMPL2(void, StubHelpers::ThrowInteropParamException, UINT resID, UINT paramIdx)
1196 {
1197     FCALL_CONTRACT;
1198
1199     HELPER_METHOD_FRAME_BEGIN_0();
1200     ::ThrowInteropParamException(resID, paramIdx);
1201     HELPER_METHOD_FRAME_END();
1202 }
1203 FCIMPLEND
1204
1205 #ifdef FEATURE_COMINTEROP
1206 FCIMPL1(void, StubHelpers::StubRegisterRCW, Object *unsafe_pThis)
1207 {
1208     FCALL_CONTRACT;
1209
1210     OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1211     HELPER_METHOD_FRAME_BEGIN_1(oref);
1212
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);
1217 #endif // _DEBUG
1218
1219     // RegisterRCW may throw OOM in which case we need to decrement the refcount on the RCW
1220     class RCWDecrementUseCountHolder
1221     {
1222     public:
1223         RCW *m_pRCW;
1224
1225         RCWDecrementUseCountHolder(RCW *pRCW)
1226         {
1227             LIMITED_METHOD_CONTRACT;
1228             m_pRCW = pRCW;
1229         }
1230
1231         ~RCWDecrementUseCountHolder()
1232         {
1233             WRAPPER_NO_CONTRACT;
1234             if (m_pRCW != NULL)
1235             {
1236                 m_pRCW->DecrementUseCount();
1237             }
1238         }
1239     };
1240
1241     RCWDecrementUseCountHolder holder(oref->GetSyncBlock()->GetInteropInfoNoCreate()->GetRCWAndIncrementUseCount());
1242     if (holder.m_pRCW == NULL)
1243     {
1244         COMPlusThrow(kInvalidComObjectException, IDS_EE_COM_OBJECT_NO_LONGER_HAS_WRAPPER);
1245     }
1246
1247     GET_THREAD()->RegisterRCW(holder.m_pRCW);
1248
1249     // if we made it here, suppress the DecrementUseCount call
1250     holder.m_pRCW = NULL;
1251
1252     HELPER_METHOD_FRAME_END();
1253 }
1254 FCIMPLEND
1255
1256 FCIMPL1(void, StubHelpers::StubUnregisterRCW, Object *unsafe_pThis)
1257 {
1258     FCALL_CONTRACT;
1259
1260     OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1261     HELPER_METHOD_FRAME_BEGIN_1(oref);
1262
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);
1267 #endif // _DEBUG
1268
1269     RCW *pRCW = GET_THREAD()->UnregisterRCW(INDEBUG(oref->GetSyncBlock()));
1270
1271     if (pRCW != NULL)
1272     {
1273         // Thread::RegisterRCW incremented the use count, decrement it now
1274         pRCW->DecrementUseCount();
1275     }
1276
1277     HELPER_METHOD_FRAME_END();
1278 }
1279 FCIMPLEND
1280
1281 class COMInterfaceMarshalerCallback : public ICOMInterfaceMarshalerCallback
1282 {
1283 public :
1284     COMInterfaceMarshalerCallback(Thread *pThread, LPVOID pCtxCookie)
1285     {
1286         CONTRACTL
1287         {
1288             NOTHROW;
1289             GC_TRIGGERS;
1290             MODE_ANY;
1291         }
1292         CONTRACTL_END;
1293
1294         _ASSERTE(pThread != NULL);
1295         _ASSERTE(pCtxCookie != NULL);
1296         
1297         m_bIsFreeThreaded = false;
1298         m_pThread = pThread;
1299         m_pCtxCookie = pCtxCookie;
1300
1301         m_bIsDCOMProxy = false;
1302     }
1303
1304     virtual void OnRCWCreated(RCW *pRCW)
1305     {
1306         LIMITED_METHOD_CONTRACT;
1307
1308         _ASSERTE(pRCW != NULL);
1309         
1310         if (pRCW->IsFreeThreaded())
1311             m_bIsFreeThreaded = true;
1312
1313         if (pRCW->IsDCOMProxy())
1314             m_bIsDCOMProxy = true;
1315     }
1316
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)
1321     {
1322         LIMITED_METHOD_CONTRACT;
1323         
1324         _ASSERTE(pRCW->SupportsIInspectable());
1325
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)
1329         {
1330             return true;
1331         }
1332         else
1333         {
1334             //
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 
1337             // the following:
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 
1341             // context yet.
1342             //
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
1346             //
1347             return false;
1348         }
1349     }
1350     
1351     virtual void OnRCWCacheHit(RCW *pRCW)
1352     {
1353         LIMITED_METHOD_CONTRACT;    
1354
1355         if (pRCW->IsFreeThreaded())
1356             m_bIsFreeThreaded = true;        
1357
1358         if (pRCW->IsDCOMProxy())
1359             m_bIsDCOMProxy = true;
1360     }
1361
1362     bool IsFreeThreaded()
1363     {
1364         LIMITED_METHOD_CONTRACT;
1365
1366         return m_bIsFreeThreaded;
1367     }
1368     
1369     bool IsDCOMProxy()
1370     {
1371         LIMITED_METHOD_CONTRACT;
1372
1373         return m_bIsDCOMProxy;
1374     }
1375
1376 private :
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
1381 };
1382
1383 //
1384 // Retrieve cached WinRT factory RCW or create a new one, according to the MethodDesc of the .ctor
1385 //
1386 FCIMPL1(Object*, StubHelpers::GetWinRTFactoryObject, MethodDesc *pCMD)
1387 {
1388     FCALL_CONTRACT;
1389
1390     OBJECTREF refFactory = NULL;
1391
1392     HELPER_METHOD_FRAME_BEGIN_RET_1(refFactory);
1393     
1394     MethodTable *pMTOfTypeToCreate = pCMD->GetMethodTable();
1395     AppDomain   *pDomain = GetAppDomain();
1396
1397     //
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
1402     //
1403     // Note that if cached WinRT factory is FTM, we'll get it back regardless of the supplied cookie
1404     //
1405     LPVOID lpCtxCookie = GetCurrentCtxCookie();
1406     refFactory = pDomain->LookupWinRTFactoryObject(pMTOfTypeToCreate, lpCtxCookie);
1407     if (refFactory == NULL)
1408     {   
1409         //
1410         // Didn't find a cached factory that matches the context
1411         // Time to create a new factory and wrap it in a RCW
1412         // 
1413
1414         //
1415         // Creates a callback to checks for singleton WinRT factory during RCW creation
1416         //
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)
1422         //
1423         // See code:COMInterfaceMarshalerCallback for more details
1424         //
1425         COMInterfaceMarshalerCallback callback(GET_THREAD(), lpCtxCookie);
1426
1427         //
1428         // Get the activation factory instance for this WinRT type and create a RCW for it
1429         //
1430         GetNativeWinRTFactoryObject(
1431             pMTOfTypeToCreate,
1432             GET_THREAD(),
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
1436             &callback,
1437             &refFactory);
1438
1439         //
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
1443         //
1444         if (callback.IsFreeThreaded())
1445             lpCtxCookie = NULL;
1446         
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.
1453         //
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
1459         {
1460             pDomain->CacheWinRTFactoryObject(pMTOfTypeToCreate, &refFactory, lpCtxCookie);
1461         }
1462     }
1463
1464     HELPER_METHOD_FRAME_END();
1465
1466     return OBJECTREFToObject(refFactory);
1467 }
1468 FCIMPLEND
1469
1470
1471 #endif
1472
1473 #ifdef MDA_SUPPORTED
1474 NOINLINE static void CheckCollectedDelegateMDAHelper(UMEntryThunk *pEntryThunk)
1475 {
1476     FC_INNER_PROLOG(StubHelpers::CheckCollectedDelegateMDA);
1477     HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
1478
1479     CallbackOnCollectedDelegateHelper(pEntryThunk);
1480
1481     HELPER_METHOD_FRAME_END();
1482     FC_INNER_EPILOG();
1483 }
1484
1485 FCIMPL1(void, StubHelpers::CheckCollectedDelegateMDA, LPVOID pEntryThunk)
1486 {
1487     CONTRACTL
1488     {
1489         FCALL_CHECK;
1490         PRECONDITION(pEntryThunk != NULL);
1491     }
1492     CONTRACTL_END;
1493
1494     if (MDA_GET_ASSISTANT(CallbackOnCollectedDelegate) == NULL)
1495         return;
1496
1497     // keep this FCall as fast as possible for the "MDA is off" case
1498     FC_INNER_RETURN_VOID(CheckCollectedDelegateMDAHelper((UMEntryThunk *)pEntryThunk));
1499 }
1500 FCIMPLEND
1501 #endif // MDA_SUPPORTED
1502
1503 #ifdef PROFILING_SUPPORTED
1504 FCIMPL3(SIZE_T, StubHelpers::ProfilerBeginTransitionCallback, SIZE_T pSecretParam, Thread* pThread, Object* unsafe_pThis)
1505 {
1506     FCALL_CONTRACT;
1507
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())
1511     {
1512         return NULL;
1513     }
1514
1515     MethodDesc* pRealMD = NULL;
1516
1517     BEGIN_PRESERVE_LAST_ERROR;
1518
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);
1523
1524     bool fReverseInterop = false;
1525
1526     if (NULL == pThread)
1527     {
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();
1533     }
1534     else
1535     if (pSecretParam == 0)
1536     {
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.
1540
1541         if (dref == NULL)
1542         {
1543             // calli pinvoke case
1544             pRealMD = NULL;
1545         }
1546         else
1547         {
1548             // unmanaged delegate case
1549             MethodTable* pMT = dref->GetMethodTable();
1550             _ASSERTE(pMT->IsDelegate());
1551
1552             EEClass * pClass = pMT->GetClass();
1553             pRealMD = ((DelegateEEClass*)pClass)->GetInvokeMethod();
1554             _ASSERTE(pRealMD);
1555         }
1556     }
1557     else
1558     {
1559         // This is either the COM interop or the pinvoke case.
1560         pRealMD = (MethodDesc*)pSecretParam;
1561     }
1562
1563     {
1564         GCX_PREEMP_THREAD_EXISTS(pThread);
1565
1566         if (fReverseInterop)
1567         {
1568             ProfilerUnmanagedToManagedTransitionMD(pRealMD, COR_PRF_TRANSITION_CALL);
1569         }
1570         else
1571         {
1572             ProfilerManagedToUnmanagedTransitionMD(pRealMD, COR_PRF_TRANSITION_CALL);
1573         }
1574     }
1575
1576     HELPER_METHOD_FRAME_END();
1577
1578     END_PRESERVE_LAST_ERROR;
1579
1580     return (SIZE_T)pRealMD;
1581 }
1582 FCIMPLEND
1583
1584 FCIMPL2(void, StubHelpers::ProfilerEndTransitionCallback, MethodDesc* pRealMD, Thread* pThread)
1585 {
1586     FCALL_CONTRACT;
1587
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())
1591     {
1592         return;
1593     }
1594
1595     BEGIN_PRESERVE_LAST_ERROR;
1596
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();
1600     {
1601         bool fReverseInterop = false;
1602
1603         if (NULL == pThread)
1604         {
1605             // if pThread is null, we are doing reverse interop
1606             pThread = GET_THREAD();
1607             fReverseInterop = true;
1608         }
1609         
1610         GCX_PREEMP_THREAD_EXISTS(pThread);
1611
1612         if (fReverseInterop)
1613         {
1614             ProfilerManagedToUnmanagedTransitionMD(pRealMD, COR_PRF_TRANSITION_RETURN);
1615         }
1616         else
1617         {
1618             ProfilerUnmanagedToManagedTransitionMD(pRealMD, COR_PRF_TRANSITION_RETURN);
1619         }
1620     }
1621     HELPER_METHOD_FRAME_END();
1622
1623     END_PRESERVE_LAST_ERROR;
1624 }
1625 FCIMPLEND
1626 #endif // PROFILING_SUPPORTED
1627
1628 FCIMPL1(Object*, StubHelpers::GetHRExceptionObject, HRESULT hr)
1629 {
1630     FCALL_CONTRACT;
1631
1632     OBJECTREF oThrowable = NULL;
1633     
1634     HELPER_METHOD_FRAME_BEGIN_RET_1(oThrowable);
1635     {
1636         // GetExceptionForHR uses equivalant logic as COMPlusThrowHR
1637         GetExceptionForHR(hr, &oThrowable);
1638     }
1639     HELPER_METHOD_FRAME_END();    
1640
1641     return OBJECTREFToObject(oThrowable);
1642 }
1643 FCIMPLEND
1644
1645 #ifdef FEATURE_COMINTEROP
1646 FCIMPL4(Object*, StubHelpers::GetCOMHRExceptionObject, HRESULT hr, MethodDesc *pMD, Object *unsafe_pThis, CLR_BOOL fForWinRT)
1647 {
1648     FCALL_CONTRACT;
1649
1650     OBJECTREF oThrowable = NULL;
1651
1652     // get 'this'
1653     OBJECTREF oref = ObjectToOBJECTREF(unsafe_pThis);
1654     
1655     HELPER_METHOD_FRAME_BEGIN_RET_2(oref, oThrowable);
1656     {
1657         IErrorInfo *pErrInfo = NULL;
1658
1659         IRestrictedErrorInfo *pResErrorInfo = NULL;
1660         BOOL bHasNonCLRLanguageErrorObject = FALSE;
1661
1662         if (fForWinRT)
1663         {
1664             SafeGetRestrictedErrorInfo(&pResErrorInfo);
1665             if (pResErrorInfo != NULL)
1666             {
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);
1672             }
1673         }
1674         if (pErrInfo == NULL && pMD != NULL)
1675         {
1676             // Retrieve the interface method table.
1677             MethodTable *pItfMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
1678
1679             // Get IUnknown pointer for this interface on this object
1680             IUnknown* pUnk = ComObject::GetComIPFromRCW(&oref, pItfMT);
1681             if (pUnk != NULL)
1682             {
1683                 // Check to see if the component supports error information for this interface.
1684                 IID ItfIID;
1685                 pItfMT->GetGuid(&ItfIID, TRUE);
1686                 pErrInfo = GetSupportedErrorInfo(pUnk, ItfIID, !fForWinRT);
1687             
1688                 DWORD cbRef = SafeRelease(pUnk);
1689                 LogInteropRelease(pUnk, cbRef, "IUnk to QI for ISupportsErrorInfo");
1690             }
1691         }
1692
1693         GetExceptionForHR(hr, pErrInfo, !fForWinRT, &oThrowable, pResErrorInfo, bHasNonCLRLanguageErrorObject);
1694     }
1695     HELPER_METHOD_FRAME_END();    
1696
1697     return OBJECTREFToObject(oThrowable);
1698 }
1699 FCIMPLEND
1700 #endif // FEATURE_COMINTEROP
1701
1702 FCIMPL3(void, StubHelpers::FmtClassUpdateNativeInternal, Object* pObjUNSAFE, BYTE* pbNative, OBJECTREF *ppCleanupWorkListOnStack)
1703 {
1704     FCALL_CONTRACT;
1705
1706     OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
1707     HELPER_METHOD_FRAME_BEGIN_1(pObj);
1708
1709     FmtClassUpdateNative(&pObj, pbNative, ppCleanupWorkListOnStack);
1710
1711     HELPER_METHOD_FRAME_END();
1712 }
1713 FCIMPLEND
1714
1715 FCIMPL2(void, StubHelpers::FmtClassUpdateCLRInternal, Object* pObjUNSAFE, BYTE* pbNative)
1716 {
1717     FCALL_CONTRACT;
1718
1719     OBJECTREF pObj = ObjectToOBJECTREF(pObjUNSAFE);
1720     HELPER_METHOD_FRAME_BEGIN_1(pObj);
1721
1722     FmtClassUpdateCLR(&pObj, pbNative);
1723
1724     HELPER_METHOD_FRAME_END();
1725 }
1726 FCIMPLEND
1727
1728 FCIMPL2(void, StubHelpers::LayoutDestroyNativeInternal, BYTE* pbNative, MethodTable* pMT)
1729 {
1730     FCALL_CONTRACT;
1731
1732     HELPER_METHOD_FRAME_BEGIN_0();
1733     LayoutDestroyNative(pbNative, pMT);
1734     HELPER_METHOD_FRAME_END();
1735 }
1736 FCIMPLEND
1737
1738 FCIMPL1(Object*, StubHelpers::AllocateInternal, EnregisteredTypeHandle pRegisteredTypeHnd)
1739 {
1740     FCALL_CONTRACT;
1741
1742     TypeHandle typeHnd = TypeHandle::FromPtr(pRegisteredTypeHnd);
1743     OBJECTREF objRet = NULL;
1744     HELPER_METHOD_FRAME_BEGIN_RET_1(objRet);
1745
1746     MethodTable* pMT = typeHnd.GetMethodTable();
1747     objRet = pMT->Allocate();
1748     
1749     HELPER_METHOD_FRAME_END();
1750
1751     return OBJECTREFToObject(objRet);
1752 }
1753 FCIMPLEND
1754
1755 FCIMPL1(void, StubHelpers::DecimalCanonicalizeInternal, DECIMAL *pDec)
1756 {
1757     FCALL_CONTRACT;
1758
1759     if (FAILED(DecimalCanonicalize(pDec)))
1760     {
1761         FCThrowResVoid(kOverflowException, W("Overflow_Currency"));
1762     }
1763 }
1764 FCIMPLEND
1765
1766 FCIMPL1(int, StubHelpers::AnsiStrlen, __in_z char* pszStr)
1767 {
1768     FCALL_CONTRACT;
1769
1770     size_t len = strlen(pszStr);
1771
1772     // the length should have been checked earlier (see StubHelpers.CheckStringLength)
1773     _ASSERTE(FitsInI4(len));
1774
1775     return (int)len;
1776 }
1777 FCIMPLEND
1778
1779 FCIMPL3(void, StubHelpers::MarshalToUnmanagedVaListInternal, va_list va, DWORD cbVaListSize, const VARARGS* pArgIterator)
1780 {
1781     FCALL_CONTRACT;
1782
1783     HELPER_METHOD_FRAME_BEGIN_0();
1784     VARARGS::MarshalToUnmanagedVaList(va, cbVaListSize, pArgIterator);
1785     HELPER_METHOD_FRAME_END();
1786 }
1787 FCIMPLEND
1788
1789 FCIMPL2(void, StubHelpers::MarshalToManagedVaListInternal, va_list va, VARARGS* pArgIterator)
1790 {
1791     FCALL_CONTRACT;
1792
1793     VARARGS::MarshalToManagedVaList(va, pArgIterator);
1794 }
1795 FCIMPLEND
1796
1797 FCIMPL3(void, StubHelpers::ValidateObject, Object *pObjUNSAFE, MethodDesc *pMD, Object *pThisUNSAFE)
1798 {
1799     FCALL_CONTRACT;
1800
1801 #ifdef VERIFY_HEAP
1802     HELPER_METHOD_FRAME_BEGIN_0();
1803
1804     StackSString errorString;
1805     EX_TRY
1806     {
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()));
1811     }
1812     EX_CATCH
1813     {
1814         FormatValidationMessage(ResolveInteropMethod(pThisUNSAFE, pMD), errorString);
1815         EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, errorString.GetUnicode());
1816     }
1817     EX_END_CATCH_UNREACHABLE;
1818
1819     HELPER_METHOD_FRAME_END();
1820 #else // VERIFY_HEAP
1821     FCUnique(0xa3);
1822     UNREACHABLE_MSG("No validation support without VERIFY_HEAP");
1823 #endif // VERIFY_HEAP
1824 }
1825 FCIMPLEND
1826
1827 FCIMPL3(void, StubHelpers::ValidateByref, void *pByref, MethodDesc *pMD, Object *pThisUNSAFE)
1828 {
1829     FCALL_CONTRACT;
1830
1831 #ifdef VERIFY_HEAP
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).
1835
1836     // Skip byref if is not pointing inside managed heap
1837     if (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pByref))
1838     {
1839         return;
1840     }
1841     ByrefValidationEntry entry;
1842     entry.pByref = pByref;
1843     entry.pMD = ResolveInteropMethod(pThisUNSAFE, pMD);
1844
1845     HELPER_METHOD_FRAME_BEGIN_0();
1846
1847     SIZE_T NumOfEntries = 0;
1848     {
1849         CrstHolder ch(&s_ByrefValidationLock);
1850
1851         if (s_ByrefValidationIndex >= s_ByrefValidationEntries.Size())
1852         {
1853             // The validation list grows as necessary, for simplicity we never shrink it.
1854             SIZE_T newSize;
1855             if (!ClrSafeInt<SIZE_T>::multiply(s_ByrefValidationIndex, 2, newSize) ||
1856                 !ClrSafeInt<SIZE_T>::addition(newSize, 1, newSize))
1857             {
1858                 ThrowHR(COR_E_OVERFLOW);
1859             }
1860
1861             s_ByrefValidationEntries.ReSizeThrows(newSize);
1862             _ASSERTE(s_ByrefValidationIndex < s_ByrefValidationEntries.Size());
1863         }
1864
1865         s_ByrefValidationEntries[s_ByrefValidationIndex] = entry;
1866         NumOfEntries = ++s_ByrefValidationIndex;
1867     }
1868
1869     if (NumOfEntries > BYREF_VALIDATION_LIST_MAX_SIZE)
1870     {
1871         // if the list is too big, trigger GC now
1872         GCHeapUtilities::GetGCHeap()->GarbageCollect(0);
1873     }
1874
1875     HELPER_METHOD_FRAME_END();
1876 #else // VERIFY_HEAP
1877     FCUnique(0xa4);
1878     UNREACHABLE_MSG("No validation support without VERIFY_HEAP");
1879 #endif // VERIFY_HEAP
1880 }
1881 FCIMPLEND
1882
1883 FCIMPL0(void*, StubHelpers::GetStubContext)
1884 {
1885     FCALL_CONTRACT;
1886
1887     FCUnique(0xa0);
1888     UNREACHABLE_MSG_RET("This is a JIT intrinsic!");
1889 }
1890 FCIMPLEND
1891
1892 FCIMPL2(void, StubHelpers::LogPinnedArgument, MethodDesc *target, Object *pinnedArg)
1893 {
1894     FCALL_CONTRACT;
1895
1896     SIZE_T managedSize = 0;
1897
1898     if (pinnedArg != NULL)
1899     {
1900         // Can pass null objects to interop, only check the size if the object is valid.
1901         managedSize = pinnedArg->GetSize();
1902     }
1903
1904     if (target != NULL)
1905     {
1906         STRESS_LOG3(LF_STUBS, LL_INFO100, "Managed object %#X with size '%#X' pinned for interop to Method [%pM]\n", pinnedArg, managedSize, target);
1907     }
1908     else
1909     {
1910         STRESS_LOG2(LF_STUBS, LL_INFO100, "Managed object %#X pinned for interop with size '%#X'", pinnedArg, managedSize);
1911     }
1912 }
1913 FCIMPLEND
1914
1915 #ifdef _WIN64
1916 FCIMPL0(void*, StubHelpers::GetStubContextAddr)
1917 {
1918     FCALL_CONTRACT;
1919
1920     FCUnique(0xa1);
1921     UNREACHABLE_MSG("This is a JIT intrinsic!");
1922 }
1923 FCIMPLEND
1924 #endif // _WIN64
1925
1926 #ifdef MDA_SUPPORTED    
1927 FCIMPL0(void, StubHelpers::TriggerGCForMDA)
1928 {
1929     FCALL_CONTRACT;
1930
1931     HELPER_METHOD_FRAME_BEGIN_0();
1932     TriggerGCForMDAInternal();    
1933     HELPER_METHOD_FRAME_END();
1934 }
1935 FCIMPLEND
1936 #endif // MDA_SUPPORTED
1937
1938 FCIMPL1(DWORD, StubHelpers::CalcVaListSize, VARARGS *varargs)
1939 {
1940     FCALL_CONTRACT;
1941
1942     return VARARGS::CalcVaListSize(varargs);
1943 }
1944 FCIMPLEND
1945
1946 #ifdef FEATURE_ARRAYSTUB_AS_IL
1947 NOINLINE static void ArrayTypeCheckSlow(Object* element, PtrArray* arr)
1948 {
1949     FC_INNER_PROLOG(StubHelpers::ArrayTypeCheck);
1950     HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
1951
1952     if (!ObjIsInstanceOf(element, arr->GetArrayElementTypeHandle()))
1953         COMPlusThrow(kArrayTypeMismatchException);
1954     
1955     HELPER_METHOD_FRAME_END();
1956
1957     FC_INNER_EPILOG();
1958 }
1959
1960 FCIMPL2(void, StubHelpers::ArrayTypeCheck, Object* element, PtrArray* arr)
1961 {
1962     FCALL_CONTRACT;
1963
1964     if (ObjIsInstanceOfNoGC(element, arr->GetArrayElementTypeHandle()) == TypeHandle::CanCast)
1965         return;
1966     
1967     FC_INNER_RETURN_VOID(ArrayTypeCheckSlow(element, arr));
1968 }
1969 FCIMPLEND
1970 #endif // FEATURE_ARRAYSTUB_AS_IL
1971
1972 #ifdef FEATURE_MULTICASTSTUB_AS_IL
1973 FCIMPL2(void, StubHelpers::MulticastDebuggerTraceHelper, Object* element, INT32 count)
1974 {
1975     FCALL_CONTRACT;
1976     FCUnique(0xa5);
1977 }
1978 FCIMPLEND
1979 #endif // FEATURE_MULTICASTSTUB_AS_IL