Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / vm / dllimport.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: DllImport.cpp
6 //
7
8 //
9 // P/Invoke support.
10 // 
11
12
13 #include "common.h"
14
15 #include "vars.hpp"
16 #include "stublink.h"
17 #include "threads.h"
18 #include "excep.h"
19 #include "dllimport.h"
20 #include "method.hpp"
21 #include "siginfo.hpp"
22 #include "security.h"
23 #include "comdelegate.h"
24 #include "ceeload.h"
25 #include "mlinfo.h"
26 #include "eeconfig.h"
27 #include "comutilnative.h"
28 #include "corhost.h"
29 #include "asmconstants.h"
30 #include "mdaassistants.h"
31 #include "customattribute.h"
32 #include "ilstubcache.h"
33 #include "typeparse.h"
34 #include "sigbuilder.h"
35 #include "sigformat.h"
36 #include "strongnameholders.h"
37 #include "ecall.h"
38
39 #include <formattype.h>
40 #include "../md/compiler/custattr.h"
41
42 #ifdef FEATURE_COMINTEROP
43 #include "runtimecallablewrapper.h"
44 #include "clrtocomcall.h"
45 #endif // FEATURE_COMINTEROP
46
47 #ifdef FEATURE_PREJIT
48 #include "compile.h"
49 #endif // FEATURE_PREJIT
50
51 #include "eventtrace.h"
52
53
54 #include "clr/fs/path.h"
55 using namespace clr::fs;
56
57 // remove when we get an updated SDK
58 #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
59 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
60
61 void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx)
62 {
63     LIMITED_METHOD_CONTRACT;
64     if (pClause->kind == ILStubEHClause::kNone)
65         return;
66
67     int idx = *pCurIdx;
68     *pCurIdx = idx + 1;
69
70     CorExceptionFlag flags;
71     switch (pClause->kind)
72     {
73     case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break;
74     case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break;
75     default:
76         UNREACHABLE_MSG("unexpected ILStubEHClause kind");
77     }
78     _ASSERTE(idx < nClauses);
79     pEHSect->Fat.Clauses[idx].Flags = flags;
80     pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset;
81     pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength;
82     pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset;
83     pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength;
84     pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken;
85 }
86
87 VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo)
88 {
89     LIMITED_METHOD_CONTRACT;
90     pEHSect->Fat.Kind       = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
91     pEHSect->Fat.DataSize   = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses);
92
93     int curIdx = 0;
94     AppendEHClause(nClauses, pEHSect, pOne, &curIdx);
95     AppendEHClause(nClauses, pEHSect, pTwo, &curIdx);
96 }
97
98 StubSigDesc::StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo /*= NULL*/)
99 {
100     CONTRACTL
101     {
102         NOTHROW;
103         GC_NOTRIGGER;
104         SUPPORTS_DAC;
105     }
106     CONTRACTL_END
107
108     m_pMD = pMD;
109     if (pSigInfo != NULL)
110     {
111         m_sig           = pSigInfo->GetSignature();
112         m_pModule       = pSigInfo->GetModule();
113     }
114     else
115     {
116         _ASSERTE(pMD != NULL);
117         m_sig           = pMD->GetSignature();
118         m_pModule       = pMD->GetModule();         // Used for token resolution.
119     }
120
121     if (pMD != NULL)
122     {
123         m_tkMethodDef = pMD->GetMemberDef();
124         SigTypeContext::InitTypeContext(pMD, &m_typeContext);
125         m_pLoaderModule = pMD->GetLoaderModule();   // Used for ILStubCache selection and MethodTable creation.
126     }
127     else
128     {
129         m_tkMethodDef = mdMethodDefNil;
130         m_pLoaderModule = m_pModule;
131     }
132
133     INDEBUG(InitDebugNames());
134 }
135
136 StubSigDesc::StubSigDesc(MethodDesc *pMD, Signature sig, Module *pModule)
137 {
138     CONTRACTL
139     {
140         NOTHROW;
141         GC_NOTRIGGER;
142         SUPPORTS_DAC;
143         PRECONDITION(!sig.IsEmpty());
144         PRECONDITION(pModule != NULL);
145     }
146     CONTRACTL_END
147
148     m_pMD           = pMD;
149     m_sig           = sig;
150     m_pModule       = pModule;
151
152     if (pMD != NULL)
153     {
154         m_tkMethodDef = pMD->GetMemberDef();
155         SigTypeContext::InitTypeContext(pMD, &m_typeContext);
156         m_pLoaderModule = pMD->GetLoaderModule();   // Used for ILStubCache selection and MethodTable creation.
157     }
158     else
159     {
160         m_tkMethodDef = mdMethodDefNil;
161         m_pLoaderModule = m_pModule;
162     }
163
164     INDEBUG(InitDebugNames());
165 }
166
167 #ifndef DACCESS_COMPILE
168
169 class StubState
170 {
171 public:
172     virtual void SetLastError(BOOL fSetLastError) = 0;
173     virtual void BeginEmit(DWORD dwStubFlags) = 0;
174     virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) = 0;
175     virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) = 0;
176     virtual void MarshalLCID(int argIdx) = 0;
177
178 #ifdef FEATURE_COMINTEROP
179     virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray) = 0;
180     virtual void MarshalFactoryReturn() = 0;
181 #endif // FEATURE_COMINTEROP
182
183     virtual void EmitInvokeTarget(MethodDesc *pStubMD) = 0;
184
185     virtual void FinishEmit(MethodDesc* pMD) = 0;
186
187     virtual ~StubState()
188     {
189         LIMITED_METHOD_CONTRACT;
190     }
191 };
192
193 class ILStubState : public StubState
194 {
195 protected:
196     
197     ILStubState(
198                 Module* pStubModule,
199                 const Signature &signature,
200                 SigTypeContext* pTypeContext,
201                 BOOL fTargetHasThis,
202                 BOOL fStubHasThis,
203                 DWORD dwStubFlags,
204                 int iLCIDParamIdx,
205                 MethodDesc* pTargetMD)
206             : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx, fTargetHasThis, fStubHasThis)
207     {
208         STANDARD_VM_CONTRACT;
209
210         m_fSetLastError = 0;
211     }
212
213 public:
214     void SetLastError(BOOL fSetLastError)
215     {
216         LIMITED_METHOD_CONTRACT;
217
218         m_fSetLastError = fSetLastError;
219     }
220
221     // We use three stub linkers to generate IL stubs.  The pre linker is the main one.  It does all the marshaling and
222     // then calls the target method.  The post return linker is only used to unmarshal the return value after we return
223     // from the target method.  The post linker handles all the unmarshaling for by ref arguments and clean-up.  It
224     // also checks if we should throw an exception etc.
225     //
226     // Currently, we have two "emittable" ILCodeLabel's.  The first one is at the beginning of the pre linker.  This
227     // label is used to emit code to declare and initialize clean-up flags.  Each argument which requires clean-up 
228     // emits one flag.  This flag is set only after the marshaling is done, and it is checked before we do any clean-up
229     // in the finally.
230     //
231     // The second "emittable" ILCodeLabel is at the beginning of the post linker.  It is used to emit code which is
232     // not safe to run in the case of an exception.  The rest of the post linker is wrapped in a finally, and it contains
233     // with the necessary clean-up which should be executed in both normal and exception cases.
234     void BeginEmit(DWORD dwStubFlags)
235     {
236         WRAPPER_NO_CONTRACT;
237         m_slIL.Begin(dwStubFlags);
238         m_dwStubFlags = dwStubFlags;
239     }
240
241     void MarshalReturn(MarshalInfo* pInfo, int argOffset)
242     {
243         CONTRACTL
244         {
245             STANDARD_VM_CHECK;
246
247             PRECONDITION(CheckPointer(pInfo));
248         }
249         CONTRACTL_END;
250
251         pInfo->GenerateReturnIL(&m_slIL, argOffset,
252                                 SF_IsForwardStub(m_dwStubFlags),
253                                 SF_IsFieldGetterStub(m_dwStubFlags),
254                                 SF_IsHRESULTSwapping(m_dwStubFlags));
255     }
256
257     void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
258     {
259         CONTRACTL
260         {
261             STANDARD_VM_CHECK;
262             PRECONDITION(CheckPointer(pInfo));
263         }
264         CONTRACTL_END;
265
266         pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags));
267     }
268
269 #ifdef FEATURE_COMINTEROP
270     // Marshal the hidden length parameter for the managed parameter in pInfo
271     virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray)
272     {
273         STANDARD_VM_CONTRACT;
274
275         pInfo->MarshalHiddenLengthArgument(&m_slIL, SF_IsForwardStub(m_dwStubFlags), isForReturnArray);
276
277         if (SF_IsReverseStub(m_dwStubFlags))
278         {
279             // Hidden length arguments appear explicitly in the native signature
280             // however, they are not in the managed signature.
281             m_slIL.AdjustTargetStackDeltaForExtraParam();
282         }
283     }
284
285     void MarshalFactoryReturn()
286     {
287         CONTRACTL
288         {
289             STANDARD_VM_CHECK;
290             PRECONDITION(SF_IsCOMStub(m_dwStubFlags));
291             PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
292         }
293         CONTRACTL_END;
294
295         ILCodeStream *pcsSetup     = m_slIL.GetSetupCodeStream();
296         ILCodeStream *pcsDispatch  = m_slIL.GetDispatchCodeStream();
297         ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
298         ILCodeStream *pcsCleanup   = m_slIL.GetCleanupCodeStream();
299
300         /*
301         *    SETUP
302         */
303
304         // create a local to hold the returned pUnk and initialize to 0 in case the factory fails
305         // and we try to release it during cleanup
306         LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
307         DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
308         pcsSetup->EmitLoadNullPtr();
309         pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
310
311         DWORD dwInnerIInspectableLocalNum = -1;
312         DWORD dwOuterIInspectableLocalNum = -1;
313         if (SF_IsWinRTCompositionStub(m_dwStubFlags))
314         {
315             // Create locals to store the outer and inner IInspectable values and initialize to null
316             // Note that we do this in the setup stream so that we're guaranteed to have a null-initialized
317             // value in the cleanup stream
318             LocalDesc locDescOuterIInspectable(ELEMENT_TYPE_I);
319             dwOuterIInspectableLocalNum = pcsSetup->NewLocal(locDescOuterIInspectable);
320             pcsSetup->EmitLoadNullPtr();
321             pcsSetup->EmitSTLOC(dwOuterIInspectableLocalNum);
322             LocalDesc locDescInnerIInspectable(ELEMENT_TYPE_I);
323             dwInnerIInspectableLocalNum = pcsSetup->NewLocal(locDescInnerIInspectable);
324             pcsSetup->EmitLoadNullPtr();
325             pcsSetup->EmitSTLOC(dwInnerIInspectableLocalNum);
326         }
327
328         /*
329         *   DISPATCH
330         */
331
332         // For composition factories, add the two extra params
333         if (SF_IsWinRTCompositionStub(m_dwStubFlags))
334         {
335             // Get outer IInspectable. The helper will return NULL if this is the "top-level" constructor,
336             // and the appropriate outer pointer otherwise.
337             pcsDispatch->EmitLoadThis();
338             m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
339             pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_OUTER_INSPECTABLE, 2, 1);
340             pcsDispatch->EmitSTLOC(dwOuterIInspectableLocalNum);
341
342             // load the outer IInspectable (3rd last argument)
343             pcsDispatch->SetStubTargetArgType(ELEMENT_TYPE_I, false);
344             pcsDispatch->EmitLDLOC(dwOuterIInspectableLocalNum);
345
346             // pass pointer to where inner non-delegating IInspectable should be stored (2nd last argument)
347             LocalDesc locDescInnerPtr(ELEMENT_TYPE_I);
348             locDescInnerPtr.MakeByRef();
349             pcsDispatch->SetStubTargetArgType(&locDescInnerPtr, false);
350             pcsDispatch->EmitLDLOCA(dwInnerIInspectableLocalNum);
351         }
352
353         // pass pointer to the local to the factory method (last argument)
354         locDescFactoryRetVal.MakeByRef();
355         pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
356         pcsDispatch->EmitLDLOCA(dwFactoryRetValLocalNum);
357
358         /*
359         *   UNMARSHAL
360         */
361
362         // Mark that the factory method has succesfully returned and so cleanup will be necessary after
363         // this point.
364         m_slIL.EmitSetArgMarshalIndex(pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
365
366         // associate the 'this' RCW with one of the returned interface pointers 
367         pcsUnmarshal->EmitLoadThis();
368
369         // now we need to find the right interface pointer to load
370         if (dwInnerIInspectableLocalNum != -1)
371         {
372             // We may have a composition scenario
373             ILCodeLabel* pNonCompositionLabel = pcsUnmarshal->NewCodeLabel();
374             ILCodeLabel* pLoadedLabel = pcsUnmarshal->NewCodeLabel();
375
376             // Did we pass an outer IInspectable?
377             pcsUnmarshal->EmitLDLOC(dwOuterIInspectableLocalNum);
378             pcsUnmarshal->EmitBRFALSE(pNonCompositionLabel);
379
380             // yes, this is a composition scenario 
381             {
382                 // ignore the delegating interface pointer (will be released in cleanup below) - we can 
383                 // re-create it by QI'ing the non-delegating one.
384                 // Note that using this could be useful in the future (avoids an extra QueryInterface call)
385                 // Just load the non-delegating interface pointer
386                 pcsUnmarshal->EmitLDLOCA(dwInnerIInspectableLocalNum);
387                 pcsUnmarshal->EmitBR(pLoadedLabel);
388             }
389             // else, no this is a non-composition scenario
390             {
391                 pcsUnmarshal->EmitLabel(pNonCompositionLabel);
392
393                 // ignore the non-delegating interface pointer (which should be null, but will regardless get
394                 // cleaned up below in the event the factory doesn't follow the pattern properly).
395                 // Just load the regular delegating interface pointer
396                 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
397             }
398
399             pcsUnmarshal->EmitLabel(pLoadedLabel);
400         }
401         else
402         {
403             // Definitely can't be a composition scenario - use the only pointer we have
404             pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
405         }
406
407         pcsUnmarshal->EmitCALL(METHOD__MARSHAL__INITIALIZE_WRAPPER_FOR_WINRT, 2, 0);
408
409         /*
410         *   CLEANUP 
411         */
412
413         // release the returned interface pointer in the finally block
414         m_slIL.SetCleanupNeeded();
415
416         ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
417
418         m_slIL.EmitCheckForArgCleanup(pcsCleanup,
419                                       NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
420                                       NDirectStubLinker::BranchIfNotMarshaled,
421                                       pSkipCleanupLabel);
422
423         EmitInterfaceClearNative(pcsCleanup, dwFactoryRetValLocalNum);
424
425         // Note that it's a no-op to pass NULL to Clear_Native, so we call it even though we don't 
426         // know if we assigned to the inner/outer IInspectable
427         if (dwInnerIInspectableLocalNum != -1)
428         {
429             EmitInterfaceClearNative(pcsCleanup, dwInnerIInspectableLocalNum);
430         }
431         if (dwOuterIInspectableLocalNum != -1)
432         {
433             EmitInterfaceClearNative(pcsCleanup, dwOuterIInspectableLocalNum);
434         }
435
436         pcsCleanup->EmitLabel(pSkipCleanupLabel);
437     }
438
439     static void EmitInterfaceClearNative(ILCodeStream* pcsEmit, DWORD dwLocalNum)
440     {
441         STANDARD_VM_CONTRACT;
442
443         ILCodeLabel *pSkipClearNativeLabel = pcsEmit->NewCodeLabel();
444         pcsEmit->EmitLDLOC(dwLocalNum);
445         pcsEmit->EmitBRFALSE(pSkipClearNativeLabel);
446         pcsEmit->EmitLDLOC(dwLocalNum);
447         pcsEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
448         pcsEmit->EmitLabel(pSkipClearNativeLabel);
449     }
450
451 #endif // FEATURE_COMINTEROP
452
453     void MarshalLCID(int argIdx)
454     {
455         STANDARD_VM_CONTRACT;
456
457         ILCodeStream* pcs = m_slIL.GetDispatchCodeStream();
458         
459 #ifdef FEATURE_USE_LCID
460         if (SF_IsReverseStub(m_dwStubFlags))
461         {
462             if ((m_slIL.GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_HASTHIS) == IMAGE_CEE_CS_CALLCONV_HASTHIS)
463             {
464                 // the arg number will be incremented by LDARG if we are in an instance method
465                 _ASSERTE(argIdx > 0);
466                 argIdx--;
467             }
468
469             LocalDesc locDescThread(MscorlibBinder::GetClass(CLASS__THREAD));
470             DWORD dwThreadLocalNum = pcs->NewLocal(locDescThread);
471
472             // call Thread.get_CurrentThread()
473             pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
474             pcs->EmitDUP();
475             pcs->EmitSTLOC(dwThreadLocalNum);
476
477             // call current_thread.get_CurrentCulture()
478             pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
479
480             // save the current culture
481             LocalDesc locDescCulture(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
482             DWORD dwCultureLocalNum = pcs->NewLocal(locDescCulture);
483
484             pcs->EmitSTLOC(dwCultureLocalNum);
485
486             // set a new one based on the LCID passed from unmanaged
487             pcs->EmitLDLOC(dwThreadLocalNum);
488             pcs->EmitLDARG(argIdx);
489
490             // call CultureInfo..ctor(lcid)
491             // call current_thread.set_CurrentCulture(culture)
492             pcs->EmitNEWOBJ(METHOD__CULTURE_INFO__INT_CTOR, 1);
493             pcs->EmitCALL(METHOD__THREAD__SET_CULTURE, 2, 0);
494
495             // and restore the current one after the call
496             m_slIL.SetCleanupNeeded();
497             ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
498
499             // call current_thread.set_CurrentCulture(original_culture)
500             pcsCleanup->EmitLDLOC(dwThreadLocalNum);
501             pcsCleanup->EmitLDLOC(dwCultureLocalNum);
502             pcsCleanup->EmitCALL(METHOD__THREAD__SET_CULTURE, 1, 1);
503
504         }
505         else
506         {
507             if (SF_IsCOMStub(m_dwStubFlags))
508             {
509                 // We used to get LCID from current thread's culture here. The code
510                 // was replaced by the hardcoded LCID_ENGLISH_US as requested by VSTO.
511                 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
512             }
513             else
514             {
515                 // call Thread.get_CurrentThread()
516                 // call current_thread.get_CurrentCulture()
517                 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
518                 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
519
520                 //call CultureInfo.get_LCID(this)
521                 pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1);
522             }
523         }
524 #else // FEATURE_USE_LCID
525         if (SF_IsForwardStub(m_dwStubFlags))
526         {
527             pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
528         }
529 #endif // FEATURE_USE_LCID
530
531         // add the extra arg to the unmanaged signature
532         LocalDesc locDescNative(ELEMENT_TYPE_I4);
533         pcs->SetStubTargetArgType(&locDescNative, false);
534
535         if (SF_IsReverseStub(m_dwStubFlags))
536         {
537             // reverse the effect of SetStubTargetArgType on the stack delta
538             // (the LCID argument is explicitly passed from unmanaged but does not
539             // show up in the managed signature in any way)
540             m_slIL.AdjustTargetStackDeltaForExtraParam();
541         }
542
543     }
544
545     void SwapStubSignatures(MethodDesc* pStubMD)
546     {
547         STANDARD_VM_CONTRACT;
548         
549         //
550         // Since the stub handles native-to-managed transitions, we have to swap the
551         // stub-state-calculated stub target sig with the stub sig itself.  This is 
552         // because the stub target sig represents the native signature and the stub 
553         // sig represents the managed signature.  
554         //
555         // The first step is to convert the managed signature to a module-independent
556         // signature and then pass it off to SetStubTargetMethodSig.  Note that the
557         // ILStubResolver will copy the sig, so we only need to make a temporary copy
558         // of it.
559         //
560         SigBuilder sigBuilder;
561
562         {
563             SigPointer sigPtr(pStubMD->GetSig());
564             sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder);
565         }
566         
567         //
568         // The second step is to reset the sig on the stub MethodDesc to be the 
569         // stub-state-calculated stub target sig.
570         //
571         {
572             //
573             // make a domain-local copy of the sig so that this state can outlive the
574             // compile time state.
575             //
576             DWORD           cbNewSig;
577             PCCOR_SIGNATURE pNewSig;
578
579             cbNewSig = GetStubTargetMethodSigLength();
580             pNewSig  = (PCCOR_SIGNATURE)(void *)pStubMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig));
581
582             memcpyNoGCRefs((void *)pNewSig, GetStubTargetMethodSig(), cbNewSig);
583             
584             pStubMD->AsDynamicMethodDesc()->SetStoredMethodSig(pNewSig, cbNewSig);
585
586             SigPointer  sigPtr(pNewSig, cbNewSig);
587             ULONG       callConvInfo;
588             IfFailThrow(sigPtr.GetCallingConvInfo(&callConvInfo));
589             
590             if (callConvInfo & CORINFO_CALLCONV_HASTHIS)
591             {
592                 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags &= ~mdStatic;
593                 pStubMD->ClearStatic();
594             }
595             else
596             {
597                 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags |= mdStatic;
598                 pStubMD->SetStatic();
599             }
600
601 #ifndef _TARGET_X86_
602             // we store the real managed argument stack size in the stub MethodDesc on non-X86
603             UINT stackSize = pStubMD->SizeOfArgStack();
604
605             if (!FitsInU2(stackSize))
606                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
607
608             pStubMD->AsDynamicMethodDesc()->SetNativeStackArgSize(static_cast<WORD>(stackSize));
609 #endif // _TARGET_X86_
610         }
611
612         DWORD   cbTempModuleIndependentSigLength;
613         BYTE *  pTempModuleIndependentSig = (BYTE *)sigBuilder.GetSignature(&cbTempModuleIndependentSigLength);
614
615         // Finish it
616         SetStubTargetMethodSig(pTempModuleIndependentSig, 
617                                cbTempModuleIndependentSigLength);
618     }
619
620     void EmitInvokeTarget(MethodDesc *pStubMD)
621     {
622         STANDARD_VM_CONTRACT;
623
624         m_slIL.DoNDirect(m_slIL.GetDispatchCodeStream(), m_dwStubFlags, pStubMD);
625     }
626
627 #ifdef FEATURE_COMINTEROP
628     void EmitExceptionHandler(LocalDesc* pNativeReturnType, LocalDesc* pManagedReturnType, 
629         ILCodeLabel** ppTryEndAndCatchBeginLabel, ILCodeLabel ** ppCatchEndAndReturnLabel)
630     {
631         STANDARD_VM_CONTRACT;
632
633         ILCodeStream* pcsExceptionHandler = m_slIL.NewCodeStream(ILStubLinker::kExceptionHandler);
634         *ppTryEndAndCatchBeginLabel  = pcsExceptionHandler->NewCodeLabel();
635         *ppCatchEndAndReturnLabel = pcsExceptionHandler->NewCodeLabel();
636
637         pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
638         pcsExceptionHandler->EmitLabel(*ppTryEndAndCatchBeginLabel);
639
640         BYTE nativeReturnElemType = pNativeReturnType->ElementType[0];      // return type of the stub
641         BYTE managedReturnElemType = pManagedReturnType->ElementType[0];    // return type of the mananged target
642
643         bool returnTheHRESULT = SF_IsHRESULTSwapping(m_dwStubFlags) || 
644                                     (managedReturnElemType == ELEMENT_TYPE_I4) ||
645                                     (managedReturnElemType == ELEMENT_TYPE_U4);
646
647 #ifdef MDA_SUPPORTED
648         if (!returnTheHRESULT)
649         {
650             MdaExceptionSwallowedOnCallFromCom* mda = MDA_GET_ASSISTANT(ExceptionSwallowedOnCallFromCom);
651             if (mda)
652             {
653                 // on the stack: exception object, but the stub linker doesn't know it
654                 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
655                 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__TRIGGER_EXCEPTION_SWALLOWED_MDA, 
656                     1,  // WARNING: This method takes 2 input args, the exception object and the stub context.
657                         //          But the ILStubLinker has no knowledge that the exception object is on the 
658                         //          stack (because it is unaware that we've just entered a catch block), so we 
659                         //          lie and claim that we only take one input argument.
660                     1); // returns the exception object back
661             }
662         }
663 #endif // MDA_SUPPORTED
664
665         DWORD retvalLocalNum = m_slIL.GetReturnValueLocalNum();
666         BinderMethodID getHRForException;
667         if (SF_IsWinRTStub(m_dwStubFlags))
668         {
669             getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION_WINRT;
670         }
671         else
672         {
673             getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION;
674         }
675
676         pcsExceptionHandler->EmitCALL(getHRForException, 
677             0,  // WARNING: This method takes 1 input arg, the exception object.  But the ILStubLinker
678                 //          has no knowledge that the exception object is on the stack (because it is
679                 //          unaware that we've just entered a catch block), so we lie and claim that we
680                 //          don't take any input arguments.
681             1);
682         
683         switch (nativeReturnElemType)
684         {
685         default:
686             UNREACHABLE_MSG("Unexpected element type found on native return type.");
687             break;
688         case ELEMENT_TYPE_VOID:
689             _ASSERTE(retvalLocalNum == (DWORD)-1);
690             pcsExceptionHandler->EmitPOP();
691             break;
692         case ELEMENT_TYPE_I4:
693         case ELEMENT_TYPE_U4:
694             {
695                 if (!returnTheHRESULT)
696                 {
697                     pcsExceptionHandler->EmitPOP();
698                     pcsExceptionHandler->EmitLDC(0);
699                     pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
700                 }
701                 _ASSERTE(retvalLocalNum != (DWORD)-1);
702                 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
703             }
704             break;
705         case ELEMENT_TYPE_R4:
706             pcsExceptionHandler->EmitPOP();
707             pcsExceptionHandler->EmitLDC_R4(CLR_NAN_32);
708             _ASSERTE(retvalLocalNum != (DWORD)-1);
709             pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
710             break;
711         case ELEMENT_TYPE_R8:
712             pcsExceptionHandler->EmitPOP();
713             pcsExceptionHandler->EmitLDC_R8(CLR_NAN_64);
714             _ASSERTE(retvalLocalNum != (DWORD)-1);
715             pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
716             break;
717         case ELEMENT_TYPE_INTERNAL:
718             {
719                 TypeHandle returnTypeHnd = pNativeReturnType->InternalToken;
720                 CONSISTENCY_CHECK(returnTypeHnd.IsValueType()); 
721                 _ASSERTE(retvalLocalNum != (DWORD)-1);
722                 pcsExceptionHandler->EmitLDLOCA(retvalLocalNum);
723                 pcsExceptionHandler->EmitINITOBJ(m_slIL.GetDispatchCodeStream()->GetToken(returnTypeHnd));
724             }
725             break;
726         case ELEMENT_TYPE_BOOLEAN:
727         case ELEMENT_TYPE_CHAR:
728         case ELEMENT_TYPE_I1:
729         case ELEMENT_TYPE_U1:
730         case ELEMENT_TYPE_I2:
731         case ELEMENT_TYPE_U2:
732         case ELEMENT_TYPE_I8:
733         case ELEMENT_TYPE_U8:
734         case ELEMENT_TYPE_I:
735         case ELEMENT_TYPE_U:
736             pcsExceptionHandler->EmitPOP();
737             pcsExceptionHandler->EmitLDC(0);
738             pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
739             _ASSERTE(retvalLocalNum != (DWORD)-1);
740             pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
741             break;
742         }
743
744         pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
745         pcsExceptionHandler->EmitLabel(*ppCatchEndAndReturnLabel);
746         if (nativeReturnElemType != ELEMENT_TYPE_VOID)
747         {
748             _ASSERTE(retvalLocalNum != (DWORD)-1);
749             pcsExceptionHandler->EmitLDLOC(retvalLocalNum);
750         }
751         pcsExceptionHandler->EmitRET();
752     }
753 #endif // FEATURE_COMINTEROP
754
755     void FinishEmit(MethodDesc* pStubMD)
756     {
757         STANDARD_VM_CONTRACT;
758
759         ILCodeStream* pcsMarshal = m_slIL.GetMarshalCodeStream();
760         ILCodeStream* pcsUnmarshal = m_slIL.GetUnmarshalCodeStream();
761         ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
762        
763         if (SF_IsHRESULTSwapping(m_dwStubFlags) && m_slIL.StubHasVoidReturnType())
764         {
765             // if the return type is void, but we're doing HRESULT swapping, we
766             // need to set the return type here.  Otherwise, the return value
767             // marshaler will do this.
768             pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4);    // HRESULT
769
770             if (SF_IsReverseStub(m_dwStubFlags))
771             {
772                 // reverse interop needs to seed the return value if the
773                 // managed function returns void but we're doing hresult
774                 // swapping.
775                 pcsUnmarshal->EmitLDC(S_OK);
776             }
777         }
778
779         LocalDesc nativeReturnType;
780         LocalDesc managedReturnType;
781         bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(m_dwStubFlags) 
782                                     && !SF_IsFieldGetterStub(m_dwStubFlags) 
783                                     && !SF_IsFieldSetterStub(m_dwStubFlags);
784
785 #ifdef FEATURE_COMINTEROP
786         if (hasTryCatchForHRESULT)
787         {
788             m_slIL.GetStubTargetReturnType(&nativeReturnType);
789             m_slIL.GetStubReturnType(&managedReturnType);
790         }
791 #endif // FEATURE_COMINTEROP
792
793         if (SF_IsHRESULTSwapping(m_dwStubFlags) && SF_IsReverseStub(m_dwStubFlags))
794         {
795             m_slIL.AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
796         }
797
798         if (SF_IsForwardCOMStub(m_dwStubFlags))
799         {
800             // Compensate for the 'this' parameter.
801             m_slIL.AdjustTargetStackDeltaForExtraParam();
802         }
803
804 #if defined(_TARGET_X86_)
805         // unmanaged CALLI will get an extra arg with the real target address if host hook is enabled
806         if (SF_IsCALLIStub(m_dwStubFlags) && NDirect::IsHostHookEnabled())
807         {
808             pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I, false);
809         }
810 #endif // _TARGET_X86_
811
812         // Don't touch target signatures from this point on otherwise it messes up the
813         // cache in ILStubState::GetStubTargetMethodSig.
814
815 #ifdef _DEBUG
816         {
817             // The native and local signatures should not have any tokens.
818             // All token references should have been converted to
819             // ELEMENT_TYPE_INTERNAL.
820             //
821             // Note that MetaSig::GetReturnType and NextArg will normalize
822             // ELEMENT_TYPE_INTERNAL back to CLASS or VALUETYPE.
823             //
824             // <TODO> need to recursively check ELEMENT_TYPE_FNPTR signatures </TODO>
825
826             SigTypeContext typeContext;  // this is an empty type context: COM calls are guaranteed to not be generics.
827             MetaSig nsig(
828                 GetStubTargetMethodSig(), 
829                 GetStubTargetMethodSigLength(), 
830                 MscorlibBinder::GetModule(), 
831                 &typeContext);
832
833             CorElementType type;
834             IfFailThrow(nsig.GetReturnProps().PeekElemType(&type));
835             CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
836
837             while (ELEMENT_TYPE_END != (type = nsig.NextArg()))
838             {
839                 IfFailThrow(nsig.GetArgProps().PeekElemType(&type));
840                 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
841             }
842         }
843 #endif // _DEBUG
844
845 #ifdef FEATURE_COMINTEROP
846         if (SF_IsForwardCOMStub(m_dwStubFlags))
847         {
848 #if defined(MDA_SUPPORTED)
849             // We won't use this NGEN'ed stub if RaceOnRCWCleanup is enabled at run-time
850             if (!SF_IsNGENedStub(m_dwStubFlags))
851             {
852                 // This code may change the type of the frame we use, so it has to be run before the code below where we
853                 // retrieve the stack arg size based on the frame type.
854                 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
855                 if (mda)
856                 {
857                     // Here we have to register the RCW of the "this" object to the RCWStack and schedule the clean-up for it.
858                     // Emit a call to StubHelpers::StubRegisterRCW() and StubHelpers::StubUnregisterRCW() to do this.
859                     m_slIL.EmitLoadRCWThis(pcsMarshal, m_dwStubFlags);
860                     pcsMarshal->EmitCALL(METHOD__STUBHELPERS__STUB_REGISTER_RCW, 1, 0);
861
862                     // We use an extra local to track whether we need to unregister the RCW on cleanup
863                     ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
864                     DWORD dwRCWRegisteredLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
865                     pcsSetup->EmitLDC(0);
866                     pcsSetup->EmitSTLOC(dwRCWRegisteredLocalNum);
867
868                     pcsMarshal->EmitLDC(1);
869                     pcsMarshal->EmitSTLOC(dwRCWRegisteredLocalNum);
870
871                     ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
872                     ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
873                     
874                     m_slIL.SetCleanupNeeded();
875                     pcsCleanup->EmitLDLOC(dwRCWRegisteredLocalNum);
876                     pcsCleanup->EmitBRFALSE(pSkipCleanupLabel);
877
878                     m_slIL.EmitLoadRCWThis(pcsCleanup, m_dwStubFlags);
879                     pcsCleanup->EmitCALL(METHOD__STUBHELPERS__STUB_UNREGISTER_RCW, 1, 0);
880
881                     pcsCleanup->EmitLabel(pSkipCleanupLabel);
882                 }
883             }
884 #endif // MDA_SUPPORTED
885         }
886 #endif // FEATURE_COMINTEROP
887
888         // <NOTE>
889         // The profiler helpers below must be called immediately before and after the call to the target.
890         // The debugger trace call helpers are invoked from StubRareDisableWorker
891         // </NOTE>
892
893 #if defined(PROFILING_SUPPORTED)
894         DWORD dwMethodDescLocalNum = -1;
895
896         // Notify the profiler of call out of the runtime
897         if (!SF_IsReverseCOMStub(m_dwStubFlags) && (CORProfilerTrackTransitions() || SF_IsNGENedStubForProfiling(m_dwStubFlags)))
898         {
899             dwMethodDescLocalNum = m_slIL.EmitProfilerBeginTransitionCallback(pcsDispatch, m_dwStubFlags);
900             _ASSERTE(dwMethodDescLocalNum != -1);
901         }
902 #endif // PROFILING_SUPPORTED
903
904 #ifdef MDA_SUPPORTED
905         if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
906             MDA_GET_ASSISTANT(GcManagedToUnmanaged))
907         {
908             m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
909         }
910 #endif // MDA_SUPPORTED
911
912         // For CoreClr, clear the last error before calling the target that returns last error.
913         // There isn't always a way to know the function have failed without checking last error,
914         // in particular on Unix.
915         if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
916         {
917             pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CLEAR_LAST_ERROR, 0, 0);
918         }
919
920         // Invoke the target (calli, call method, call delegate, get/set field, etc.)
921         EmitInvokeTarget(pStubMD);
922
923         // Saving last error must be the first thing we do after returning from the target
924         if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
925         {
926             pcsDispatch->EmitCALL(METHOD__STUBHELPERS__SET_LAST_ERROR, 0, 0);
927         }
928
929 #if defined(_TARGET_X86_)
930         if (SF_IsForwardDelegateStub(m_dwStubFlags))
931         {
932             // the delegate may have an intercept stub attached to its sync block so we should
933             // prevent it from being garbage collected when the call is in progress
934             pcsDispatch->EmitLoadThis();
935             pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
936         }
937 #endif // defined(_TARGET_X86_)
938
939 #ifdef MDA_SUPPORTED
940         if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
941             MDA_GET_ASSISTANT(GcUnmanagedToManaged))
942         {
943             m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
944         }
945 #endif // MDA_SUPPORTED
946
947 #ifdef VERIFY_HEAP
948         if (SF_IsForwardStub(m_dwStubFlags) && g_pConfig->InteropValidatePinnedObjects())
949         {
950             // call StubHelpers.ValidateObject/StubHelpers.ValidateByref on pinned locals
951             m_slIL.EmitObjectValidation(pcsDispatch, m_dwStubFlags);
952         }
953 #endif // VERIFY_HEAP
954
955 #if defined(PROFILING_SUPPORTED)
956         // Notify the profiler of return back into the runtime
957         if (dwMethodDescLocalNum != -1)
958         {
959             m_slIL.EmitProfilerEndTransitionCallback(pcsDispatch, m_dwStubFlags, dwMethodDescLocalNum);
960         }
961 #endif // PROFILING_SUPPORTED
962
963 #ifdef FEATURE_COMINTEROP
964         if (SF_IsForwardCOMStub(m_dwStubFlags))
965         {
966             // Make sure that the RCW stays alive for the duration of the call. Note that if we do HRESULT
967             // swapping, we'll pass 'this' to GetCOMHRExceptionObject after returning from the target so
968             // GC.KeepAlive is not necessary.
969             if (!SF_IsHRESULTSwapping(m_dwStubFlags))
970             {
971                 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
972                 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
973             }
974         }
975 #endif // FEATURE_COMINTEROP
976
977         if (SF_IsHRESULTSwapping(m_dwStubFlags))
978         {
979             if (SF_IsForwardStub(m_dwStubFlags))
980             {
981                 ILCodeLabel* pSkipThrowLabel = pcsDispatch->NewCodeLabel();
982
983                 pcsDispatch->EmitDUP();
984                 pcsDispatch->EmitLDC(0);
985                 pcsDispatch->EmitBGE(pSkipThrowLabel);
986
987 #ifdef FEATURE_COMINTEROP
988                 if (SF_IsCOMStub(m_dwStubFlags))
989                 {
990                     m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
991                     m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
992
993                     if (SF_IsWinRTStub(m_dwStubFlags))
994                     {
995                         pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT_WINRT, 3, 1);
996                     }
997                     else
998                     {
999                         pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT, 3, 1);
1000                     }
1001                 }
1002                 else
1003 #endif // FEATURE_COMINTEROP
1004                 {
1005                     pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_HR_EXCEPTION_OBJECT, 1, 1);
1006                 }
1007                 
1008                 pcsDispatch->EmitTHROW();
1009                 pcsDispatch->EmitLDC(0);   // keep the IL stack balanced across the branch and the fall-through
1010                 pcsDispatch->EmitLabel(pSkipThrowLabel);
1011                 pcsDispatch->EmitPOP();
1012             }
1013         }
1014
1015         m_slIL.End(m_dwStubFlags);
1016         if (!hasTryCatchForHRESULT) // we will 'leave' the try scope and then 'ret' from outside
1017         {
1018             pcsUnmarshal->EmitRET();
1019         }
1020
1021         CORJIT_FLAGS jitFlags(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB);
1022                 
1023         if (m_slIL.HasInteropParamExceptionInfo())
1024         {
1025             // This code will not use the secret parameter, so we do not
1026             // tell the JIT to bother with it.
1027             m_slIL.ClearCode();
1028             m_slIL.GenerateInteropParamException(pcsMarshal);
1029         }
1030         else if (SF_IsFieldGetterStub(m_dwStubFlags) || SF_IsFieldSetterStub(m_dwStubFlags))
1031         {
1032             // Field access stubs are not shared and do not use the secret parameter.
1033         }
1034 #ifndef _WIN64
1035         else if (SF_IsForwardDelegateStub(m_dwStubFlags) ||
1036                 (SF_IsForwardCOMStub(m_dwStubFlags) && SF_IsWinRTDelegateStub(m_dwStubFlags)))
1037         {
1038             // Forward delegate stubs get all the context they need in 'this' so they
1039             // don't use the secret parameter. Except for AMD64 where we use the secret
1040             // argument to pass the real target to the stub-for-host.
1041         }
1042 #endif // !_WIN64
1043         else
1044         {
1045             // All other IL stubs will need to use the secret parameter.
1046             jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PUBLISH_SECRET_PARAM);
1047         }
1048
1049         if (SF_IsReverseStub(m_dwStubFlags))
1050         {
1051             SwapStubSignatures(pStubMD);
1052         }
1053
1054         ILCodeLabel* pTryEndAndCatchBeginLabel = NULL; // try ends at the same place the catch begins
1055         ILCodeLabel* pCatchEndAndReturnLabel = NULL;   // catch ends at the same place we resume afterwards
1056 #ifdef FEATURE_COMINTEROP
1057         if (hasTryCatchForHRESULT)
1058         {
1059             EmitExceptionHandler(&nativeReturnType, &managedReturnType, &pTryEndAndCatchBeginLabel, &pCatchEndAndReturnLabel);
1060         }
1061 #endif // FEATURE_COMINTEROP
1062
1063         UINT   maxStack;
1064         size_t cbCode;
1065         DWORD  cbSig;
1066         BYTE * pbBuffer;
1067         BYTE * pbLocalSig;
1068
1069         cbCode = m_slIL.Link(&maxStack);
1070         cbSig = m_slIL.GetLocalSigSize();
1071
1072         ILStubResolver *       pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
1073         COR_ILMETHOD_DECODER * pILHeader = pResolver->AllocGeneratedIL(cbCode, cbSig, maxStack);
1074         pbBuffer   = (BYTE *)pILHeader->Code;
1075         pbLocalSig = (BYTE *)pILHeader->LocalVarSig;
1076         _ASSERTE(cbSig == pILHeader->cbLocalVarSig);
1077
1078         ILStubEHClause cleanupTryFinally = { 0 };
1079         ILStubEHClause convertToHRTryCatch = { 0 };
1080         m_slIL.GetCleanupFinallyOffsets(&cleanupTryFinally);
1081
1082 #ifdef FEATURE_COMINTEROP
1083         if (hasTryCatchForHRESULT)
1084         {
1085             convertToHRTryCatch.kind = ILStubEHClause::kTypedCatch;
1086             convertToHRTryCatch.dwTryBeginOffset = 0;
1087             convertToHRTryCatch.dwHandlerBeginOffset = ((DWORD)pTryEndAndCatchBeginLabel->GetCodeOffset());
1088             convertToHRTryCatch.cbTryLength = convertToHRTryCatch.dwHandlerBeginOffset - convertToHRTryCatch.dwTryBeginOffset;
1089             convertToHRTryCatch.cbHandlerLength = ((DWORD)pCatchEndAndReturnLabel->GetCodeOffset()) - convertToHRTryCatch.dwHandlerBeginOffset;
1090             convertToHRTryCatch.dwTypeToken = pcsDispatch->GetToken(g_pObjectClass);
1091         }
1092 #endif // FEATURE_COMINTEROP
1093
1094         int nEHClauses = 0;
1095
1096         if (convertToHRTryCatch.cbHandlerLength != 0)
1097             nEHClauses++;
1098
1099         if (cleanupTryFinally.cbHandlerLength != 0)
1100             nEHClauses++;
1101
1102         if (nEHClauses > 0)
1103         {
1104             COR_ILMETHOD_SECT_EH* pEHSect = pResolver->AllocEHSect(nEHClauses);
1105             PopulateEHSect(pEHSect, nEHClauses, &cleanupTryFinally, &convertToHRTryCatch);
1106         }
1107
1108         m_slIL.GenerateCode(pbBuffer, cbCode);
1109         m_slIL.GetLocalSig(pbLocalSig, cbSig);
1110
1111         pResolver->SetJitFlags(jitFlags);
1112
1113 #ifdef LOGGING
1114         LOG((LF_STUBS, LL_INFO1000, "---------------------------------------------------------------------\n"));
1115         LOG((LF_STUBS, LL_INFO1000, "NDirect IL stub dump: %s::%s\n", pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
1116         if (LoggingEnabled() && LoggingOn(LF_STUBS, LL_INFO1000))
1117         {
1118             CQuickBytes qbManaged;
1119             CQuickBytes qbLocal;
1120
1121             PCCOR_SIGNATURE pManagedSig;
1122             ULONG           cManagedSig;
1123
1124             IMDInternalImport* pIMDI = MscorlibBinder::GetModule()->GetMDImport();
1125
1126             pStubMD->GetSig(&pManagedSig, &cManagedSig);
1127
1128             PrettyPrintSig(pManagedSig,  cManagedSig, "*",  &qbManaged, pStubMD->GetMDImport(), NULL);
1129             PrettyPrintSig(pbLocalSig,   cbSig, NULL, &qbLocal,   pIMDI, NULL);
1130
1131             LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, qbManaged.Ptr()));
1132             LOG((LF_STUBS, LL_INFO1000, "locals sig:           %p: %s\n", pbLocalSig+1, qbLocal.Ptr()));
1133
1134             if (cleanupTryFinally.cbHandlerLength != 0)
1135             {
1136                 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x finally_begin: 0x%04x finally_end: 0x%04x \n", 
1137                     cleanupTryFinally.dwTryBeginOffset, cleanupTryFinally.dwTryBeginOffset + cleanupTryFinally.cbTryLength, 
1138                     cleanupTryFinally.dwHandlerBeginOffset, cleanupTryFinally.dwHandlerBeginOffset + cleanupTryFinally.cbHandlerLength));
1139             }
1140             if (convertToHRTryCatch.cbHandlerLength != 0)
1141             {
1142                 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x catch_begin: 0x%04x catch_end: 0x%04x type_token: 0x%08x\n", 
1143                     convertToHRTryCatch.dwTryBeginOffset, convertToHRTryCatch.dwTryBeginOffset + convertToHRTryCatch.cbTryLength, 
1144                     convertToHRTryCatch.dwHandlerBeginOffset, convertToHRTryCatch.dwHandlerBeginOffset + convertToHRTryCatch.cbHandlerLength,
1145                     convertToHRTryCatch.dwTypeToken));
1146             }
1147
1148             LogILStubFlags(LF_STUBS, LL_INFO1000, m_dwStubFlags);
1149
1150             m_slIL.LogILStub(jitFlags);
1151         }
1152         LOG((LF_STUBS, LL_INFO1000, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
1153 #endif // LOGGING
1154         
1155     }
1156
1157
1158 #ifdef LOGGING
1159     //---------------------------------------------------------------------------------------
1160     // 
1161     static inline void LogOneFlag(DWORD flags, DWORD flag, LPCSTR str, DWORD facility, DWORD level)
1162     {
1163         LIMITED_METHOD_CONTRACT;
1164         if (flags & flag)
1165         {
1166             LOG((facility, level, str));
1167         }
1168     }
1169
1170     static void LogILStubFlags(DWORD facility, DWORD level, DWORD dwStubFlags)
1171     {
1172         LIMITED_METHOD_CONTRACT;
1173         LOG((facility, level, "dwStubFlags: 0x%08x\n", dwStubFlags));
1174         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_CONVSIGASVARARG,         "   NDIRECTSTUB_FL_CONVSIGASVARARG\n", facility, level);
1175         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_BESTFIT,                 "   NDIRECTSTUB_FL_BESTFIT\n", facility, level);
1176         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR,   "   NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR\n", facility, level);
1177         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUB,              "   NDIRECTSTUB_FL_NGENEDSTUB\n", facility, level);
1178         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DELEGATE,                "   NDIRECTSTUB_FL_DELEGATE\n", facility, level);
1179         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DOHRESULTSWAPPING,       "   NDIRECTSTUB_FL_DOHRESULTSWAPPING\n", facility, level);
1180         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_REVERSE_INTEROP,         "   NDIRECTSTUB_FL_REVERSE_INTEROP\n", facility, level);
1181 #ifdef FEATURE_COMINTEROP
1182         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_COM,                     "   NDIRECTSTUB_FL_COM\n", facility, level);
1183 #endif // FEATURE_COMINTEROP
1184         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING,  "   NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING\n", facility, level);
1185         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL,    "   NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL\n", facility, level);
1186         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_HASDECLARATIVESECURITY,  "   NDIRECTSTUB_FL_HASDECLARATIVESECURITY\n", facility, level);
1187         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_UNMANAGED_CALLI,         "   NDIRECTSTUB_FL_UNMANAGED_CALLI\n", facility, level);
1188         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_TRIGGERCCTOR,            "   NDIRECTSTUB_FL_TRIGGERCCTOR\n", facility, level);
1189 #ifdef FEATURE_COMINTEROP
1190         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDGETTER,             "   NDIRECTSTUB_FL_FIELDGETTER\n", facility, level);
1191         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDSETTER,             "   NDIRECTSTUB_FL_FIELDSETTER\n", facility, level);
1192         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRT,                   "   NDIRECTSTUB_FL_WINRT\n", facility, level);
1193         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTDELEGATE,           "   NDIRECTSTUB_FL_WINRTDELEGATE\n", facility, level);
1194         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSHAREDGENERIC,      "   NDIRECTSTUB_FL_WINRTSHAREDGENERIC\n", facility, level);
1195         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCTOR,               "   NDIRECTSTUB_FL_WINRTCTOR\n", facility, level);
1196         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCOMPOSITION,        "   NDIRECTSTUB_FL_WINRTCOMPOSITION\n", facility, level);
1197         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSTATIC,             "   NDIRECTSTUB_FL_WINRTSTATIC\n", facility, level);
1198         LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTHASREDIRECTION,     "   NDIRECTSTUB_FL_WINRTHASREDIRECTION\n", facility, level);
1199 #endif // FEATURE_COMINTEROP
1200
1201         //
1202         // no need to log the internal flags, let's just assert what we expect to see...
1203         //
1204         CONSISTENCY_CHECK(!SF_IsCOMLateBoundStub(dwStubFlags));
1205         CONSISTENCY_CHECK(!SF_IsCOMEventCallStub(dwStubFlags));
1206
1207         DWORD dwKnownMask = 
1208             NDIRECTSTUB_FL_CONVSIGASVARARG          |
1209             NDIRECTSTUB_FL_BESTFIT                  |
1210             NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR    |
1211             NDIRECTSTUB_FL_NGENEDSTUB               |
1212             NDIRECTSTUB_FL_DELEGATE                 |
1213             NDIRECTSTUB_FL_DOHRESULTSWAPPING        |
1214             NDIRECTSTUB_FL_REVERSE_INTEROP          |
1215             NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING   |
1216             NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL     |
1217             NDIRECTSTUB_FL_HASDECLARATIVESECURITY   |
1218             NDIRECTSTUB_FL_UNMANAGED_CALLI          |
1219             NDIRECTSTUB_FL_TRIGGERCCTOR             |
1220 #ifdef FEATURE_COMINTEROP
1221             NDIRECTSTUB_FL_COM                      |
1222             NDIRECTSTUB_FL_COMLATEBOUND             |   // internal
1223             NDIRECTSTUB_FL_COMEVENTCALL             |   // internal
1224             NDIRECTSTUB_FL_FIELDGETTER              |
1225             NDIRECTSTUB_FL_FIELDSETTER              |
1226             NDIRECTSTUB_FL_WINRT                    |
1227             NDIRECTSTUB_FL_WINRTDELEGATE            |
1228             NDIRECTSTUB_FL_WINRTCTOR                |
1229             NDIRECTSTUB_FL_WINRTCOMPOSITION         |
1230             NDIRECTSTUB_FL_WINRTSTATIC              |
1231             NDIRECTSTUB_FL_WINRTHASREDIRECTION      |
1232 #endif // FEATURE_COMINTEROP
1233             NULL;
1234
1235         DWORD dwUnknownFlags = dwStubFlags & ~dwKnownMask;
1236         if (0 != dwUnknownFlags)
1237         {
1238             LOG((facility, level, "UNKNOWN FLAGS: 0x%08x\n", dwUnknownFlags));
1239         }
1240     }
1241 #endif // LOGGING
1242
1243     PCCOR_SIGNATURE GetStubTargetMethodSig()
1244     {
1245         CONTRACT(PCCOR_SIGNATURE)
1246         {
1247             STANDARD_VM_CHECK;
1248             POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
1249         }
1250         CONTRACT_END;
1251
1252         BYTE *pb;
1253
1254         if (!m_qbNativeFnSigBuffer.Size())
1255         {
1256             DWORD cb = m_slIL.GetStubTargetMethodSigSize();
1257             pb = (BYTE *)m_qbNativeFnSigBuffer.AllocThrows(cb);
1258
1259             m_slIL.GetStubTargetMethodSig(pb, cb);
1260         }
1261         else
1262         {
1263             pb = (BYTE*)m_qbNativeFnSigBuffer.Ptr();
1264         }
1265
1266         RETURN pb;
1267     }
1268
1269     DWORD 
1270     GetStubTargetMethodSigLength()
1271     {
1272         WRAPPER_NO_CONTRACT;
1273
1274         return m_slIL.GetStubTargetMethodSigSize();
1275     }
1276
1277     void SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1278     {
1279         WRAPPER_NO_CONTRACT;
1280
1281         m_slIL.SetStubTargetMethodSig(pSig, cSig);
1282         m_qbNativeFnSigBuffer.Shrink(0);
1283     }
1284     
1285     TokenLookupMap* GetTokenLookupMap() { WRAPPER_NO_CONTRACT; return m_slIL.GetTokenLookupMap(); }
1286
1287 protected:
1288     CQuickBytes         m_qbNativeFnSigBuffer;
1289     NDirectStubLinker   m_slIL;
1290     BOOL                m_fSetLastError;
1291     DWORD               m_dwStubFlags;
1292 };
1293
1294
1295 class PInvoke_ILStubState : public ILStubState
1296 {
1297 public:
1298         
1299     PInvoke_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1300                         CorPinvokeMap unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
1301         : ILStubState(
1302                 pStubModule,
1303                 signature,
1304                 pTypeContext,
1305                 TargetHasThis(dwStubFlags),
1306                 StubHasThis(dwStubFlags),
1307                 dwStubFlags,
1308                 iLCIDParamIdx,
1309                 pTargetMD)
1310     {
1311         STANDARD_VM_CONTRACT;
1312
1313         if (SF_IsForwardStub(dwStubFlags))
1314         {
1315             m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
1316         }
1317     }
1318
1319 private:
1320     static BOOL TargetHasThis(DWORD dwStubFlags)
1321     {
1322         //
1323         // in reverse pinvoke on delegate, the managed target will 
1324         // have a 'this' pointer, but the unmanaged signature does 
1325         // not.
1326         //
1327         return SF_IsReverseDelegateStub(dwStubFlags);
1328     }
1329
1330     static BOOL StubHasThis(DWORD dwStubFlags)
1331     {
1332         //
1333         // in forward pinvoke on a delegate, the stub will have a
1334         // 'this' pointer, but the unmanaged target will not.
1335         //
1336         return SF_IsForwardDelegateStub(dwStubFlags);
1337     }
1338 };
1339
1340 #ifdef FEATURE_COMINTEROP
1341 class CLRToCOM_ILStubState : public ILStubState
1342 {
1343 public:
1344
1345     CLRToCOM_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1346                          int iLCIDParamIdx, MethodDesc* pTargetMD)
1347         : ILStubState(
1348                 pStubModule,
1349                 signature,
1350                 pTypeContext,
1351                 TRUE,
1352                 !SF_IsWinRTStaticStub(dwStubFlags), // fStubHasThis
1353                 dwStubFlags,
1354                 iLCIDParamIdx,
1355                 pTargetMD)
1356     {
1357         STANDARD_VM_CONTRACT;
1358
1359         if (SF_IsForwardStub(dwStubFlags))
1360         {
1361             m_slIL.SetCallingConvention(pmCallConvStdcall, SF_IsVarArgStub(dwStubFlags));
1362         }
1363     }
1364
1365     void BeginEmit(DWORD dwStubFlags)  // CLR to COM IL
1366     {
1367         STANDARD_VM_CONTRACT;
1368
1369         ILStubState::BeginEmit(dwStubFlags);
1370
1371         ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1372
1373         // add the 'this' COM IP parameter to the target CALLI
1374         m_slIL.GetMarshalCodeStream()->SetStubTargetArgType(ELEMENT_TYPE_I, false);
1375
1376         // convert 'this' to COM IP and the target method entry point
1377         m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
1378
1379 #ifdef _WIN64
1380         if (SF_IsWinRTDelegateStub(m_dwStubFlags))
1381         {
1382             // write the stub context (EEImplMethodDesc representing the Invoke)
1383             // into the secret arg so it shows up in the InlinedCallFrame and can
1384             // be used by stub for host
1385
1386             pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
1387             m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1388             pcsDispatch->EmitSTIND_I();
1389             pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1390         }
1391         else
1392 #endif // _WIN64
1393         {
1394             m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1395         }
1396
1397         pcsDispatch->EmitLDLOCA(m_slIL.GetTargetEntryPointLocalNum());
1398
1399         BinderMethodID getCOMIPMethod;
1400         bool fDoPostCallIPCleanup = true;
1401
1402         if (!SF_IsNGENedStub(dwStubFlags) && NDirect::IsHostHookEnabled())
1403         {
1404             // always use the non-optimized helper if we are hosted
1405             getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1406         }
1407         else if (SF_IsWinRTStub(dwStubFlags))
1408         {
1409             // WinRT uses optimized helpers
1410             if (SF_IsWinRTSharedGenericStub(dwStubFlags))
1411                 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_SHARED_GENERIC;
1412             else if (SF_IsWinRTDelegateStub(dwStubFlags))
1413                 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_DELEGATE;
1414             else
1415                 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT;
1416
1417             // GetCOMIPFromRCW_WinRT, GetCOMIPFromRCW_WinRTSharedGeneric, and GetCOMIPFromRCW_WinRTDelegate
1418             // always cache the COM interface pointer so no post-call cleanup is needed
1419             fDoPostCallIPCleanup = false;
1420         }
1421         else
1422         {
1423             // classic COM interop uses the non-optimized helper
1424             getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1425         }
1426
1427         DWORD dwIPRequiresCleanupLocalNum = (DWORD)-1;
1428         if (fDoPostCallIPCleanup)
1429         {
1430             dwIPRequiresCleanupLocalNum = pcsDispatch->NewLocal(ELEMENT_TYPE_BOOLEAN);
1431             pcsDispatch->EmitLDLOCA(dwIPRequiresCleanupLocalNum);
1432
1433             // StubHelpers.GetCOMIPFromRCW(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget, out bool pfNeedsRelease)
1434             pcsDispatch->EmitCALL(getCOMIPMethod, 4, 1);
1435         }
1436         else
1437         {
1438             // StubHelpers.GetCOMIPFromRCW_WinRT*(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget)
1439             pcsDispatch->EmitCALL(getCOMIPMethod, 3, 1);
1440         }
1441
1442
1443         // save it because we'll need it to compute the CALLI target and release it
1444         pcsDispatch->EmitDUP();
1445         pcsDispatch->EmitSTLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1446
1447         if (fDoPostCallIPCleanup)
1448         {
1449             // make sure it's Release()'ed after the call
1450             m_slIL.SetCleanupNeeded();
1451             ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
1452
1453             ILCodeLabel *pSkipThisCleanup = pcsCleanup->NewCodeLabel();
1454
1455             // and if it requires cleanup (i.e. it's not taken from the RCW cache)
1456             pcsCleanup->EmitLDLOC(dwIPRequiresCleanupLocalNum);
1457             pcsCleanup->EmitBRFALSE(pSkipThisCleanup);
1458
1459             pcsCleanup->EmitLDLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1460             pcsCleanup->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
1461             pcsCleanup->EmitLabel(pSkipThisCleanup);
1462         }
1463     }
1464 };
1465
1466 class COMToCLR_ILStubState : public ILStubState
1467 {
1468 public:
1469
1470     COMToCLR_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1471                          int iLCIDParamIdx, MethodDesc* pTargetMD)
1472         : ILStubState(
1473                 pStubModule,
1474                 signature,
1475                 pTypeContext,
1476                 TRUE,
1477                 TRUE,
1478                 dwStubFlags,
1479                 iLCIDParamIdx,
1480                 pTargetMD)
1481     {
1482         STANDARD_VM_CONTRACT;
1483     }
1484
1485     void BeginEmit(DWORD dwStubFlags)  // COM to CLR IL
1486     {
1487         STANDARD_VM_CONTRACT;
1488
1489         ILStubState::BeginEmit(dwStubFlags);
1490
1491         if (SF_IsWinRTStaticStub(dwStubFlags))
1492         {
1493             // we are not loading 'this' because the target is static
1494             m_slIL.AdjustTargetStackDeltaForExtraParam();
1495         }
1496         else
1497         {
1498             // load this
1499             m_slIL.GetDispatchCodeStream()->EmitLoadThis();
1500         }
1501     }
1502
1503     void MarshalFactoryReturn()
1504     {
1505         CONTRACTL
1506         {
1507             STANDARD_VM_CHECK;
1508             PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
1509         }
1510         CONTRACTL_END;
1511
1512         ILCodeStream *pcsSetup     = m_slIL.GetSetupCodeStream();
1513         ILCodeStream *pcsDispatch  = m_slIL.GetDispatchCodeStream();
1514         ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
1515         ILCodeStream *pcsExCleanup = m_slIL.GetExceptionCleanupCodeStream();
1516
1517         LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
1518         DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
1519         pcsSetup->EmitLoadNullPtr();
1520         pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
1521
1522         locDescFactoryRetVal.MakeByRef();
1523
1524         // expect one additional argument - pointer to a location that receives the created instance
1525         DWORD dwRetValArgNum = pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
1526         m_slIL.AdjustTargetStackDeltaForExtraParam();
1527
1528         // convert 'this' to an interface pointer corresponding to the default interface of this class
1529         pcsUnmarshal->EmitLoadThis();
1530         pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1531         pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_RETURN_VALUE, 2, 1);
1532         pcsUnmarshal->EmitSTLOC(dwFactoryRetValLocalNum);
1533
1534         // assign it to the location pointed to by the argument
1535         pcsUnmarshal->EmitLDARG(dwRetValArgNum);
1536         pcsUnmarshal->EmitLDLOC(dwFactoryRetValLocalNum);
1537         pcsUnmarshal->EmitSTIND_I();
1538
1539         // on exception, we want to release the IInspectable's and assign NULL to output locations
1540         m_slIL.SetExceptionCleanupNeeded();
1541
1542         EmitInterfaceClearNative(pcsExCleanup, dwFactoryRetValLocalNum);
1543
1544         // *retVal = NULL
1545         pcsExCleanup->EmitLDARG(dwRetValArgNum);
1546         pcsExCleanup->EmitLoadNullPtr();
1547         pcsExCleanup->EmitSTIND_I();
1548
1549     }
1550 };
1551
1552 class COMToCLRFieldAccess_ILStubState : public COMToCLR_ILStubState
1553 {
1554 public:
1555
1556     COMToCLRFieldAccess_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext,
1557                                     DWORD dwStubFlags, FieldDesc* pFD)
1558         : COMToCLR_ILStubState(
1559                 pStubModule,
1560                 signature,
1561                 pTypeContext,
1562                 dwStubFlags,
1563                 -1,
1564                 NULL)
1565     {
1566         STANDARD_VM_CONTRACT;
1567
1568         _ASSERTE(pFD != NULL);
1569         m_pFD = pFD;
1570     }
1571
1572     void EmitInvokeTarget(MethodDesc *pStubMD)
1573     {
1574         STANDARD_VM_CONTRACT;
1575
1576         ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
1577
1578         if (SF_IsFieldGetterStub(m_dwStubFlags))
1579         {
1580             pcsDispatch->EmitLDFLD(pcsDispatch->GetToken(m_pFD));
1581         }
1582         else
1583         {
1584             CONSISTENCY_CHECK(SF_IsFieldSetterStub(m_dwStubFlags));
1585             pcsDispatch->EmitSTFLD(pcsDispatch->GetToken(m_pFD));
1586         }
1587     }
1588
1589 protected:
1590     FieldDesc *m_pFD;
1591 };
1592 #endif // FEATURE_COMINTEROP
1593
1594
1595 NDirectStubLinker::NDirectStubLinker(
1596             DWORD dwStubFlags,
1597             Module* pModule,
1598             const Signature &signature,
1599             SigTypeContext *pTypeContext,
1600             MethodDesc* pTargetMD,
1601             int  iLCIDParamIdx,
1602             BOOL fTargetHasThis, 
1603             BOOL fStubHasThis)
1604      : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, fTargetHasThis, fStubHasThis, !SF_IsCOMStub(dwStubFlags)),
1605     m_pCleanupFinallyBeginLabel(NULL),
1606     m_pCleanupFinallyEndLabel(NULL),
1607     m_pSkipExceptionCleanupLabel(NULL),
1608 #ifdef FEATURE_COMINTEROP
1609     m_dwWinRTFactoryObjectLocalNum(-1),
1610 #endif // FEATURE_COMINTEROP
1611     m_fHasCleanupCode(FALSE),
1612     m_fHasExceptionCleanupCode(FALSE),
1613     m_fCleanupWorkListIsSetup(FALSE),
1614     m_dwThreadLocalNum(-1),
1615     m_dwCleanupWorkListLocalNum(-1),
1616     m_dwRetValLocalNum(-1),
1617     m_ErrorResID(-1),
1618     m_ErrorParamIdx(-1),
1619     m_iLCIDParamIdx(iLCIDParamIdx),
1620     m_dwStubFlags(dwStubFlags)
1621 {
1622     STANDARD_VM_CONTRACT;
1623
1624
1625     m_pcsSetup              = NewCodeStream(ILStubLinker::kSetup);              // do any one-time setup work
1626     m_pcsMarshal            = NewCodeStream(ILStubLinker::kMarshal);            // marshals arguments
1627     m_pcsDispatch           = NewCodeStream(ILStubLinker::kDispatch);           // sets up arguments and makes call
1628     m_pcsRetUnmarshal       = NewCodeStream(ILStubLinker::kReturnUnmarshal);    // unmarshals return value
1629     m_pcsUnmarshal          = NewCodeStream(ILStubLinker::kUnmarshal);          // unmarshals arguments
1630     m_pcsExceptionCleanup   = NewCodeStream(ILStubLinker::kExceptionCleanup);   // MAY NOT THROW: goes in a finally and does exception-only cleanup
1631     m_pcsCleanup            = NewCodeStream(ILStubLinker::kCleanup);            // MAY NOT THROW: goes in a finally and does unconditional cleanup
1632
1633     //
1634     // Add locals
1635     m_dwArgMarshalIndexLocalNum = NewLocal(ELEMENT_TYPE_I4);
1636     m_pcsMarshal->EmitLDC(0);
1637     m_pcsMarshal->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1638     
1639 #ifdef FEATURE_COMINTEROP
1640     //
1641     // Forward COM interop needs a local to hold target interface pointer
1642     //
1643     if (SF_IsForwardCOMStub(m_dwStubFlags))
1644     {
1645         m_dwTargetEntryPointLocalNum = NewLocal(ELEMENT_TYPE_I);
1646         m_dwTargetInterfacePointerLocalNum = NewLocal(ELEMENT_TYPE_I);
1647         m_pcsSetup->EmitLoadNullPtr();
1648         m_pcsSetup->EmitSTLOC(m_dwTargetInterfacePointerLocalNum);
1649     }
1650 #endif // FEATURE_COMINTEROP
1651 }
1652
1653 void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg)
1654 {
1655     LIMITED_METHOD_CONTRACT;
1656     ULONG uNativeCallingConv = 0;
1657
1658 #if !defined(_TARGET_X86_)
1659     if (fIsVarArg)
1660     {
1661         // The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM:
1662         // any float values must be duplicated in the corresponding general-purpose registers.
1663         uNativeCallingConv = CORINFO_CALLCONV_NATIVEVARARG;
1664     }
1665     else
1666 #endif // !_TARGET_X86_
1667     {
1668         switch (unmngCallConv)
1669         {
1670             case pmCallConvCdecl:
1671                 uNativeCallingConv = CORINFO_CALLCONV_C;
1672                 break;
1673             case pmCallConvStdcall:
1674                 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1675                 break;
1676             case pmCallConvThiscall:
1677                 uNativeCallingConv = CORINFO_CALLCONV_THISCALL;
1678                 break;
1679             default:
1680                 _ASSERTE(!"Invalid calling convention.");
1681                 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1682                 break;
1683         }
1684     }
1685
1686     SetStubTargetCallingConv((CorCallingConvention)uNativeCallingConv);
1687 }
1688
1689 void NDirectStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx)
1690 {
1691     WRAPPER_NO_CONTRACT;
1692
1693     // 
1694     // This sets our state local variable that tracks the progress of the stub execution.
1695     // In the finally block we test this variable to see what cleanup we need to do. The
1696     // variable starts with the value of 0 and is assigned the following values as the 
1697     // stub executes:
1698     //
1699     // CLEANUP_INDEX_ARG0_MARSHAL + 1               - 1st argument marshaled
1700     // CLEANUP_INDEX_ARG0_MARSHAL + 2               - 2nd argument marshaled
1701     // ...
1702     // CLEANUP_INDEX_ARG0_MARSHAL + n               - nth argument marshaled
1703     // CLEANUP_INDEX_RETVAL_UNMARSHAL + 1           - return value unmarshaled
1704     // CLEANUP_INDEX_ARG0_UNMARSHAL + 1             - 1st argument unmarshaled
1705     // CLEANUP_INDEX_ARG0_UNMARSHAL + 2             - 2nd argument unmarshaled
1706     // ...
1707     // CLEANUP_INDEX_ARG0_UNMARSHAL + n             - nth argument unmarshaled
1708     // CLEANUP_INDEX_ALL_DONE + 1                   - ran to completion, no exception thrown
1709     //
1710     // Note: There may be gaps, i.e. if say 2nd argument does not need cleanup, the
1711     // state variable will never be assigned the corresponding value. However, the
1712     // value must always monotonically increase so we can use <=, >, etc.
1713     // 
1714
1715     pcsEmit->EmitLDC(uArgIdx + 1);
1716     pcsEmit->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1717 }
1718
1719 void NDirectStubLinker::EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel)
1720 {
1721     STANDARD_VM_CONTRACT;
1722
1723     SetCleanupNeeded();
1724
1725     // See EmitSetArgMarshalIndex.
1726     pcsEmit->EmitLDLOC(m_dwArgMarshalIndexLocalNum);
1727     pcsEmit->EmitLDC(uArgIdx);
1728
1729     switch (branchKind)
1730     {
1731         case BranchIfMarshaled:
1732         {
1733             // we branch to the label if the argument has been marshaled
1734             pcsEmit->EmitBGT(pSkipCleanupLabel);
1735             break;
1736         }
1737
1738         case BranchIfNotMarshaled:
1739         {
1740             // we branch to the label if the argument has not been marshaled
1741             pcsEmit->EmitBLE(pSkipCleanupLabel);
1742             break;
1743         }
1744
1745         default:
1746             UNREACHABLE();
1747     }
1748 }
1749
1750 int NDirectStubLinker::GetLCIDParamIdx()
1751 {
1752     LIMITED_METHOD_CONTRACT;
1753     return m_iLCIDParamIdx;
1754 }
1755
1756 ILCodeStream* NDirectStubLinker::GetSetupCodeStream()
1757 {
1758     LIMITED_METHOD_CONTRACT;
1759     return m_pcsSetup;
1760 }
1761
1762 ILCodeStream* NDirectStubLinker::GetMarshalCodeStream()
1763 {
1764     LIMITED_METHOD_CONTRACT;
1765     return m_pcsMarshal;
1766 }
1767
1768 ILCodeStream* NDirectStubLinker::GetUnmarshalCodeStream()
1769 {
1770     LIMITED_METHOD_CONTRACT;
1771     return m_pcsUnmarshal;
1772 }
1773
1774 ILCodeStream* NDirectStubLinker::GetReturnUnmarshalCodeStream()
1775 {
1776     LIMITED_METHOD_CONTRACT;
1777     return m_pcsRetUnmarshal;
1778 }
1779
1780 ILCodeStream* NDirectStubLinker::GetDispatchCodeStream()
1781 {
1782     LIMITED_METHOD_CONTRACT;
1783     return m_pcsDispatch;
1784 }
1785
1786 ILCodeStream* NDirectStubLinker::GetCleanupCodeStream()
1787 {
1788     LIMITED_METHOD_CONTRACT;
1789     return m_pcsCleanup;
1790 }
1791
1792 ILCodeStream* NDirectStubLinker::GetExceptionCleanupCodeStream()
1793 {
1794     LIMITED_METHOD_CONTRACT;
1795     return m_pcsExceptionCleanup;
1796 }
1797
1798 void NDirectStubLinker::AdjustTargetStackDeltaForExtraParam()
1799 {
1800     LIMITED_METHOD_CONTRACT;
1801     //
1802     // Compensate for the extra parameter.
1803     //
1804     m_iTargetStackDelta++;
1805 }
1806
1807 void NDirectStubLinker::AdjustTargetStackDeltaForReverseInteropHRESULTSwapping()
1808 {
1809     WRAPPER_NO_CONTRACT;
1810     //
1811     // In the case of reverse pinvoke, we build up the 'target'
1812     // signature as if it were normal forward pinvoke and then
1813     // switch that signature (representing the native sig) with
1814     // the stub's sig (representing the managed sig).  However,
1815     // as a side-effect, our calcualted target stack delta is 
1816     // wrong.  
1817     //
1818     // The only way that we support a different stack delta is
1819     // through hresult swapping.  So this code "undoes" the 
1820     // deltas that would have been applied in that case.  
1821     //
1822
1823     if (StubHasVoidReturnType())
1824     {
1825         //
1826         // If the managed return type is void, undo the HRESULT 
1827         // return type added to our target sig for HRESULT swapping.
1828         // No extra argument will have been added because it makes
1829         // no sense to add an extry byref void argument.
1830         //
1831         m_iTargetStackDelta--;
1832     }
1833     else
1834     {
1835         //
1836         // no longer pop the extra byref argument from the stack
1837         //
1838         m_iTargetStackDelta++;
1839     }
1840 }
1841
1842 void NDirectStubLinker::SetInteropParamExceptionInfo(UINT resID, UINT paramIdx)
1843 {
1844     LIMITED_METHOD_CONTRACT;
1845
1846     // only keep the first one
1847     if (HasInteropParamExceptionInfo())
1848     {
1849         return;
1850     }
1851
1852     m_ErrorResID = resID;
1853     m_ErrorParamIdx = paramIdx;
1854 }
1855
1856 bool NDirectStubLinker::HasInteropParamExceptionInfo()
1857 {
1858     LIMITED_METHOD_CONTRACT;
1859
1860     return !(((DWORD)-1 == m_ErrorResID) && ((DWORD)-1 == m_ErrorParamIdx));
1861 }
1862
1863 void NDirectStubLinker::GenerateInteropParamException(ILCodeStream* pcsEmit)
1864 {
1865     STANDARD_VM_CONTRACT;
1866
1867     pcsEmit->EmitLDC(m_ErrorResID);
1868     pcsEmit->EmitLDC(m_ErrorParamIdx);
1869     pcsEmit->EmitCALL(METHOD__STUBHELPERS__THROW_INTEROP_PARAM_EXCEPTION, 2, 0);
1870     
1871     pcsEmit->EmitLDNULL();
1872     pcsEmit->EmitTHROW();
1873 }
1874
1875 #ifdef FEATURE_COMINTEROP
1876 DWORD NDirectStubLinker::GetTargetInterfacePointerLocalNum()
1877 {
1878     LIMITED_METHOD_CONTRACT;
1879     CONSISTENCY_CHECK(m_dwTargetInterfacePointerLocalNum != (DWORD)-1);
1880     return m_dwTargetInterfacePointerLocalNum;
1881 }
1882 DWORD NDirectStubLinker::GetTargetEntryPointLocalNum()
1883 {
1884     LIMITED_METHOD_CONTRACT;
1885     CONSISTENCY_CHECK(m_dwTargetEntryPointLocalNum != (DWORD)-1);
1886     return m_dwTargetEntryPointLocalNum;
1887 }
1888
1889 void NDirectStubLinker::EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags)
1890 {
1891     STANDARD_VM_CONTRACT;
1892
1893     if (SF_IsForwardStub(dwStubFlags) && 
1894         (SF_IsWinRTCtorStub(dwStubFlags) || SF_IsWinRTStaticStub(dwStubFlags)))
1895     {
1896         // WinRT ctor/static stubs make the call on the factory object instead of 'this'
1897         if (m_dwWinRTFactoryObjectLocalNum == (DWORD)-1)
1898         {
1899             m_dwWinRTFactoryObjectLocalNum = NewLocal(ELEMENT_TYPE_OBJECT);
1900
1901             // get the factory object
1902             EmitLoadStubContext(m_pcsSetup, dwStubFlags);
1903             m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_OBJECT, 1, 1);
1904             m_pcsSetup->EmitSTLOC(m_dwWinRTFactoryObjectLocalNum);
1905         }
1906
1907         pcsEmit->EmitLDLOC(m_dwWinRTFactoryObjectLocalNum);
1908     }
1909     else
1910     {
1911         pcsEmit->EmitLoadThis();
1912     }
1913 }
1914 #endif // FEATURE_COMINTEROP
1915
1916 DWORD NDirectStubLinker::GetCleanupWorkListLocalNum()
1917 {
1918     LIMITED_METHOD_CONTRACT;
1919     CONSISTENCY_CHECK(m_dwCleanupWorkListLocalNum != (DWORD)-1);
1920     return m_dwCleanupWorkListLocalNum;
1921 }
1922
1923 DWORD NDirectStubLinker::GetThreadLocalNum()
1924 {
1925     STANDARD_VM_CONTRACT;
1926
1927     if (m_dwThreadLocalNum == (DWORD)-1)
1928     {
1929         // The local is created and initialized lazily when first asked.
1930         m_dwThreadLocalNum = NewLocal(ELEMENT_TYPE_I);
1931         m_pcsSetup->EmitCALL(METHOD__THREAD__INTERNAL_GET_CURRENT_THREAD, 0, 1);
1932         m_pcsSetup->EmitSTLOC(m_dwThreadLocalNum);
1933     }
1934
1935     return m_dwThreadLocalNum;
1936 }
1937
1938 DWORD NDirectStubLinker::GetReturnValueLocalNum()
1939 {
1940     LIMITED_METHOD_CONTRACT;
1941     return m_dwRetValLocalNum;
1942 }
1943
1944 BOOL NDirectStubLinker::IsCleanupNeeded()
1945 {
1946     LIMITED_METHOD_CONTRACT;
1947
1948     return (m_fHasCleanupCode || IsCleanupWorkListSetup());
1949 }
1950
1951 BOOL NDirectStubLinker::IsExceptionCleanupNeeded()
1952 {
1953     LIMITED_METHOD_CONTRACT;
1954
1955     return m_fHasExceptionCleanupCode;
1956 }
1957
1958 void NDirectStubLinker::InitCleanupCode()
1959 {
1960     CONTRACTL
1961     {
1962         STANDARD_VM_CHECK;
1963         PRECONDITION(NULL == m_pCleanupFinallyBeginLabel);
1964     }
1965     CONTRACTL_END;
1966
1967     m_pCleanupFinallyBeginLabel = NewCodeLabel();
1968     m_pcsExceptionCleanup->EmitLabel(m_pCleanupFinallyBeginLabel);
1969 }
1970
1971 void NDirectStubLinker::InitExceptionCleanupCode()
1972 {
1973     CONTRACTL
1974     {
1975         STANDARD_VM_CHECK;
1976         PRECONDITION(NULL == m_pSkipExceptionCleanupLabel);
1977     }
1978     CONTRACTL_END;
1979
1980     SetCleanupNeeded();
1981
1982     // we want to skip the entire exception cleanup if no exception has been thrown
1983     m_pSkipExceptionCleanupLabel = NewCodeLabel();
1984     EmitCheckForArgCleanup(m_pcsExceptionCleanup, CLEANUP_INDEX_ALL_DONE, BranchIfMarshaled, m_pSkipExceptionCleanupLabel);
1985 }
1986
1987 void NDirectStubLinker::SetCleanupNeeded()
1988 {
1989     WRAPPER_NO_CONTRACT;
1990
1991     if (!m_fHasCleanupCode)
1992     {
1993         m_fHasCleanupCode = TRUE;
1994         InitCleanupCode();
1995     }
1996 }
1997
1998 void NDirectStubLinker::SetExceptionCleanupNeeded()
1999 {
2000     WRAPPER_NO_CONTRACT;
2001
2002     if (!m_fHasExceptionCleanupCode)
2003     {
2004         m_fHasExceptionCleanupCode = TRUE;
2005         InitExceptionCleanupCode();
2006     }
2007 }
2008
2009 void NDirectStubLinker::NeedsCleanupList()
2010 {
2011     STANDARD_VM_CONTRACT;
2012
2013     if (!IsCleanupWorkListSetup())
2014     {
2015         m_fCleanupWorkListIsSetup = TRUE;
2016         SetCleanupNeeded();
2017
2018         // we setup a new local that will hold the cleanup work list
2019         LocalDesc desc(MscorlibBinder::GetClass(CLASS__CLEANUP_WORK_LIST));
2020         m_dwCleanupWorkListLocalNum = NewLocal(desc);
2021     }
2022 }
2023
2024
2025 BOOL NDirectStubLinker::IsCleanupWorkListSetup ()
2026 {
2027     LIMITED_METHOD_CONTRACT;
2028
2029     return m_fCleanupWorkListIsSetup;
2030 }
2031
2032
2033 void NDirectStubLinker::LoadCleanupWorkList(ILCodeStream* pcsEmit)
2034 {
2035     STANDARD_VM_CONTRACT;
2036
2037     NeedsCleanupList();
2038     pcsEmit->EmitLDLOCA(GetCleanupWorkListLocalNum());
2039 }
2040
2041
2042 void NDirectStubLinker::Begin(DWORD dwStubFlags)
2043 {
2044     STANDARD_VM_CONTRACT;
2045
2046 #ifdef FEATURE_COMINTEROP
2047     if (SF_IsWinRTHasRedirection(dwStubFlags))
2048     {
2049         _ASSERTE(SF_IsForwardCOMStub(dwStubFlags));
2050
2051         // The very first thing we need to do is check whether the call should be routed to
2052         // the marshaling stub for the corresponding projected WinRT interface. If so, we
2053         // tail-call there.
2054         m_pcsSetup->EmitLoadThis();
2055         EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2056         m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__SHOULD_CALL_WINRT_INTERFACE, 2, 1);
2057
2058         ILCodeLabel *pNoRedirection = m_pcsSetup->NewCodeLabel();
2059         m_pcsSetup->EmitBRFALSE(pNoRedirection);
2060
2061         MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(
2062             GetTargetMD(),
2063             TypeHandle::Interop_ManagedToNative);
2064
2065         CONSISTENCY_CHECK(pAdapterMD != NULL && !pAdapterMD->HasMethodInstantiation());
2066
2067         m_pcsSetup->EmitJMP(m_pcsSetup->GetToken(pAdapterMD));
2068
2069         m_pcsSetup->EmitLabel(pNoRedirection);
2070     }
2071 #endif // FEATURE_COMINTEROP
2072
2073     if (SF_IsForwardStub(dwStubFlags))
2074     {
2075
2076         if (SF_IsStubWithCctorTrigger(dwStubFlags))
2077         {
2078             EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2079             m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__INIT_DECLARING_TYPE, 1, 0);
2080         }
2081     }
2082     else
2083     {
2084 #ifdef MDA_SUPPORTED
2085         if (!SF_IsNGENedStub(dwStubFlags) && MDA_GET_ASSISTANT(GcUnmanagedToManaged))
2086         {
2087             EmitCallGcCollectForMDA(m_pcsSetup, dwStubFlags);
2088         }
2089 #endif // MDA_SUPPORTED
2090
2091         if (SF_IsDelegateStub(dwStubFlags))
2092         {
2093 #if defined(MDA_SUPPORTED)
2094             // GC was induced (gcUnmanagedToManagedMDA), arguments have been marshaled, and we are about
2095             // to touch the UMEntryThunk and extract the delegate target from it so this is the right time
2096             // to do the collected delegate MDA check.
2097
2098             // The call to CheckCollectedDelegateMDA is emitted regardless of whether the MDA is on at the
2099             // moment. This is to avoid having to ignore NGENed stubs without the call just as we do for
2100             // the GC MDA (callbackOncollectedDelegateMDA is turned on under managed debugger by default
2101             // so the impact would be substantial). The helper bails out fast if the MDA is not enabled.
2102             EmitLoadStubContext(m_pcsDispatch, dwStubFlags);
2103             m_pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CHECK_COLLECTED_DELEGATE_MDA, 1, 0);
2104 #endif // MDA_SUPPORTED
2105
2106             //
2107             // recover delegate object from UMEntryThunk
2108
2109             EmitLoadStubContext(m_pcsDispatch, dwStubFlags); // load UMEntryThunk*
2110             
2111             m_pcsDispatch->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2112             m_pcsDispatch->EmitADD();
2113             m_pcsDispatch->EmitLDIND_I();      // get OBJECTHANDLE
2114             m_pcsDispatch->EmitLDIND_REF();    // get Delegate object
2115             m_pcsDispatch->EmitLDFLD(GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__TARGET)));
2116         }
2117     }
2118
2119     m_pCleanupTryBeginLabel = NewCodeLabel();
2120     m_pcsMarshal->EmitLabel(m_pCleanupTryBeginLabel);
2121 }
2122
2123 void NDirectStubLinker::End(DWORD dwStubFlags)
2124 {
2125     STANDARD_VM_CONTRACT;
2126
2127     ILCodeStream* pcs = m_pcsUnmarshal;
2128
2129     bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(dwStubFlags) 
2130                                     && !SF_IsFieldGetterStub(dwStubFlags) 
2131                                     && !SF_IsFieldSetterStub(dwStubFlags);
2132
2133     //
2134     // Create a local for the return value and store the return value in it.
2135     //
2136     if (IsCleanupNeeded() || hasTryCatchForHRESULT)
2137     {
2138         // Save the return value if necessary, since the IL stack will be emptied when we leave a try block.
2139         LocalDesc locDescRetVal;
2140         if (SF_IsForwardStub(dwStubFlags))
2141         {
2142             GetStubReturnType(&locDescRetVal);
2143         }
2144         else
2145         {
2146             GetStubTargetReturnType(&locDescRetVal);
2147         }
2148
2149         if (!( (locDescRetVal.cbType == 1) && (locDescRetVal.ElementType[0] == ELEMENT_TYPE_VOID) ))
2150         {
2151             m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2152             if (SF_IsReverseStub(dwStubFlags) && StubHasVoidReturnType())
2153             {
2154                 // if the target returns void and we are doing HRESULT swapping, S_OK is loaded
2155                 // in the unmarshal stream
2156                 m_pcsUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2157             }
2158             else
2159             {
2160                 // otherwise the return value is loaded in the return unmarshal stream
2161                 m_pcsRetUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2162             }
2163         }
2164         else if (hasTryCatchForHRESULT && (locDescRetVal.ElementType[0] != ELEMENT_TYPE_VOID))
2165         {
2166             m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2167         }
2168     }
2169
2170     //
2171     // Emit end-of-try and end-of-finally code for the try/finally
2172     //
2173     if (IsCleanupNeeded())
2174     {
2175         m_pCleanupFinallyEndLabel = NewCodeLabel();
2176         m_pCleanupTryEndLabel = NewCodeLabel();
2177
2178         if (IsExceptionCleanupNeeded())
2179         {
2180             // if we made it here, no exception has been thrown
2181             EmitSetArgMarshalIndex(m_pcsUnmarshal, CLEANUP_INDEX_ALL_DONE);
2182         }
2183
2184         // Emit a leave at the end of the try block.  If we have an outer try/catch, we need
2185         // to leave to the beginning of the ExceptionHandler code stream, which follows the 
2186         // Cleanup code stream.  If we don't, we can just leave to the tail end of the
2187         // Unmarshal code stream where we'll emit our RET.  
2188
2189         ILCodeLabel* pLeaveTarget = m_pCleanupTryEndLabel;
2190         if (hasTryCatchForHRESULT)
2191         {
2192             pLeaveTarget = m_pCleanupFinallyEndLabel;
2193         }
2194
2195         m_pcsUnmarshal->EmitLEAVE(pLeaveTarget);
2196         m_pcsUnmarshal->EmitLabel(m_pCleanupTryEndLabel);
2197
2198         // Emit a call to destroy the clean-up list if needed.
2199         if (IsCleanupWorkListSetup())
2200         {
2201             LoadCleanupWorkList(m_pcsCleanup);
2202             m_pcsCleanup->EmitCALL(METHOD__STUBHELPERS__DESTROY_CLEANUP_LIST, 1, 0);
2203         }
2204
2205         // Emit the endfinally.
2206         m_pcsCleanup->EmitENDFINALLY();
2207         m_pcsCleanup->EmitLabel(m_pCleanupFinallyEndLabel);
2208     }
2209
2210 #ifdef MDA_SUPPORTED
2211     if (SF_IsReverseStub(dwStubFlags) && !SF_IsNGENedStub(dwStubFlags) &&
2212         MDA_GET_ASSISTANT(GcManagedToUnmanaged))
2213     {
2214         EmitCallGcCollectForMDA(pcs, dwStubFlags);
2215     }
2216 #endif // MDA_SUPPORTED
2217
2218     if (IsExceptionCleanupNeeded())
2219     {
2220         m_pcsExceptionCleanup->EmitLabel(m_pSkipExceptionCleanupLabel);
2221     }
2222
2223     // Reload the return value 
2224     if ((m_dwRetValLocalNum != (DWORD)-1) && !hasTryCatchForHRESULT)
2225     {
2226         pcs->EmitLDLOC(m_dwRetValLocalNum);
2227     }
2228 }
2229
2230 void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD)
2231 {
2232     STANDARD_VM_CONTRACT;
2233     if (SF_IsForwardStub(dwStubFlags)) // managed-to-native
2234     {
2235
2236         if (SF_IsDelegateStub(dwStubFlags)) // delegate invocation
2237         {
2238             // get the delegate unmanaged target - we call a helper instead of just grabbing
2239             // the _methodPtrAux field because we may need to intercept the call for host, MDA, etc.
2240             pcsEmit->EmitLoadThis();
2241 #ifdef _WIN64
2242             // on AMD64 GetDelegateTarget will return address of the generic stub for host when we are hosted
2243             // and update the secret argument with real target - the secret arg will be embedded in the
2244             // InlinedCallFrame by the JIT and fetched via TLS->Thread->Frame->Datum by the stub for host
2245             pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
2246 #else // _WIN64
2247             // we don't need to do this on x86 because stub for host is generated dynamically per target
2248             pcsEmit->EmitLDNULL();
2249 #endif // _WIN64
2250             pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_TARGET, 2, 1);
2251         }
2252         else // direct invocation
2253         {
2254             if (SF_IsCALLIStub(dwStubFlags)) // unmanaged CALLI
2255             {
2256                 // if we ever NGEN CALLI stubs, this would have to be done differently
2257                 _ASSERTE(!SF_IsNGENedStub(dwStubFlags));
2258
2259 #ifndef CROSSGEN_COMPILE
2260
2261 #ifdef _TARGET_X86_
2262
2263                 {
2264                     // for managed-to-unmanaged CALLI that requires marshaling, the target is passed
2265                     // as the secret argument to the stub by GenericPInvokeCalliHelper (asmhelpers.asm)
2266                     EmitLoadStubContext(pcsEmit, dwStubFlags);
2267                 }
2268
2269 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2270                 if (NDirect::IsHostHookEnabled())
2271                 {
2272                     // we need to call to the host hook, real target is passed as the last argument
2273                     Stub *pHostStub = NDirect::GenerateStubForHost(
2274                         GetStubSigModule(),
2275                         (CorUnmanagedCallingConvention)(GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_MASK),
2276                         pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize());
2277
2278                     pcsEmit->EmitLDC((DWORD_PTR)pHostStub->GetEntryPoint());
2279                 }
2280 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2281
2282 #else // _TARGET_X86_
2283
2284 #ifdef FEATURE_INCLUDE_ALL_INTERFACES 
2285                 if (NDirect::IsHostHookEnabled())
2286                 {
2287                     // the stub for host will get the original target from the secret arg
2288                     pcsEmit->EmitLDC((DWORD_PTR)GetEEFuncEntryPoint(PInvokeStubForHost));
2289                 }
2290                 else
2291 #endif // FEATURE_INCLUDE_ALL_INTERFACES 
2292                 {
2293                     // the secret arg has been shifted to left and ORed with 1 (see code:GenericPInvokeCalliHelper)
2294                     EmitLoadStubContext(pcsEmit, dwStubFlags);
2295 #ifndef _TARGET_ARM_
2296                     pcsEmit->EmitLDC(1);
2297                     pcsEmit->EmitSHR_UN();
2298 #endif
2299                 }
2300
2301 #endif // _TARGET_X86_
2302
2303 #endif // CROSSGEN_COMPILE
2304             }
2305             else
2306 #ifdef FEATURE_COMINTEROP
2307             if (!SF_IsCOMStub(dwStubFlags)) // forward P/Invoke
2308 #endif // FEATURE_COMINTEROP
2309             {
2310                 EmitLoadStubContext(pcsEmit, dwStubFlags);
2311
2312                 {
2313                     // Perf: inline the helper for now
2314                     //pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_NDIRECT_TARGET, 1, 1);
2315                     pcsEmit->EmitLDC(offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
2316                     pcsEmit->EmitADD();
2317                     pcsEmit->EmitLDIND_I();
2318                     pcsEmit->EmitLDIND_I();
2319                 }
2320             }
2321 #ifdef FEATURE_COMINTEROP
2322             else
2323             {
2324                 // this is a CLR -> COM call
2325                 // the target has been computed by StubHelpers::GetCOMIPFromRCW
2326                 pcsEmit->EmitLDLOC(m_dwTargetEntryPointLocalNum);
2327             }
2328 #endif // FEATURE_COMINTEROP
2329         }
2330     }
2331     else // native-to-managed
2332     {
2333         if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate
2334         {
2335             int tokDelegate_methodPtr = pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR));
2336
2337             EmitLoadStubContext(pcsEmit, dwStubFlags);
2338             pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2339             pcsEmit->EmitADD();
2340             pcsEmit->EmitLDIND_I();                    // Get OBJECTHANDLE
2341             pcsEmit->EmitLDIND_REF();                  // Get Delegate object
2342             pcsEmit->EmitLDFLD(tokDelegate_methodPtr); // get _methodPtr 
2343         }
2344 #ifdef FEATURE_COMINTEROP
2345         else if (SF_IsCOMStub(dwStubFlags)) // COM -> CLR call
2346         {
2347             // managed target is passed directly in the secret argument
2348             EmitLoadStubContext(pcsEmit, dwStubFlags);
2349         }
2350 #endif // FEATURE_COMINTEROP
2351         else // direct reverse P/Invoke (CoreCLR hosting)
2352         {
2353             EmitLoadStubContext(pcsEmit, dwStubFlags);
2354             CONSISTENCY_CHECK(0 == offsetof(UMEntryThunk, m_pManagedTarget)); // if this changes, just add back the EmitLDC/EmitADD below
2355             // pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pManagedTarget));
2356             // pcsEmit->EmitADD();
2357             pcsEmit->EmitLDIND_I();  // Get UMEntryThunk::m_pManagedTarget
2358         }
2359     }
2360
2361     // For managed-to-native calls, the rest of the work is done by the JIT. It will
2362     // erect InlinedCallFrame, flip GC mode, and use the specified calling convention
2363     // to call the target. For native-to-managed calls, this is an ordinary managed
2364     // CALLI and nothing special happens.
2365     pcsEmit->EmitCALLI(TOKEN_ILSTUB_TARGET_SIG, 0, m_iTargetStackDelta);
2366 }
2367
2368 void NDirectStubLinker::EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal)
2369 {
2370     STANDARD_VM_CONTRACT;
2371
2372     if (SF_IsForwardPInvokeStub(m_dwStubFlags) && !SF_IsForwardDelegateStub(m_dwStubFlags))
2373     {
2374         // get the secret argument via intrinsic
2375         pslILEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2376     }
2377     else
2378     {
2379         // no secret argument
2380         pslILEmit->EmitLoadNullPtr();
2381     }
2382
2383     pslILEmit->EmitLDLOC(dwPinnedLocal);
2384
2385     pslILEmit->EmitCALL(METHOD__STUBHELPERS__LOG_PINNED_ARGUMENT, 2, 0);
2386 }
2387
2388 void NDirectStubLinker::GetCleanupFinallyOffsets(ILStubEHClause * pClause)
2389 {
2390     CONTRACTL
2391     {
2392         STANDARD_VM_CHECK;
2393         PRECONDITION(CheckPointer(pClause));
2394     }
2395     CONTRACTL_END;
2396
2397     if (m_pCleanupFinallyEndLabel)
2398     {
2399         _ASSERTE(m_pCleanupFinallyBeginLabel);
2400         _ASSERTE(m_pCleanupTryBeginLabel);
2401         _ASSERTE(m_pCleanupTryEndLabel);
2402
2403         pClause->kind = ILStubEHClause::kFinally;
2404         pClause->dwTryBeginOffset      = (DWORD)m_pCleanupTryBeginLabel->GetCodeOffset();
2405         pClause->cbTryLength           = (DWORD)m_pCleanupTryEndLabel->GetCodeOffset() - pClause->dwTryBeginOffset;
2406         pClause->dwHandlerBeginOffset  = (DWORD)m_pCleanupFinallyBeginLabel->GetCodeOffset();
2407         pClause->cbHandlerLength       = (DWORD)m_pCleanupFinallyEndLabel->GetCodeOffset() - pClause->dwHandlerBeginOffset;
2408     }
2409 }
2410
2411 void NDirectStubLinker::ClearCode()
2412 {
2413     WRAPPER_NO_CONTRACT;
2414     ILStubLinker::ClearCode();
2415     
2416     m_pCleanupTryBeginLabel = 0;
2417     m_pCleanupTryEndLabel = 0;
2418     m_pCleanupFinallyBeginLabel = 0;
2419     m_pCleanupFinallyEndLabel = 0;
2420 }
2421
2422 #ifdef PROFILING_SUPPORTED
2423 DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2424 {
2425     STANDARD_VM_CONTRACT;
2426
2427     if (SF_IsForwardDelegateStub(dwStubFlags) || SF_IsCALLIStub(dwStubFlags))
2428     {
2429         // secret argument does not contain MD nor UMEntryThunk
2430         pcsEmit->EmitLoadNullPtr();
2431     }
2432     else
2433     {
2434         EmitLoadStubContext(pcsEmit, dwStubFlags);
2435     }
2436
2437     if (SF_IsForwardStub(dwStubFlags))
2438     {
2439         pcsEmit->EmitLDLOC(GetThreadLocalNum());
2440     }
2441     else
2442     {
2443         // we use a null pThread to indicate reverse interop
2444         pcsEmit->EmitLDC(NULL);
2445     }
2446         
2447     // In the unmanaged delegate case, we need the "this" object to retrieve the MD 
2448     // in StubHelpers::ProfilerEnterCallback().
2449     if (SF_IsDelegateStub(dwStubFlags))
2450     {
2451         if (SF_IsForwardStub(dwStubFlags))
2452         {
2453             pcsEmit->EmitLoadThis();
2454         }
2455         else
2456         {
2457             EmitLoadStubContext(pcsEmit, dwStubFlags); // load UMEntryThunk*
2458             pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2459             pcsEmit->EmitADD();
2460             pcsEmit->EmitLDIND_I();      // get OBJECTHANDLE
2461             pcsEmit->EmitLDIND_REF();    // get Delegate object
2462         }
2463     }
2464     else
2465     {
2466         pcsEmit->EmitLDC(NULL);
2467     }
2468     pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_BEGIN_TRANSITION_CALLBACK, 3, 1);
2469
2470     // Store the MD for StubHelpers::ProfilerLeaveCallback().
2471     DWORD dwMethodDescLocalNum = pcsEmit->NewLocal(ELEMENT_TYPE_I);
2472     pcsEmit->EmitSTLOC(dwMethodDescLocalNum);
2473     return dwMethodDescLocalNum;
2474 }
2475
2476 void NDirectStubLinker::EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum)
2477 {
2478     STANDARD_VM_CONTRACT;
2479
2480     pcsEmit->EmitLDLOC(dwMethodDescLocalNum);
2481     if (SF_IsReverseStub(dwStubFlags))
2482     {
2483         // we use a null pThread to indicate reverse interop
2484         pcsEmit->EmitLDC(NULL);
2485     }
2486     else
2487     {
2488         pcsEmit->EmitLDLOC(GetThreadLocalNum());
2489     }
2490     pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_END_TRANSITION_CALLBACK, 2, 0);
2491 }
2492 #endif // PROFILING_SUPPPORTED
2493
2494 #ifdef VERIFY_HEAP
2495 void NDirectStubLinker::EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags)
2496 {
2497     STANDARD_VM_CONTRACT;
2498
2499     pcsEmit->EmitLDLOC(dwLocalNum);
2500
2501     if (SF_IsDelegateStub(dwStubFlags))
2502     {
2503         pcsEmit->EmitLoadNullPtr();
2504         pcsEmit->EmitLoadThis();
2505     }
2506     else if (SF_IsCALLIStub(dwStubFlags))
2507     {
2508         pcsEmit->EmitLoadNullPtr();
2509         pcsEmit->EmitLDNULL();
2510     }
2511     else
2512     {
2513         // P/Invoke, CLR->COM
2514         EmitLoadStubContext(pcsEmit, dwStubFlags);
2515         pcsEmit->EmitLDNULL();
2516     }
2517
2518     if (fIsByref)
2519     {
2520         // StubHelpers.ValidateByref(byref, pMD, pThis)
2521         pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_BYREF, 3, 0);
2522     }
2523     else
2524     {
2525         // StubHelpers.ValidateObject(obj, pMD, pThis)
2526         pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_OBJECT, 3, 0);
2527     }
2528 }
2529
2530 void NDirectStubLinker::EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2531 {
2532     STANDARD_VM_CONTRACT;
2533
2534     // generate validation callouts for pinned locals
2535     CQuickBytes qbLocalSig;
2536     DWORD cbSig = GetLocalSigSize();
2537     
2538     qbLocalSig.AllocThrows(cbSig);
2539     PCOR_SIGNATURE pSig = (PCOR_SIGNATURE)qbLocalSig.Ptr();
2540
2541     GetLocalSig(pSig, cbSig);
2542     SigPointer ptr(pSig, cbSig);
2543
2544     IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
2545
2546     ULONG numLocals;
2547     IfFailThrow(ptr.GetData(&numLocals));
2548
2549     for (ULONG i = 0; i < numLocals; i++)
2550     {
2551         BYTE modifier;
2552         IfFailThrow(ptr.PeekByte(&modifier));
2553         if (modifier == ELEMENT_TYPE_PINNED)
2554         {
2555             IfFailThrow(ptr.GetByte(NULL));
2556             IfFailThrow(ptr.PeekByte(&modifier));
2557             EmitValidateLocal(pcsEmit, i, (modifier == ELEMENT_TYPE_BYREF), dwStubFlags);
2558         }
2559
2560         IfFailThrow(ptr.SkipExactlyOne());
2561     }
2562 }
2563 #endif // VERIFY_HEAP
2564
2565 // Loads the 'secret argument' passed to the stub.
2566 void NDirectStubLinker::EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2567 {
2568     STANDARD_VM_CONTRACT;
2569
2570     CONSISTENCY_CHECK(!SF_IsForwardDelegateStub(dwStubFlags));
2571     CONSISTENCY_CHECK(!SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags));
2572
2573 #ifdef FEATURE_COMINTEROP
2574     if (SF_IsWinRTDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags))
2575     {
2576         // we have the delegate 'this' but we need the EEImpl/Instantiated 'Invoke' MD pointer
2577         // (Delegate.GetInvokeMethod does not return exact instantiated MD so we call our own helper)
2578         pcsEmit->EmitLoadThis();
2579         pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_INVOKE_METHOD, 1, 1);
2580     }
2581     else
2582 #endif // FEATURE_COMINTEROP
2583     {
2584         // get the secret argument via intrinsic
2585         pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2586     }
2587 }
2588
2589 #ifdef MDA_SUPPORTED
2590 void NDirectStubLinker::EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2591 {
2592     STANDARD_VM_CONTRACT;
2593
2594     ILCodeLabel *pSkipGcLabel = NULL;
2595
2596     if (SF_IsForwardPInvokeStub(dwStubFlags) &&
2597         !SF_IsDelegateStub(dwStubFlags) &&
2598         !SF_IsCALLIStub(dwStubFlags))
2599     {
2600         // don't call GC if this is a QCall
2601         EmitLoadStubContext(pcsEmit, dwStubFlags);
2602         pcsEmit->EmitCALL(METHOD__STUBHELPERS__IS_QCALL, 1, 1);
2603
2604         pSkipGcLabel = pcsEmit->NewCodeLabel();
2605         pcsEmit->EmitBRTRUE(pSkipGcLabel);
2606     }
2607
2608     pcsEmit->EmitCALL(METHOD__STUBHELPERS__TRIGGER_GC_FOR_MDA, 0, 0);
2609
2610     if (pSkipGcLabel != NULL)
2611     {
2612         pcsEmit->EmitLabel(pSkipGcLabel);
2613     }
2614 }
2615 #endif // MDA_SUPPORTED
2616
2617 #ifdef FEATURE_COMINTEROP
2618
2619 class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing calls
2620 {
2621 public:
2622     DispatchStubState()
2623         : m_dwStubFlags(0),
2624           m_lateBoundFlags(0)
2625     {
2626         WRAPPER_NO_CONTRACT;
2627     }
2628
2629     void SetLastError(BOOL fSetLastError)
2630     {
2631         LIMITED_METHOD_CONTRACT;
2632
2633         CONSISTENCY_CHECK(!fSetLastError);
2634     }
2635
2636     void BeginEmit(DWORD dwStubFlags)
2637     {
2638         LIMITED_METHOD_CONTRACT;
2639
2640         CONSISTENCY_CHECK(SF_IsCOMStub(dwStubFlags));
2641         m_dwStubFlags = dwStubFlags;
2642     }
2643
2644     void MarshalReturn(MarshalInfo* pInfo, int argOffset)
2645     {
2646         CONTRACTL
2647         {
2648             STANDARD_VM_CHECK;
2649
2650             PRECONDITION(CheckPointer(pInfo));
2651         }
2652         CONTRACTL_END;
2653     }
2654
2655     void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
2656     {
2657         CONTRACTL
2658         {
2659             STANDARD_VM_CHECK;
2660             PRECONDITION(CheckPointer(pInfo));
2661         }
2662         CONTRACTL_END;
2663
2664         if (SF_IsCOMLateBoundStub(m_dwStubFlags) && pInfo->GetDispWrapperType() != 0)
2665         {
2666             m_lateBoundFlags |= ComPlusCallInfo::kRequiresArgumentWrapping;
2667         }
2668     }
2669
2670     void MarshalLCID(int argIdx)
2671     {
2672         LIMITED_METHOD_CONTRACT;
2673     }
2674
2675 #ifdef FEATURE_COMINTEROP
2676     void MarshalHiddenLengthArgument(MarshalInfo *, BOOL)
2677     {
2678         LIMITED_METHOD_CONTRACT;
2679     }
2680     void MarshalFactoryReturn()
2681     {
2682         LIMITED_METHOD_CONTRACT;
2683         UNREACHABLE();
2684     }
2685 #endif // FEATURE_COMINTEROP
2686
2687     void EmitInvokeTarget(MethodDesc *pStubMD)
2688     {
2689         LIMITED_METHOD_CONTRACT;
2690         UNREACHABLE_MSG("Should never come to DispatchStubState::EmitInvokeTarget");
2691     }
2692
2693     void FinishEmit(MethodDesc *pMD)
2694     {
2695         STANDARD_VM_CONTRACT;
2696
2697         // set flags directly on the interop MD
2698         _ASSERTE(pMD->IsComPlusCall());
2699
2700         ((ComPlusCallMethodDesc *)pMD)->SetLateBoundFlags(m_lateBoundFlags);
2701     }
2702
2703 protected:
2704     DWORD        m_dwStubFlags;
2705     BYTE         m_lateBoundFlags; // ComPlusCallMethodDesc::Flags
2706 };
2707
2708 #endif // FEATURE_COMINTEROP
2709
2710
2711 void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
2712 {
2713     CONTRACTL
2714     {
2715         THROWS;
2716         GC_NOTRIGGER;
2717         MODE_ANY;
2718     }
2719     CONTRACTL_END;
2720     
2721     // initialize data members
2722     m_wFlags = 0;
2723     m_pModule = pModule;
2724     m_callConv = (CorPinvokeMap)0;
2725     SetBestFitMapping (TRUE);
2726     SetThrowOnUnmappableChar (FALSE);
2727     SetLinkFlags (nlfNone);
2728     SetCharSet (nltAnsi);
2729     m_error = 0;
2730
2731     // assembly/type level m_bestFit & m_bThrowOnUnmappableChar
2732     BOOL bBestFit;
2733     BOOL bThrowOnUnmappableChar;
2734
2735     if (pMT != NULL)
2736     {
2737         EEClass::GetBestFitMapping(pMT, &bBestFit, &bThrowOnUnmappableChar);
2738     }
2739     else
2740     {
2741         ReadBestFitCustomAttribute(m_pModule->GetMDImport(), mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
2742     }
2743
2744     SetBestFitMapping (bBestFit);
2745     SetThrowOnUnmappableChar (bThrowOnUnmappableChar);
2746 }
2747
2748 void PInvokeStaticSigInfo::PreInit(MethodDesc* pMD)
2749 {
2750     CONTRACTL
2751     {
2752         THROWS;
2753         GC_NOTRIGGER;
2754         MODE_ANY;
2755     }
2756     CONTRACTL_END;
2757
2758     PreInit(pMD->GetModule(), pMD->GetMethodTable());
2759     SetIsStatic (pMD->IsStatic());
2760     m_sig = pMD->GetSignature();
2761     if (pMD->IsEEImpl())
2762     {
2763         CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
2764         SetIsDelegateInterop(TRUE);
2765     }
2766 }
2767
2768 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
2769     MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError) 
2770
2771     CONTRACTL
2772     {
2773         THROWS;
2774         GC_NOTRIGGER;
2775         MODE_ANY;
2776     }
2777     CONTRACTL_END;
2778     
2779     DllImportInit(pMD, pLibName, pEntryPointName);
2780
2781     if (throwOnError)
2782         ReportErrors();
2783 }
2784
2785 PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOnError)
2786 {
2787     CONTRACTL
2788     {
2789         THROWS;
2790         GC_NOTRIGGER;
2791         MODE_ANY;
2792
2793         PRECONDITION(CheckPointer(pMD));
2794     }
2795     CONTRACTL_END;
2796
2797     HRESULT hr = S_OK;
2798
2799     MethodTable * pMT = pMD->GetMethodTable();
2800
2801     if (!pMT->IsDelegate())
2802     {
2803         DllImportInit(pMD, NULL, NULL);
2804         return;
2805     }
2806
2807     // initialize data members to defaults
2808     PreInit(pMD);
2809
2810     // System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute
2811     BYTE* pData = NULL;
2812     LONG cData = 0;
2813     CorPinvokeMap callConv = (CorPinvokeMap)0;
2814
2815     HRESULT hRESULT = pMT->GetMDImport()->GetCustomAttributeByName(
2816         pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, (const VOID **)(&pData), (ULONG *)&cData);
2817     IfFailThrow(hRESULT);
2818     if(cData != 0)
2819     {
2820         CustomAttributeParser ca(pData, cData);
2821
2822         CaArg args[1];
2823         args[0].InitEnum(SERIALIZATION_TYPE_I4, (ULONG)m_callConv);
2824
2825         IfFailGo(ParseKnownCaArgs(ca, args, lengthof(args)));
2826
2827         enum UnmanagedFunctionPointerNamedArgs
2828         {
2829             MDA_CharSet,
2830             MDA_BestFitMapping,
2831             MDA_ThrowOnUnmappableChar,
2832             MDA_SetLastError,
2833             MDA_PreserveSig,
2834             MDA_Last,
2835         };
2836
2837         CaNamedArg namedArgs[MDA_Last];
2838         namedArgs[MDA_CharSet].InitI4FieldEnum("CharSet", "System.Runtime.InteropServices.CharSet", (ULONG)GetCharSet());
2839         namedArgs[MDA_BestFitMapping].InitBoolField("BestFitMapping", (ULONG)GetBestFitMapping());
2840         namedArgs[MDA_ThrowOnUnmappableChar].InitBoolField("ThrowOnUnmappableChar", (ULONG)GetThrowOnUnmappableChar());
2841         namedArgs[MDA_SetLastError].InitBoolField("SetLastError", 0);
2842         namedArgs[MDA_PreserveSig].InitBoolField("PreserveSig", 0);
2843
2844         IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
2845
2846         callConv = (CorPinvokeMap)(args[0].val.u4 << 8);
2847         CorNativeLinkType nlt = (CorNativeLinkType)0;
2848
2849         // XXX Tue 07/19/2005
2850         // Keep in sync with the handling of CorPInvokeMap in
2851         // PInvokeStaticSigInfo::DllImportInit.
2852         switch( namedArgs[MDA_CharSet].val.u4 )
2853         {
2854         case 0:
2855         case nltAnsi:
2856             nlt = nltAnsi; break;
2857         case nltUnicode:
2858         case nltAuto:   // Since Win9x isn't supported anymore, nltAuto always represents unicode strings.
2859             nlt = nltUnicode; break;
2860         default:
2861             hr = E_FAIL; goto ErrExit;
2862         }
2863         SetCharSet ( nlt );
2864         SetBestFitMapping (namedArgs[MDA_BestFitMapping].val.u1);
2865         SetThrowOnUnmappableChar (namedArgs[MDA_ThrowOnUnmappableChar].val.u1);
2866         if (namedArgs[MDA_SetLastError].val.u1) 
2867             SetLinkFlags ((CorNativeLinkFlags)(nlfLastError | GetLinkFlags()));
2868         if (namedArgs[MDA_PreserveSig].val.u1)
2869             SetLinkFlags ((CorNativeLinkFlags)(nlfNoMangle | GetLinkFlags()));
2870     }
2871
2872             
2873 ErrExit:    
2874     if (hr != S_OK)
2875         SetError(IDS_EE_NDIRECT_BADNATL);   
2876
2877     InitCallConv(callConv, pMD->IsVarArg()); 
2878
2879     if (throwOnError)
2880         ReportErrors();   
2881 }
2882
2883 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
2884     Signature sig, Module* pModule, ThrowOnError throwOnError)
2885 {
2886     CONTRACTL
2887     {
2888         THROWS;
2889         GC_NOTRIGGER;
2890         MODE_ANY;
2891
2892         PRECONDITION(CheckPointer(pModule));
2893     }
2894     CONTRACTL_END;
2895
2896     PreInit(pModule, NULL);
2897     m_sig = sig;
2898     SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
2899     InitCallConv((CorPinvokeMap)0, FALSE);
2900     
2901     if (throwOnError)
2902         ReportErrors();    
2903 }
2904
2905 void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LPCUTF8 *ppEntryPointName)
2906 {
2907     CONTRACTL
2908     {
2909         THROWS;
2910         GC_NOTRIGGER;
2911         MODE_ANY;
2912
2913         PRECONDITION(CheckPointer(pMD));
2914
2915         // These preconditions to prevent multithreaded regression 
2916         // where pMD->ndirect.m_szLibName was passed in directly, cleared 
2917         // by this API, then accessed on another thread before being reset here.
2918         PRECONDITION(CheckPointer(ppLibName, NULL_OK) && (!ppLibName || *ppLibName == NULL)); 
2919         PRECONDITION(CheckPointer(ppEntryPointName, NULL_OK) && (!ppEntryPointName || *ppEntryPointName == NULL));
2920     }
2921     CONTRACTL_END;
2922
2923     // initialize data members to defaults
2924     PreInit(pMD);
2925
2926     // System.Runtime.InteropServices.DllImportAttribute
2927     IMDInternalImport  *pInternalImport = pMD->GetMDImport();
2928     CorPinvokeMap mappingFlags = pmMaxValue;
2929     mdModuleRef modref = mdModuleRefNil;
2930     if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
2931     {
2932 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
2933         // The guessing heuristic has been broken with NGen for a long time since we stopped loading
2934         // images at NGen time using full LoadLibrary. The DLL references are not resolved correctly
2935         // without full LoadLibrary.
2936         //
2937         // Disable the heuristic consistently during NGen so that it does not kick in by accident.
2938         if (!IsCompilationProcess())
2939             BestGuessNDirectDefaults(pMD);
2940 #endif
2941         InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
2942         return;
2943     }
2944     
2945     // out parameter pEntryPointName
2946     if (ppEntryPointName && *ppEntryPointName == NULL)
2947         *ppEntryPointName = pMD->GetName();
2948     
2949     // out parameter pLibName
2950     if (ppLibName != NULL)
2951     {
2952         if (FAILED(pInternalImport->GetModuleRefProps(modref, ppLibName)))
2953         {
2954             SetError(IDS_CLASSLOAD_BADFORMAT);
2955             return;
2956         }
2957     }
2958     
2959     // m_callConv
2960     InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
2961     
2962     // m_bestFit
2963     CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
2964     if (bestFitMask == pmBestFitEnabled)
2965         SetBestFitMapping (TRUE);
2966     else if (bestFitMask == pmBestFitDisabled)
2967         SetBestFitMapping (FALSE);
2968
2969     // m_bThrowOnUnmappableChar
2970     CorPinvokeMap unmappableMask = (CorPinvokeMap)(mappingFlags & pmThrowOnUnmappableCharMask);
2971     if (unmappableMask == pmThrowOnUnmappableCharEnabled)
2972         SetThrowOnUnmappableChar (TRUE);
2973     else if (unmappableMask == pmThrowOnUnmappableCharDisabled)
2974         SetThrowOnUnmappableChar (FALSE);
2975
2976     // inkFlags : CorPinvoke -> CorNativeLinkFlags
2977     if (mappingFlags & pmSupportsLastError)
2978         SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
2979     if (mappingFlags & pmNoMangle)
2980         SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfNoMangle));
2981
2982     // XXX Tue 07/19/2005
2983     // Keep in sync with the handling of CorNativeLinkType in
2984     // PInvokeStaticSigInfo::PInvokeStaticSigInfo.
2985     
2986     // charset : CorPinvoke -> CorNativeLinkType
2987     CorPinvokeMap charSetMask = (CorPinvokeMap)(mappingFlags & (pmCharSetNotSpec | pmCharSetAnsi | pmCharSetUnicode | pmCharSetAuto));
2988     if (charSetMask == pmCharSetNotSpec || charSetMask == pmCharSetAnsi)
2989     {
2990         SetCharSet (nltAnsi);
2991     }
2992     else if (charSetMask == pmCharSetUnicode || charSetMask == pmCharSetAuto)
2993     {
2994         // Since Win9x isn't supported anymore, pmCharSetAuto always represents unicode strings.
2995         SetCharSet (nltUnicode);
2996     }
2997     else
2998     {
2999         SetError(IDS_EE_NDIRECT_BADNATL);
3000     }
3001 }
3002
3003
3004 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3005
3006 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3007 static BOOL HeuristicDoesThisLooksLikeAnApiCallHelper(LPBYTE pTarget)
3008 {
3009     CONTRACTL
3010     {
3011         NOTHROW;
3012         GC_NOTRIGGER;
3013         MODE_ANY;
3014     }
3015     CONTRACTL_END;
3016
3017     // This code is not that useful anymore since this functionality is already embedded in the VC linker.
3018     // The linker will emit the lasterror flag by default for functions residing in modules that are
3019     // a superset of the list below.
3020     // Look for bug VSWhidbey 241895.
3021
3022     static struct SysDllInfo
3023     {
3024         LPCWSTR pName;
3025         LPBYTE pImageBase;
3026         DWORD  dwImageSize;
3027     } gSysDllInfo[] =  {{WINDOWS_KERNEL32_DLLNAME_W, 0, 0},
3028                         {W("GDI32"),           0, 0},
3029                         {W("USER32"),          0, 0},
3030                         {W("ADVAPI32"),        0, 0}
3031                        };
3032
3033
3034     for (int i = 0; i < sizeof(gSysDllInfo)/sizeof(*gSysDllInfo); i++)
3035     {
3036         if (gSysDllInfo[i].pImageBase == 0)
3037         {
3038             IMAGE_DOS_HEADER *pDos = (IMAGE_DOS_HEADER*)CLRGetModuleHandle(gSysDllInfo[i].pName);
3039             if (pDos)
3040             {
3041                 if (pDos->e_magic == VAL16(IMAGE_DOS_SIGNATURE))
3042                 {
3043                     IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*) (((LPBYTE)pDos) + VAL32(pDos->e_lfanew));
3044                     if (pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) &&
3045                         pNT->FileHeader.SizeOfOptionalHeader == 
3046 #ifdef _WIN64
3047                             VAL16(sizeof(IMAGE_OPTIONAL_HEADER64))
3048 #else
3049                             VAL16(sizeof(IMAGE_OPTIONAL_HEADER32))
3050 #endif
3051                         && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
3052                     {
3053                         gSysDllInfo[i].dwImageSize = VAL32(pNT->OptionalHeader.SizeOfImage);
3054                     }
3055                 }
3056
3057                 gSysDllInfo[i].pImageBase = (LPBYTE)pDos;
3058             }
3059         }
3060         if (gSysDllInfo[i].pImageBase != 0 &&
3061             pTarget >= gSysDllInfo[i].pImageBase &&
3062             pTarget < gSysDllInfo[i].pImageBase + gSysDllInfo[i].dwImageSize)
3063         {
3064             return TRUE;
3065         }
3066     }
3067
3068     return FALSE;
3069 }
3070
3071 LPBYTE FollowIndirect(LPBYTE pTarget)
3072 {
3073     CONTRACT (LPBYTE)
3074     {
3075         NOTHROW;
3076         GC_NOTRIGGER;
3077         MODE_ANY;
3078         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3079     }
3080     CONTRACT_END;
3081
3082     LPBYTE pRet = NULL;
3083
3084     EX_TRY
3085     {
3086         AVInRuntimeImplOkayHolder AVOkay;
3087         
3088 #ifdef _TARGET_X86_
3089         if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3090         {
3091             pRet = **(LPBYTE**)(pTarget + 2);
3092         }
3093 #elif defined(_TARGET_AMD64_)
3094         if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3095         {
3096             INT64 rva = *(INT32*)(pTarget + 2);
3097             pRet = *(LPBYTE*)(pTarget + 6 + rva);
3098         }
3099 #endif
3100     }
3101     EX_CATCH
3102     {
3103         // Catch AVs here.
3104     }
3105     EX_END_CATCH(SwallowAllExceptions);
3106
3107     RETURN pRet;
3108 }
3109
3110 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3111 BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget)
3112 {
3113     CONTRACTL
3114     {
3115         NOTHROW;
3116         GC_NOTRIGGER;
3117         MODE_ANY;
3118     }
3119     CONTRACTL_END;
3120
3121     if (pTarget == NULL)
3122         return FALSE;
3123
3124     if (HeuristicDoesThisLooksLikeAnApiCallHelper(pTarget))
3125         return TRUE;
3126
3127     LPBYTE pTarget2 = FollowIndirect(pTarget);
3128     if (pTarget2)
3129     {
3130         // jmp [xxxx] - could be an import thunk
3131         return HeuristicDoesThisLooksLikeAnApiCallHelper( pTarget2 );
3132     }
3133
3134     return FALSE;
3135 }
3136
3137 BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
3138 {
3139     CONTRACTL
3140     {
3141         NOTHROW;
3142         GC_NOTRIGGER;
3143         MODE_ANY;
3144     }
3145     CONTRACTL_END;
3146
3147     static LPBYTE pGetLastError = NULL;
3148     if (!pGetLastError)
3149     {
3150         // No need to use a holder here, since no cleanup is necessary.
3151         HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
3152         if (hMod)
3153         {
3154             pGetLastError = (LPBYTE)GetProcAddress(hMod, "GetLastError");
3155             if (!pGetLastError)
3156             {
3157                 // This should never happen but better to be cautious.
3158                 pGetLastError = (LPBYTE)-1;
3159             }
3160         }
3161         else
3162         {
3163             // We failed to get the module handle for kernel32.dll. This is almost impossible
3164             // however better to err on the side of caution.
3165             pGetLastError = (LPBYTE)-1;
3166         }
3167     }
3168
3169     if (pTarget == pGetLastError)
3170         return TRUE;
3171
3172     if (pTarget == NULL)
3173         return FALSE;
3174
3175     LPBYTE pTarget2 = FollowIndirect(pTarget);
3176     if (pTarget2)
3177     {
3178         // jmp [xxxx] - could be an import thunk
3179         return pTarget2 == pGetLastError;
3180     }
3181
3182     return FALSE;
3183 }
3184
3185 DWORD __stdcall FalseGetLastError()
3186 {
3187     WRAPPER_NO_CONTRACT;
3188
3189     return GetThread()->m_dwLastError;
3190 }
3191
3192 void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
3193 {
3194     CONTRACTL
3195     {
3196         NOTHROW;
3197         GC_NOTRIGGER;
3198         MODE_ANY;
3199     }
3200     CONTRACTL_END;
3201
3202     if (!pMD->IsNDirect())
3203         return;
3204
3205     NDirectMethodDesc* pMDD = (NDirectMethodDesc*)pMD;
3206     
3207     if (!pMDD->IsEarlyBound())
3208         return;
3209
3210     LPVOID pTarget = NULL;
3211         
3212     // NOTE: If we get inside this block, and this is a call to GetLastError, 
3213     //  then InitEarlyBoundNDirectTarget has not been run yet.
3214     if (pMDD->NDirectTargetIsImportThunk())
3215     {
3216         // Get the unmanaged callsite.
3217         pTarget = (LPVOID)pMDD->GetModule()->GetInternalPInvokeTarget(pMDD->GetRVA());
3218
3219         // If this is a call to GetLastError, then we haven't overwritten m_pNativeNDirectTarget yet.
3220         if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)pTarget))
3221             pTarget = (BYTE*) FalseGetLastError;
3222     }
3223     else
3224     {
3225         pTarget = pMDD->GetNativeNDirectTarget();
3226     }
3227
3228     if (HeuristicDoesThisLooksLikeAnApiCall((LPBYTE) pTarget))
3229         SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3230 }
3231
3232 #endif // FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
3233
3234
3235 void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
3236 {
3237     CONTRACTL
3238     {
3239         NOTHROW;
3240         GC_NOTRIGGER;
3241         MODE_ANY;
3242     }
3243     CONTRACTL_END
3244
3245     // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
3246     if (callConv == pmCallConvWinapi)
3247         callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3248
3249     CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
3250     BOOL fSuccess = MetaSig::GetUnmanagedCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv);
3251
3252     if (!fSuccess)
3253     {
3254         SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format
3255     }
3256
3257     // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
3258     // to do this before we check to make sure the PInvoke map calling convention and the 
3259     // signature calling convention match for compatibility reasons.
3260     if (sigCallConv == pmCallConvWinapi)
3261         sigCallConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3262
3263     if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
3264         SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
3265
3266     if (callConv == 0 && sigCallConv == 0)
3267         m_callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3268     else if (callConv != 0)
3269         m_callConv = callConv;
3270     else
3271         m_callConv = sigCallConv;
3272
3273     if (bIsVarArg && m_callConv != pmCallConvCdecl)
3274         SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
3275 }
3276
3277 void PInvokeStaticSigInfo::ReportErrors()
3278 {
3279     CONTRACTL
3280     {
3281         THROWS;
3282         GC_NOTRIGGER;
3283         MODE_ANY;
3284     }
3285     CONTRACTL_END;
3286
3287     if (m_error != 0)
3288         COMPlusThrow(kTypeLoadException, m_error);      
3289 }
3290
3291
3292 //---------------------------------------------------------
3293 // Does a class or method have a NAT_L CustomAttribute?
3294 //
3295 // S_OK    = yes
3296 // S_FALSE = no
3297 // FAILED  = unknown because something failed.
3298 //---------------------------------------------------------
3299 /*static*/
3300 HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs)
3301 {
3302     CONTRACTL
3303     {
3304         NOTHROW;
3305         GC_NOTRIGGER;
3306         MODE_ANY;
3307
3308         PRECONDITION(CheckPointer(pInternalImport));
3309         PRECONDITION(TypeFromToken(token) == mdtMethodDef);
3310     }
3311     CONTRACTL_END;
3312
3313     // Check method flags first before trying to find the custom value
3314     if (!IsReallyMdPinvokeImpl(dwMemberAttrs))
3315         return S_FALSE;
3316
3317     DWORD   mappingFlags;
3318     LPCSTR  pszImportName;
3319     mdModuleRef modref;
3320
3321     if (SUCCEEDED(pInternalImport->GetPinvokeMap(token, &mappingFlags, &pszImportName, &modref)))
3322         return S_OK;
3323
3324     return S_FALSE;
3325 }
3326
3327
3328 // Either MD or signature & module must be given.
3329 /*static*/
3330 BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*/, Module *pModule /*= NULL*/)
3331 {
3332     CONTRACTL
3333     {
3334         STANDARD_VM_CHECK;
3335         PRECONDITION(pMD != NULL || (pSig != NULL && pModule != NULL));
3336     }
3337     CONTRACTL_END;
3338
3339     // As a by-product, when returning FALSE we will also set the native stack size to the MD if it's
3340     // an NDirectMethodDesc. This number is needed to link the P/Invoke (it determines the @n entry
3341     // point name suffix and affects alignment thunk generation on the Mac). If this method returns
3342     // TRUE, the stack size will be set when building the marshaling IL stub.
3343     DWORD dwStackSize = 0;
3344     CorPinvokeMap callConv = (CorPinvokeMap)0;
3345
3346     if (pMD != NULL)
3347     {
3348         if (pMD->IsNDirect() || pMD->IsComPlusCall())
3349         {
3350             // HRESULT swapping is handled by stub
3351             if ((pMD->GetImplAttrs() & miPreserveSig) == 0)
3352                 return TRUE;
3353         }
3354
3355         // SetLastError is handled by stub
3356         PInvokeStaticSigInfo sigInfo(pMD);
3357         if (sigInfo.GetLinkFlags() & nlfLastError)
3358             return TRUE;
3359
3360         // LCID argument is handled by stub
3361         if (GetLCIDParameterIndex(pMD) != -1)
3362             return TRUE;
3363
3364         // making sure that cctor has run may be handled by stub
3365         if (pMD->IsNDirect() && ((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
3366             return TRUE;
3367
3368         callConv = sigInfo.GetCallConv();
3369     }
3370
3371     if (pSig == NULL)
3372     {
3373         PREFIX_ASSUME(pMD != NULL);
3374
3375         pSig = pMD->GetSig();
3376         pModule = pMD->GetModule();
3377     }
3378
3379     // Check to make certain that the signature only contains types that marshal trivially
3380     SigPointer ptr(pSig);
3381     IfFailThrow(ptr.GetCallingConvInfo(NULL));
3382     ULONG numArgs;
3383     IfFailThrow(ptr.GetData(&numArgs));
3384     numArgs++;   // +1 for return type
3385
3386     // We'll need to parse parameter native types
3387     mdParamDef *pParamTokenArray = (mdParamDef *)_alloca(numArgs * sizeof(mdParamDef));
3388     IMDInternalImport *pMDImport = pModule->GetMDImport();
3389
3390     SigTypeContext emptyTypeContext;
3391
3392     mdMethodDef methodToken = mdMethodDefNil;
3393     if (pMD != NULL)
3394     {
3395         methodToken = pMD->GetMemberDef();
3396     }
3397     CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
3398
3399     for (ULONG i = 0; i < numArgs; i++)
3400     {
3401         SigPointer arg = ptr;
3402         CorElementType type;
3403         IfFailThrow(arg.PeekElemType(&type));
3404
3405         switch (type)
3406         {
3407             case ELEMENT_TYPE_PTR:
3408             {
3409                 IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR
3410                 IfFailThrow(arg.PeekElemType(&type));
3411
3412                 if (type == ELEMENT_TYPE_VALUETYPE)
3413                 {
3414                     if ((arg.HasCustomModifier(pModule,
3415                                               "Microsoft.VisualC.NeedsCopyConstructorModifier",
3416                                               ELEMENT_TYPE_CMOD_REQD)) ||
3417                         (arg.HasCustomModifier(pModule,
3418                                               "System.Runtime.CompilerServices.IsCopyConstructed",
3419                                               ELEMENT_TYPE_CMOD_REQD)))
3420                     {
3421                         return TRUE;
3422                     }
3423                 }
3424                 if (i > 0) dwStackSize += sizeof(SLOT);
3425                 break;
3426             }
3427
3428             case ELEMENT_TYPE_INTERNAL:
3429
3430                 // this check is not functional in DAC and provides no security against a malicious dump
3431                 // the DAC is prepared to receive an invalid type handle
3432 #ifndef DACCESS_COMPILE
3433                 if (pModule->IsSigInIL(arg.GetPtr()))
3434                     THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
3435 #endif
3436
3437                 /* Fall thru */
3438
3439             case ELEMENT_TYPE_VALUETYPE:
3440             {
3441                 TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext);
3442
3443                 // JIT can handle internal blittable value types
3444                 if (!hndArgType.IsBlittable() && !hndArgType.IsEnum())
3445                 {
3446                     return TRUE;
3447                 }
3448
3449                 // return value is fine as long as it can be normalized to an integer
3450                 if (i == 0)
3451                 {
3452                     CorElementType normalizedType = hndArgType.GetInternalCorElementType();
3453                     if (normalizedType == ELEMENT_TYPE_VALUETYPE)
3454                     {
3455                         // it is a structure even after normalization
3456                         return TRUE;
3457                     }
3458                 }
3459                 else
3460                 {
3461                     dwStackSize += StackElemSize(hndArgType.GetSize());
3462                 }
3463                 break;
3464             }
3465             
3466             case ELEMENT_TYPE_BOOLEAN:
3467             case ELEMENT_TYPE_CHAR:
3468             {
3469                 // Bool requires marshaling
3470                 // Char may require marshaling (MARSHAL_TYPE_ANSICHAR)
3471                 return TRUE;
3472             }
3473
3474             default:
3475             {
3476                 if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
3477                 {
3478                     if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
3479                 }
3480                 else
3481                 {
3482                     // other non-primitive type - requires marshaling
3483                     return TRUE;
3484                 }
3485             }
3486         }
3487
3488         // check for explicit MarshalAs
3489         NativeTypeParamInfo paramInfo;
3490
3491         if (pParamTokenArray[i] != mdParamDefNil)
3492         {
3493             if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, &paramInfo) ||
3494                 paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT)
3495             {
3496                 // Presence of MarshalAs does not necessitate marshaling (it could as well be the default
3497                 // for the type), but it's a good enough heuristic. We definitely don't want to duplicate
3498                 // the logic from code:MarshalInfo.MarshalInfo here.
3499                 return TRUE;
3500             }
3501         }
3502
3503         IfFailThrow(ptr.SkipExactlyOne());
3504     }
3505
3506     if (!FitsInU2(dwStackSize))
3507         return TRUE;
3508
3509     // do not set the stack size for varargs - the number is call site specific
3510     if (pMD != NULL && !pMD->IsVarArg())
3511     {
3512         if (pMD->IsNDirect())
3513         {
3514             ((NDirectMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize), callConv);
3515         }
3516 #ifdef FEATURE_COMINTEROP
3517         else if (pMD->IsComPlusCall())
3518         {
3519             // calling convention is always stdcall
3520             ((ComPlusCallMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize));
3521         }
3522 #endif // FEATURE_COMINTEROP
3523     }
3524
3525     return FALSE;
3526 }
3527
3528
3529 // factorization of CreateNDirectStubWorker
3530 static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig&           msig,
3531                                                      mdParamDef*        params,
3532                                                      CorNativeLinkType  nlType,
3533                                                      CorNativeLinkFlags nlFlags,
3534                                                      UINT               argidx,  // this is used for reverse pinvoke hresult swapping
3535                                                      StubState*         pss,
3536                                                      BOOL               fThisCall,
3537                                                      int                argOffset,
3538                                                      DWORD              dwStubFlags,
3539                                                      MethodDesc         *pMD,
3540                                                      UINT&              nativeStackOffset,
3541                                                      bool&              fStubNeedsCOM,
3542                                                      int                nativeArgIndex
3543                                                      DEBUG_ARG(LPCUTF8  pDebugName)
3544                                                      DEBUG_ARG(LPCUTF8  pDebugClassName)
3545                                                      )
3546 {
3547     CONTRACTL
3548     {
3549         STANDARD_VM_CHECK;
3550
3551         PRECONDITION(CheckPointer(params));
3552         PRECONDITION(CheckPointer(pss));
3553         PRECONDITION(CheckPointer(pMD, NULL_OK));
3554     }
3555     CONTRACTL_END;
3556
3557     MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3558
3559     MarshalInfo::MarshalScenario ms;
3560 #ifdef FEATURE_COMINTEROP
3561     if (SF_IsCOMStub(dwStubFlags))
3562     {
3563         if (SF_IsWinRTStub(dwStubFlags))
3564             ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3565         else
3566             ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3567     }
3568     else
3569 #endif // FEATURE_COMINTEROP
3570     {
3571         ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
3572     }
3573
3574 #ifdef FEATURE_COMINTEROP
3575     if (SF_IsWinRTCtorStub(dwStubFlags))
3576     {
3577         _ASSERTE(msig.GetReturnType() == ELEMENT_TYPE_VOID);
3578         _ASSERTE(SF_IsHRESULTSwapping(dwStubFlags));
3579         
3580         pss->MarshalFactoryReturn();
3581         nativeStackOffset += sizeof(LPVOID);
3582         if (SF_IsWinRTCompositionStub(dwStubFlags))
3583         {
3584             nativeStackOffset += 2 * sizeof(LPVOID);
3585         }
3586     }
3587     else
3588 #endif // FEATURE_COMINTEROP
3589     if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
3590     {
3591         MarshalInfo returnInfo(msig.GetModule(),
3592                                 msig.GetReturnProps(),
3593                                 msig.GetSigTypeContext(),
3594                                 params[0],
3595                                 ms,
3596                                 nlType,
3597                                 nlFlags,
3598                                 FALSE,
3599                                 argidx,
3600                                 msig.NumFixedArgs(),
3601                                 SF_IsBestFit(dwStubFlags),
3602                                 SF_IsThrowOnUnmappableChar(dwStubFlags),
3603                                 TRUE,
3604                                 pMD,
3605                                 TRUE
3606                                 DEBUG_ARG(pDebugName)
3607                                 DEBUG_ARG(pDebugClassName)
3608                                 DEBUG_ARG(0)
3609                                 );
3610
3611         marshalType = returnInfo.GetMarshalType();
3612
3613         fStubNeedsCOM |= returnInfo.MarshalerRequiresCOM();
3614
3615 #ifdef FEATURE_COMINTEROP
3616         if (marshalType == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3617         {
3618             // Hidden length arrays are only valid with HRESULT swapping
3619             if (!SF_IsHRESULTSwapping(dwStubFlags))
3620             {
3621                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3622             }
3623
3624             // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3625             returnInfo.SetHiddenLengthParamIndex(static_cast<UINT16>(nativeArgIndex));
3626
3627             // Inject the hidden argument so that it winds up at the end of the method signature
3628             pss->MarshalHiddenLengthArgument(&returnInfo, TRUE);
3629             nativeStackOffset += returnInfo.GetHiddenLengthParamStackSize();
3630
3631             if (SF_IsReverseStub(dwStubFlags))
3632             {
3633                 ++argOffset;
3634             }
3635         }
3636
3637         if (SF_IsCOMStub(dwStubFlags))
3638         {
3639             if (marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS ||
3640                 marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3641                 marshalType == MarshalInfo::MARSHAL_TYPE_GUID ||
3642                 marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL)
3643             {
3644 #ifndef _TARGET_X86_
3645                 // We cannot optimize marshalType to MARSHAL_TYPE_GENERIC_* because the JIT works with exact types
3646                 // and would refuse to compile the stub if it implicitly converted between scalars and value types (also see
3647                 // code:MarshalInfo.MarhalInfo where we do the optimization on x86). We want to throw only if the structure
3648                 // is too big to be returned in registers.
3649                 if (marshalType != MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3650                     IsUnmanagedValueTypeReturnedByRef(returnInfo.GetNativeArgSize()))
3651 #endif // _TARGET_X86_
3652                 {
3653                     if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3654                     {
3655                         // Note that this limitation is very likely not needed anymore and could be lifted if we care.
3656                         COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3657                     }
3658                 }
3659
3660                 pss->MarshalReturn(&returnInfo, argOffset);
3661             }
3662             else
3663             {
3664                 // We don't support native methods that return VARIANTs directly.
3665                 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT)
3666                 {
3667                     if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3668                     {
3669                         COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3670                     }
3671                 }
3672
3673                 pss->MarshalReturn(&returnInfo, argOffset);
3674             }
3675         }
3676         else
3677 #endif // FEATURE_COMINTEROP
3678         {
3679             if (marshalType > MarshalInfo::MARSHAL_TYPE_DOUBLE && IsUnsupportedValueTypeReturn(msig))
3680             {
3681                 if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
3682                         || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
3683                         || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
3684 #ifdef FEATURE_COMINTEROP                    
3685                         || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
3686 #endif // FEATURE_COMINTEROP
3687                    )
3688                 {
3689                     if (SF_IsHRESULTSwapping(dwStubFlags))
3690                     {
3691                         // V1 restriction: we could implement this but it's late in the game to do so.
3692                         COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3693                     }
3694                 }
3695                 else if (marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF)
3696                 {
3697                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION);
3698                 }
3699                 else
3700                 {
3701                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3702                 }
3703             }
3704
3705 #ifdef FEATURE_COMINTEROP
3706             if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
3707             {
3708                 // No support for returning variants. This is a V1 restriction, due to the late date,
3709                 // don't want to add the special-case code to support this in light of low demand.
3710                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NOVARIANTRETURN);
3711             }
3712 #endif // FEATURE_COMINTEROP
3713
3714             pss->MarshalReturn(&returnInfo, argOffset);
3715         }
3716     }
3717
3718     return marshalType;
3719 }
3720
3721 static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
3722 {
3723     LIMITED_METHOD_CONTRACT;
3724 #ifdef _TARGET_X86_
3725     if (fThisCall)
3726     {
3727         // -1 means that the argument is not on the stack
3728         return (stackSize >= sizeof(SLOT) ? (stackSize - sizeof(SLOT)) : (UINT)-1);
3729     }
3730 #endif // _TARGET_X86_
3731     return stackSize;
3732 }
3733
3734 #ifdef FEATURE_COMINTEROP
3735
3736 struct HiddenParameterInfo
3737 {
3738     MarshalInfo *pManagedParam;     // Managed parameter which required the hidden parameter
3739     int          nativeIndex;       // 0 based index into the native method signature where the hidden parameter should be injected
3740 };
3741
3742 // Get the indexes of any hidden length parameters to be marshaled for the method
3743 //
3744 // At return, each value in the ppParamIndexes array is a 0 based index into the native method signature where
3745 // the length parameter for a hidden length array should be passed.  The MarshalInfo objects will also be
3746 // updated such that they all have explicit marshaling information.
3747 //
3748 // The caller is responsible for freeing the memory pointed to by ppParamIndexes
3749 void CheckForHiddenParameters(DWORD cParamMarshalInfo,
3750                               __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo,
3751                               __out DWORD *pcHiddenNativeParameters,
3752                               __out HiddenParameterInfo **ppHiddenNativeParameters)
3753 {
3754     CONTRACTL
3755     {
3756         STANDARD_VM_CHECK;
3757         PRECONDITION(CheckPointer(pParamMarshalInfo));
3758         PRECONDITION(CheckPointer(pcHiddenNativeParameters));
3759         PRECONDITION(CheckPointer(ppHiddenNativeParameters));
3760     }
3761     CONTRACTL_END;
3762
3763     NewArrayHolder<HiddenParameterInfo> hiddenParamInfo(new HiddenParameterInfo[cParamMarshalInfo]);
3764     DWORD foundInfoCount = 0;
3765
3766     for (DWORD iParam = 0; iParam < cParamMarshalInfo; ++iParam)
3767     {
3768         // Look for hidden length arrays, which all require additional parameters to be added
3769         if (pParamMarshalInfo[iParam].GetMarshalType() == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3770         {
3771             DWORD currentNativeIndex = iParam + foundInfoCount;
3772
3773             // The location of the length parameter is implicitly just before the array pointer.
3774             // We'll give it our current index, and bumping the found count will push us back a slot.
3775
3776             // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3777             pParamMarshalInfo[iParam].SetHiddenLengthParamIndex(static_cast<UINT16>(currentNativeIndex));
3778
3779             hiddenParamInfo[foundInfoCount].nativeIndex = pParamMarshalInfo[iParam].HiddenLengthParamIndex();
3780             hiddenParamInfo[foundInfoCount].pManagedParam = &(pParamMarshalInfo[iParam]);
3781             ++foundInfoCount;
3782         }
3783     }
3784
3785     *pcHiddenNativeParameters = foundInfoCount;
3786     *ppHiddenNativeParameters = hiddenParamInfo.Extract();
3787 }
3788
3789 bool IsHiddenParameter(int nativeArgIndex,
3790                        DWORD cHiddenParameters,
3791                        __in_ecount(cHiddenParameters) HiddenParameterInfo *pHiddenParameters,
3792                        __out HiddenParameterInfo **ppHiddenParameterInfo)
3793 {
3794     CONTRACTL
3795     {
3796         STANDARD_VM_CHECK;
3797         PRECONDITION(cHiddenParameters == 0 || CheckPointer(pHiddenParameters));
3798         PRECONDITION(CheckPointer(ppHiddenParameterInfo));
3799     }
3800     CONTRACTL_END;
3801
3802     *ppHiddenParameterInfo = NULL;
3803
3804     for (DWORD i = 0; i < cHiddenParameters; ++i)
3805     {
3806         _ASSERTE(pHiddenParameters[i].nativeIndex != -1);
3807         if (pHiddenParameters[i].nativeIndex == nativeArgIndex)
3808         {
3809             *ppHiddenParameterInfo = &(pHiddenParameters[i]);
3810             return true;
3811         }
3812     }
3813
3814     return false;
3815 }
3816
3817 #endif // FEATURE_COMINTEROP
3818
3819 //---------------------------------------------------------
3820 // Creates a new stub for a N/Direct call. Return refcount is 1.
3821 // Note that this function may now throw if it fails to create
3822 // a stub.
3823 //---------------------------------------------------------
3824 static void CreateNDirectStubWorker(StubState*         pss,
3825                                     StubSigDesc*       pSigDesc,
3826                                     CorNativeLinkType  nlType,
3827                                     CorNativeLinkFlags nlFlags,
3828                                     CorPinvokeMap      unmgdCallConv,
3829                                     DWORD              dwStubFlags,
3830                                     MethodDesc         *pMD,
3831                                     mdParamDef*        pParamTokenArray,
3832                                     int                iLCIDArg
3833                                     )
3834 {
3835     CONTRACTL
3836     {
3837         STANDARD_VM_CHECK;
3838
3839         PRECONDITION(CheckPointer(pss));
3840         PRECONDITION(CheckPointer(pSigDesc));
3841         PRECONDITION(CheckPointer(pMD, NULL_OK));
3842         PRECONDITION(!pMD || pMD->IsILStub() || (0 != pMD->GetMethodTable()->IsDelegate()) == SF_IsDelegateStub(dwStubFlags));
3843     }
3844     CONTRACTL_END;
3845
3846     SF_ConsistencyCheck(dwStubFlags);
3847
3848 #ifdef _DEBUG
3849     if (g_pConfig->ShouldBreakOnInteropStubSetup(pSigDesc->m_pDebugName))
3850         CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName));
3851 #endif // _DEBUG
3852
3853     Stub* pstub = NULL;
3854
3855     if (SF_IsCOMStub(dwStubFlags))
3856     {
3857         _ASSERTE(0 == nlType);
3858         _ASSERTE(0 == nlFlags);
3859         _ASSERTE(0 == unmgdCallConv);
3860     }
3861     else
3862     {
3863         _ASSERTE(nlType == nltAnsi || nlType == nltUnicode);
3864     }
3865     Module *pModule = pSigDesc->m_pModule;
3866
3867     //
3868     // Set up signature walking objects.
3869     //
3870
3871     MetaSig msig(pSigDesc->m_sig, 
3872                  pModule, 
3873                  &pSigDesc->m_typeContext);
3874
3875     if (SF_IsVarArgStub(dwStubFlags))
3876         msig.SetTreatAsVarArg();
3877
3878     bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
3879
3880     pss->SetLastError(nlFlags & nlfLastError);
3881
3882     // This has been in the product since forward P/Invoke via delegates was
3883     // introduced. It's wrong, but please keep it for backward compatibility.
3884     if (SF_IsDelegateStub(dwStubFlags))
3885         pss->SetLastError(TRUE);
3886
3887     pss->BeginEmit(dwStubFlags);
3888
3889     if (-1 != iLCIDArg)
3890     {
3891         // LCID is not supported on WinRT
3892         _ASSERTE(!SF_IsWinRTStub(dwStubFlags));
3893
3894         // The code to handle the LCID  will call MarshalLCID before calling MarshalArgument
3895         // on the argument the LCID should go after. So we just bump up the index here.
3896         iLCIDArg++;
3897     }
3898
3899     int numArgs = msig.NumFixedArgs();
3900
3901     // thiscall must have at least one parameter (the "this")
3902     if (fThisCall && numArgs == 0)
3903         COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
3904
3905     //
3906     // Now, emit the IL.
3907     //
3908
3909     int argOffset = 0;
3910
3911     MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3912
3913     //
3914     // Marshal the return value.
3915     //
3916
3917     UINT nativeStackSize = (SF_IsCOMStub(dwStubFlags) ? sizeof(SLOT) : 0);
3918     bool fHasCopyCtorArgs = false;
3919     bool fStubNeedsCOM = SF_IsCOMStub(dwStubFlags);
3920     
3921     // Normally we would like this to be false so that we use the correct signature 
3922     // in the IL_STUB, (i.e if it returns a value class then the signature will use that)
3923     // When this bool is true we change the return type to void and explicitly add a
3924     // return buffer argument as the first argument.
3925     BOOL fMarshalReturnValueFirst = false;
3926     
3927     // We can only change fMarshalReturnValueFirst to true when we are NOT doing HRESULT-swapping!
3928     //
3929     if (!SF_IsHRESULTSwapping(dwStubFlags))
3930     {
3931
3932 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
3933         // JIT32 has problems in generating code for pinvoke ILStubs which do a return in return buffer.
3934         // Therefore instead we change the signature of calli to return void and make the return buffer as first
3935         // argument. This matches the ABI i.e. return buffer is passed as first arg. So native target will get the
3936         // return buffer in correct register.
3937         // The return structure secret arg comes first, however byvalue return is processed at
3938         // the end because it could be the HRESULT-swapped argument which always comes last.
3939         fMarshalReturnValueFirst = HasRetBuffArg(&msig);
3940 #endif
3941
3942     }
3943     
3944     if (fMarshalReturnValueFirst)
3945     {
3946         marshalType = DoMarshalReturnValue(msig,
3947                                            pParamTokenArray,
3948                                            nlType,
3949                                            nlFlags,
3950                                            0,
3951                                            pss,
3952                                            fThisCall,
3953                                            argOffset,
3954                                            dwStubFlags,
3955                                            pMD,
3956                                            nativeStackSize,
3957                                            fStubNeedsCOM,
3958                                            0
3959                                            DEBUG_ARG(pSigDesc->m_pDebugName)
3960                                            DEBUG_ARG(pSigDesc->m_pDebugClassName)
3961                                            );
3962
3963         if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE ||
3964             marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY ||
3965             marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET ||
3966             marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF ||
3967             marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
3968 #ifdef FEATURE_COMINTEROP
3969          || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
3970 #endif // FEATURE_COMINTEROP
3971             )
3972         {
3973             // These are special non-blittable types returned by-ref in managed,
3974             // but marshaled as primitive values returned by-value in unmanaged.
3975         }
3976         else
3977         {
3978             // This is an ordinary value type - see if it is returned by-ref.
3979             MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
3980             if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
3981             {
3982                 nativeStackSize += sizeof(LPVOID);
3983             }
3984         }
3985     }
3986
3987     //
3988     // Marshal the arguments
3989     //
3990     MarshalInfo::MarshalScenario ms;
3991 #ifdef FEATURE_COMINTEROP
3992     if (SF_IsCOMStub(dwStubFlags))
3993     {
3994         if (SF_IsWinRTStub(dwStubFlags))
3995             ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3996         else
3997             ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3998     }
3999     else
4000 #endif // FEATURE_COMINTEROP
4001     {
4002         ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
4003     }
4004
4005     // Build up marshaling information for each of the method's parameters
4006     SIZE_T cbParamMarshalInfo;
4007     if (!ClrSafeInt<SIZE_T>::multiply(sizeof(MarshalInfo), numArgs, cbParamMarshalInfo))
4008     {
4009         COMPlusThrowHR(COR_E_OVERFLOW);
4010     }
4011
4012     NewArrayHolder<BYTE> pbParamMarshalInfo(new BYTE[cbParamMarshalInfo]);
4013     MarshalInfo *pParamMarshalInfo = reinterpret_cast<MarshalInfo *>(pbParamMarshalInfo.GetValue());
4014
4015     MetaSig paramInfoMSig(msig);
4016     for (int i = 0; i < numArgs; ++i)
4017     {
4018         paramInfoMSig.NextArg();
4019         new(&(pParamMarshalInfo[i])) MarshalInfo(paramInfoMSig.GetModule(),
4020                                                  paramInfoMSig.GetArgProps(),
4021                                                  paramInfoMSig.GetSigTypeContext(),
4022                                                  pParamTokenArray[i + 1],
4023                                                  ms,
4024                                                  nlType,
4025                                                  nlFlags,
4026                                                  TRUE,
4027                                                  i + 1,
4028                                                  numArgs,
4029                                                  SF_IsBestFit(dwStubFlags),
4030                                                  SF_IsThrowOnUnmappableChar(dwStubFlags),
4031                                                  TRUE,
4032                                                  pMD,
4033                                                  TRUE
4034                                                  DEBUG_ARG(pSigDesc->m_pDebugName)
4035                                                  DEBUG_ARG(pSigDesc->m_pDebugClassName)
4036                                                  DEBUG_ARG(i + 1));
4037     }
4038
4039 #ifdef FEATURE_COMINTEROP
4040     // Check to see if we need to inject any additional hidden parameters
4041     DWORD cHiddenNativeParameters;
4042     NewArrayHolder<HiddenParameterInfo> pHiddenNativeParameters;
4043     CheckForHiddenParameters(numArgs, pParamMarshalInfo, &cHiddenNativeParameters, &pHiddenNativeParameters);
4044
4045     // Hidden parameters and LCID do not mix
4046     _ASSERTE(!(cHiddenNativeParameters > 0 && iLCIDArg != -1));
4047 #endif // FEATURE_COMINTEROP
4048
4049     // Marshal the parameters
4050     int argidx = 1;
4051     int nativeArgIndex = 0;
4052     while (argidx <= numArgs)
4053     {
4054 #ifdef FEATURE_COMINTEROP
4055         HiddenParameterInfo *pHiddenParameter;
4056         // Check to see if we need to inject a hidden parameter
4057         if (IsHiddenParameter(nativeArgIndex, cHiddenNativeParameters, pHiddenNativeParameters, &pHiddenParameter))
4058         {
4059             pss->MarshalHiddenLengthArgument(pHiddenParameter->pManagedParam, FALSE);
4060             nativeStackSize += pHiddenParameter->pManagedParam->GetHiddenLengthParamStackSize();
4061
4062             if (SF_IsReverseStub(dwStubFlags))
4063             {
4064                 ++argOffset;
4065             }
4066         }
4067         else
4068 #endif // FEATURE_COMINTEROP
4069         {
4070             //
4071             // Check to see if this is the parameter after which we need to insert the LCID.
4072             //
4073             if (argidx == iLCIDArg)
4074             {
4075                 pss->MarshalLCID(argidx);
4076                 nativeStackSize += sizeof(LPVOID);
4077
4078                 if (SF_IsReverseStub(dwStubFlags))
4079                     argOffset++;
4080             }
4081
4082             msig.NextArg();
4083
4084             MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4085
4086 #ifdef FEATURE_COMINTEROP
4087             // For the hidden-length array, length parameters must occur before the parameter containing the array pointer
4088             _ASSERTE(info.GetMarshalType() != MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY || nativeArgIndex > info.HiddenLengthParamIndex());
4089 #endif // FEATURE_COMINTEROP
4090
4091             pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4092             nativeStackSize += info.GetNativeArgSize();
4093
4094             fStubNeedsCOM |= info.MarshalerRequiresCOM();
4095
4096             if (fThisCall && argidx == 1)
4097             {
4098                 // make sure that the first parameter is enregisterable
4099                 if (info.GetNativeArgSize() > sizeof(SLOT))
4100                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4101             }
4102
4103
4104             argidx++;
4105         }
4106         
4107         ++nativeArgIndex;
4108     }
4109
4110     // Check to see if this is the parameter after which we need to insert the LCID.
4111     if (argidx == iLCIDArg)
4112     {
4113         pss->MarshalLCID(argidx);
4114         nativeStackSize += sizeof(LPVOID);
4115
4116         if (SF_IsReverseStub(dwStubFlags))
4117             argOffset++;
4118     }
4119
4120     if (!fMarshalReturnValueFirst)
4121     {
4122         // This could be a HRESULT-swapped argument so it must come last.
4123         marshalType = DoMarshalReturnValue(msig,
4124                              pParamTokenArray,
4125                              nlType,
4126                              nlFlags,
4127                              argidx,
4128                              pss,
4129                              fThisCall,
4130                              argOffset,
4131                              dwStubFlags,
4132                              pMD,
4133                              nativeStackSize,
4134                              fStubNeedsCOM,
4135                              nativeArgIndex
4136                              DEBUG_ARG(pSigDesc->m_pDebugName)
4137                              DEBUG_ARG(pSigDesc->m_pDebugClassName)
4138                              );
4139
4140         // If the return value is a SafeHandle or CriticalHandle, mark the stub method.
4141         // Interop methods that use this stub will have an implicit reliability contract
4142         // (see code:TAStackCrawlCallBack).
4143         if (!SF_IsHRESULTSwapping(dwStubFlags))
4144         {
4145             if (marshalType == MarshalInfo::MARSHAL_TYPE_SAFEHANDLE ||
4146                 marshalType == MarshalInfo::MARSHAL_TYPE_CRITICALHANDLE)
4147             {
4148                 if (pMD->IsDynamicMethod())
4149                     pMD->AsDynamicMethodDesc()->SetUnbreakable(true);
4150             }
4151         }
4152     }
4153
4154     if (SF_IsHRESULTSwapping(dwStubFlags))
4155     {
4156         if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
4157             nativeStackSize += sizeof(LPVOID);
4158     }
4159
4160     if (pMD->IsDynamicMethod())
4161     {
4162         // Set the native stack size to the IL stub MD. It is needed for alignment
4163         // thunk generation on the Mac and stdcall name decoration on Windows.
4164         // We do not store it directly in the interop MethodDesc here because due 
4165         // to sharing we come here only for the first call with given signature and 
4166         // the target MD may even be NULL.
4167
4168 #ifdef _TARGET_X86_
4169         if (fThisCall)
4170         {
4171             _ASSERTE(nativeStackSize >= sizeof(SLOT));
4172             nativeStackSize -= sizeof(SLOT);
4173         }
4174 #else // _TARGET_X86_
4175         //
4176         // The algorithm to compute nativeStackSize on the fly is x86-specific.
4177         // Recompute the correct size for other platforms from the stub signature.
4178         //
4179         if (SF_IsForwardStub(dwStubFlags))
4180         {
4181             // It would be nice to compute the correct value for forward stubs too.
4182             // The value is only used in MarshalNative::NumParamBytes right now,
4183             // and changing what MarshalNative::NumParamBytes returns is 
4184             // a potential breaking change.
4185         }
4186         else
4187         {
4188             // native stack size is updated in code:ILStubState.SwapStubSignatures
4189         }
4190 #endif // _TARGET_X86_
4191
4192         if (!FitsInU2(nativeStackSize))
4193             COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
4194
4195         DynamicMethodDesc *pDMD = pMD->AsDynamicMethodDesc();
4196
4197         pDMD->SetNativeStackArgSize(static_cast<WORD>(nativeStackSize));
4198         pDMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
4199         pDMD->SetStubNeedsCOMStarted(fStubNeedsCOM);
4200     }
4201
4202     // FinishEmit needs to know the native stack arg size so we call it after the number
4203     // has been set in the stub MD (code:DynamicMethodDesc.SetNativeStackArgSize)
4204     pss->FinishEmit(pMD);
4205 }
4206
4207 class NDirectStubHashBlob : public ILStubHashBlobBase
4208 {
4209 public:
4210     Module*     m_pModule;
4211
4212     WORD        m_unmgdCallConv;
4213     BYTE        m_nlType;                   // C_ASSERTS are in NDirect::CreateHashBlob
4214     BYTE        m_nlFlags;
4215
4216     DWORD       m_StubFlags;
4217
4218     INT32       m_iLCIDArg;
4219     INT32       m_nParams;
4220     BYTE        m_rgbSigAndParamData[1];
4221     // (dwParamAttr, cbNativeType)          // length: number of parameters
4222     // NativeTypeBlob                       // length: number of parameters
4223     // BYTE     m_rgbSigData[];             // length: determined by sig walk
4224 };
4225
4226 // For better performance and less memory fragmentation,
4227 // I'm using structure here to avoid allocating 3 different arrays.
4228 struct ParamInfo
4229 {
4230     DWORD dwParamAttr;
4231     ULONG cbNativeType;
4232     PCCOR_SIGNATURE pvNativeType;
4233 };  
4234
4235 ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams)
4236 {
4237     STANDARD_VM_CONTRACT;
4238
4239     NDirectStubHashBlob*    pBlob;
4240
4241     IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport();
4242
4243     CQuickBytes paramInfoBytes;
4244     paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens);
4245     ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr();
4246     ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens);
4247
4248     size_t cbNativeTypeTotal = 0;
4249     
4250     //
4251     // Collect information for function parameters
4252     //     
4253     for (int idx = 0; idx < pParams->m_nParamTokens; idx++)
4254     {
4255         mdParamDef token = pParams->m_pParamTokenArray[idx];
4256         if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token)
4257         {
4258             USHORT usSequence_Ignore;       // We don't need usSequence in the hash as the param array is already sorted
4259             LPCSTR szParamName_Ignore;
4260             IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, &paramInfos[idx].dwParamAttr, &szParamName_Ignore));
4261
4262             if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal)
4263             {
4264                 IfFailThrow(pInternalImport->GetFieldMarshal(token, &paramInfos[idx].pvNativeType, &paramInfos[idx].cbNativeType));
4265                 cbNativeTypeTotal += paramInfos[idx].cbNativeType;
4266             }
4267         }
4268     }
4269
4270     SigPointer sigPtr = pParams->m_sig.CreateSigPointer();
4271     
4272     // note that ConvertToInternalSignature also resolves generics so different instantiations will get different
4273     // hash blobs for methods that have generic parameters in their signature
4274     SigBuilder sigBuilder;
4275     sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE);
4276
4277     DWORD cbSig;
4278     PVOID pSig = sigBuilder.GetSignature(&cbSig);
4279
4280     //
4281     // Build hash blob for IL stub sharing
4282     //
4283     S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) +
4284                             S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) +   // Parameter attributes
4285                             S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) +   // Native type blob size
4286                             S_SIZE_T(cbNativeTypeTotal) +                                   // Native type blob data
4287                             S_SIZE_T(cbSig);                                                // Signature
4288                             
4289     if (cbSizeOfBlob.IsOverflow())
4290         COMPlusThrowHR(COR_E_OVERFLOW);
4291
4292     static_assert_no_msg(nltMaxValue   <= 0xFF);
4293     static_assert_no_msg(nlfMaxValue   <= 0xFF);
4294     static_assert_no_msg(pmMaxValue    <= 0xFFFF);
4295
4296     NewArrayHolder<BYTE> pBytes = new BYTE[cbSizeOfBlob.Value()];
4297     // zero out the hash bytes to ensure all bit fields are deterministically set
4298     ZeroMemory(pBytes, cbSizeOfBlob.Value());
4299     pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes;
4300
4301     pBlob->m_pModule                = NULL;
4302
4303     if (SF_IsNGENedStub(pParams->m_dwStubFlags))
4304     {
4305         // don't share across modules if we are ngening the stub
4306         pBlob->m_pModule = pParams->m_pModule;
4307     }
4308
4309     pBlob->m_cbSizeOfBlob           = cbSizeOfBlob.Value();
4310     pBlob->m_unmgdCallConv          = static_cast<WORD>(pParams->m_unmgdCallConv);
4311     pBlob->m_nlType                 = static_cast<BYTE>(pParams->m_nlType);
4312     pBlob->m_nlFlags                = static_cast<BYTE>(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub
4313     pBlob->m_iLCIDArg               = pParams->m_iLCIDArg;
4314
4315     pBlob->m_StubFlags              = pParams->m_dwStubFlags;
4316     pBlob->m_nParams                = pParams->m_nParamTokens;
4317
4318     BYTE* pBlobParams               = &pBlob->m_rgbSigAndParamData[0];
4319
4320     //
4321     // Write (dwParamAttr, cbNativeType) for parameters
4322     //
4323     // Note that these need to be aligned and it is why they are written before the byte blobs
4324     // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs
4325     //
4326     _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0);
4327     _ASSERTE(sizeof(DWORD) == sizeof(ULONG));
4328     
4329     for (int i = 0; i < pParams->m_nParamTokens; ++i)
4330     {
4331         // We only care about In/Out/HasFieldMarshal
4332         // Other attr are about optional/default values which are not used in marshalling,
4333         // but only used in compilers        
4334         *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal);
4335         pBlobParams += sizeof(DWORD);
4336
4337         *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType;
4338         pBlobParams += sizeof(ULONG);
4339     }
4340
4341     //
4342     // Write native type blob for parameters
4343     //
4344     for (int i = 0; i < pParams->m_nParamTokens; ++i)
4345     {
4346         memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType);
4347         pBlobParams += paramInfos[i].cbNativeType;
4348     }
4349     
4350     //
4351     // Copy signature
4352     // 
4353     memcpy(pBlobParams, pSig, cbSig);
4354
4355     // Verify that we indeed have reached the end
4356     _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value());
4357
4358     pBytes.SuppressRelease();
4359     return (ILStubHashBlob*)pBlob;
4360 }
4361
4362 // static inline
4363 ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams)
4364 {
4365     CONTRACTL
4366     {
4367         THROWS;
4368         GC_NOTRIGGER;
4369         MODE_ANY;
4370     }
4371     CONTRACTL_END;
4372
4373     // Use the m_pLoaderModule instead of m_pModule
4374     // They could be different for methods on generic types.
4375     return pParams->m_pLoaderModule->GetILStubCache();
4376 }
4377
4378 // static
4379 MethodDesc* NDirect::GetStubMethodDesc(
4380     MethodDesc *pTargetMD,
4381     NDirectStubParameters* pParams,
4382     ILStubHashBlob* pHashParams,
4383     AllocMemTracker* pamTracker,
4384     bool& bILStubCreator,
4385     MethodDesc* pLastMD)
4386 {
4387     CONTRACT(MethodDesc*)
4388     {
4389         STANDARD_VM_CHECK;
4390
4391         PRECONDITION(CheckPointer(pParams));
4392         PRECONDITION(!pParams->m_sig.IsEmpty());
4393         PRECONDITION(CheckPointer(pParams->m_pModule));
4394         PRECONDITION(CheckPointer(pTargetMD, NULL_OK));
4395         POSTCONDITION(CheckPointer(RETVAL));
4396     }
4397     CONTRACT_END;
4398
4399     MethodDesc*     pMD;
4400
4401     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4402
4403     pMD = pCache->GetStubMethodDesc(pTargetMD,
4404                                     pHashParams, 
4405                                     pParams->m_dwStubFlags, 
4406                                     pParams->m_pModule, 
4407                                     pParams->m_sig.GetRawSig(),
4408                                     pParams->m_sig.GetRawSigLen(),
4409                                     pamTracker,
4410                                     bILStubCreator,
4411                                     pLastMD);
4412
4413     RETURN pMD;
4414 }
4415
4416
4417 // static
4418 void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams)
4419 {
4420     CONTRACTL
4421     {
4422         STANDARD_VM_CHECK;
4423
4424         PRECONDITION(CheckPointer(pParams));
4425         PRECONDITION(CheckPointer(pHashParams));
4426         PRECONDITION(!pParams->m_sig.IsEmpty());
4427         PRECONDITION(CheckPointer(pParams->m_pModule));
4428     }
4429     CONTRACTL_END;
4430
4431     LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams));
4432
4433     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4434
4435     pCache->DeleteEntry(pHashParams);
4436 }
4437
4438 // static
4439 void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD)
4440 {
4441     CONTRACTL
4442     {
4443         STANDARD_VM_CHECK;
4444
4445         PRECONDITION(CheckPointer(pParams));
4446         PRECONDITION(!pParams->m_sig.IsEmpty());
4447         PRECONDITION(CheckPointer(pParams->m_pModule));
4448     }
4449     CONTRACTL_END;
4450
4451     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4452
4453     pCache->AddMethodDescChunkWithLockTaken(pMD);
4454 }
4455
4456 //
4457 // Additional factorization of CreateNDirectStub.  This hoists all the metadata accesses
4458 // into one location so that we can leave CreateNDirectStubWorker to just generate the 
4459 // IL.  This allows us to cache a stub based on the inputs to CreateNDirectStubWorker
4460 // instead of having to generate the IL first before doing the caching.
4461 //
4462 void CreateNDirectStubAccessMetadata(StubSigDesc*       pSigDesc,       // IN
4463                                      CorPinvokeMap      unmgdCallConv,  // IN
4464                                      DWORD*             pdwStubFlags,   // IN/OUT
4465                                      int*               piLCIDArg,      // OUT
4466                                      int*               pNumArgs        // OUT
4467                                      )
4468 {
4469     STANDARD_VM_CONTRACT;
4470
4471     if (SF_IsCOMStub(*pdwStubFlags))
4472     {
4473         _ASSERTE(0 == unmgdCallConv);
4474     }
4475     else
4476     {
4477         if (unmgdCallConv != pmCallConvStdcall &&
4478             unmgdCallConv != pmCallConvCdecl &&
4479             unmgdCallConv != pmCallConvThiscall)
4480         {
4481             COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
4482         }
4483     }
4484     
4485 #ifdef FEATURE_COMINTEROP
4486     if (SF_IsDelegateStub(*pdwStubFlags))
4487     {
4488         _ASSERTE(!SF_IsWinRTStub(*pdwStubFlags));
4489         if (pSigDesc->m_pMD->GetMethodTable()->IsProjectedFromWinRT())
4490         {
4491             // We do not allow P/Invoking via WinRT delegates to better segregate WinRT
4492             // from classic interop scenarios.
4493             COMPlusThrow(kMarshalDirectiveException, IDS_EE_DELEGATEPINVOKE_WINRT);
4494         }
4495     }
4496 #endif // FEATURE_COMINTEROP
4497
4498     MetaSig msig(pSigDesc->m_sig, 
4499                  pSigDesc->m_pModule, 
4500                  &pSigDesc->m_typeContext);
4501
4502     if (SF_IsVarArgStub(*pdwStubFlags))
4503         msig.SetTreatAsVarArg();
4504
4505     (*pNumArgs) = msig.NumFixedArgs();
4506     
4507     IMDInternalImport* pInternalImport = pSigDesc->m_pModule->GetMDImport();
4508
4509     _ASSERTE(!SF_IsHRESULTSwapping(*pdwStubFlags));
4510
4511     mdMethodDef md = pSigDesc->m_tkMethodDef;
4512     if (md != mdMethodDefNil)
4513     {
4514         DWORD           dwDescrOffset;
4515         DWORD           dwImplFlags;
4516         IfFailThrow(pInternalImport->GetMethodImplProps(
4517             md, 
4518             &dwDescrOffset, 
4519             &dwImplFlags));
4520         
4521 #ifdef FEATURE_COMINTEROP
4522         if (SF_IsWinRTStub(*pdwStubFlags))
4523         {
4524             // All WinRT methods do HRESULT swapping
4525             if (IsMiPreserveSig(dwImplFlags))
4526             {
4527                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_PRESERVESIG_WINRT);
4528             }
4529
4530             (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4531         }
4532         else
4533 #endif // FEATURE_COMINTEROP
4534         if (SF_IsReverseStub(*pdwStubFlags))
4535         {
4536             // only COM-to-CLR call supports hresult swapping in the reverse direction
4537             if (SF_IsCOMStub(*pdwStubFlags) && !IsMiPreserveSig(dwImplFlags))
4538             {
4539                 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4540             }
4541         }
4542         else
4543         {
4544             // fwd pinvoke, fwd com interop support hresult swapping.
4545             // delegate to an unmanaged method does not.
4546             if (!IsMiPreserveSig(dwImplFlags) && !SF_IsDelegateStub(*pdwStubFlags))
4547             {
4548                 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4549             }
4550         }
4551     }
4552
4553     if (pSigDesc->m_pMD != NULL)
4554     {
4555         (*piLCIDArg) = GetLCIDParameterIndex(pSigDesc->m_pMD);
4556     }
4557     else
4558     {
4559         (*piLCIDArg) = -1;
4560     }
4561
4562     // Check to see if we need to do LCID conversion.
4563     if ((*piLCIDArg) != -1 && (*piLCIDArg) > (*pNumArgs))
4564     {
4565         COMPlusThrow(kIndexOutOfRangeException, IDS_EE_INVALIDLCIDPARAM);
4566     }
4567
4568     if (SF_IsCOMStub(*pdwStubFlags) && !SF_IsWinRTStaticStub(*pdwStubFlags))
4569     {
4570         CONSISTENCY_CHECK(msig.HasThis());
4571     }
4572     else
4573     {
4574         if (msig.HasThis() && !SF_IsDelegateStub(*pdwStubFlags))
4575         {
4576             COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC);
4577         }
4578     }
4579 }
4580
4581 void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError /*= TRUE*/)
4582 {
4583     if (pNMD->IsSynchronized() && throwOnError)
4584         COMPlusThrow(kTypeLoadException, IDS_EE_NOSYNCHRONIZED);
4585
4586     WORD ndirectflags = 0;
4587     if (pNMD->MethodDesc::IsVarArg())
4588         ndirectflags |= NDirectMethodDesc::kVarArgs;
4589
4590     LPCUTF8 szLibName = NULL, szEntryPointName = NULL;
4591     new (pSigInfo) PInvokeStaticSigInfo(pNMD, &szLibName, &szEntryPointName,
4592         (throwOnError ? PInvokeStaticSigInfo::THROW_ON_ERROR : PInvokeStaticSigInfo::NO_THROW_ON_ERROR));
4593
4594     if (pSigInfo->GetCharSet() == nltAnsi)
4595         ndirectflags |= NDirectMethodDesc::kNativeAnsi;
4596
4597     CorNativeLinkFlags linkflags = pSigInfo->GetLinkFlags();    
4598     if (linkflags & nlfLastError)
4599         ndirectflags |= NDirectMethodDesc::kLastError;
4600     if (linkflags & nlfNoMangle)
4601         ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
4602     
4603     CorPinvokeMap callConv = pSigInfo->GetCallConv();
4604     if (callConv == pmCallConvStdcall)
4605         ndirectflags |= NDirectMethodDesc::kStdCall;
4606     if (callConv == pmCallConvThiscall)
4607         ndirectflags |= NDirectMethodDesc::kThisCall;
4608
4609     if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
4610     {
4611         ndirectflags |= NDirectMethodDesc::kIsQCall;
4612     }
4613     else
4614     {
4615         EnsureWritablePages(&pNMD->ndirect);
4616         pNMD->ndirect.m_pszLibName = szLibName;
4617         pNMD->ndirect.m_pszEntrypointName = szEntryPointName;
4618     }
4619
4620 #ifdef _TARGET_X86_
4621     if (ndirectflags & NDirectMethodDesc::kStdCall)
4622     {
4623         // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling.
4624         MetaSig msig(pNMD);
4625         ArgIterator argit(&msig);
4626         if (argit.HasRetBuffArg())
4627         {
4628             MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4629             if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4630             {
4631                 ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf;
4632             }
4633         }
4634     }
4635 #endif // _TARGET_X86_
4636
4637     // Call this exactly ONCE per thread. Do not publish incomplete prestub flags
4638     // or you will introduce a race condition.
4639     pNMD->InterlockedSetNDirectFlags(ndirectflags);
4640 }
4641
4642 #ifdef FEATURE_COMINTEROP
4643 // Find the MethodDesc of the predefined IL stub method by either
4644 // 1) looking at redirected adapter interfaces, OR
4645 // 2) looking at special attributes for the specific interop scenario (specified by dwStubFlags).
4646 // Currently only ManagedToNativeComInteropStubAttribute is supported.
4647 // It returns NULL if no such attribute(s) can be found.  
4648 // But if the attribute is found and is invalid, or something went wrong in the looking up
4649 // process, an exception will be thrown. If everything goes well, you'll get the MethodDesc
4650 // of the stub method
4651 HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD)
4652 {
4653     CONTRACT(HRESULT)
4654     {
4655         THROWS;
4656         GC_TRIGGERS;
4657         MODE_ANY;
4658         PRECONDITION(CheckPointer(pTargetMD));
4659         PRECONDITION(CheckPointer(ppRetStubMD));
4660         PRECONDITION(*ppRetStubMD == NULL);
4661     }
4662     CONTRACT_END;
4663
4664     HRESULT hr;
4665
4666     MethodTable *pTargetMT = pTargetMD->GetMethodTable();
4667
4668     // Check if this is a redirected interface - we have static stubs in mscorlib for those.
4669     if (SF_IsForwardCOMStub(dwStubFlags) && pTargetMT->IsInterface())
4670     {
4671
4672         // Redirect generic redirected interfaces to the corresponding adapter methods in mscorlib
4673         if (pTargetMT->HasInstantiation())
4674         {
4675             MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(pTargetMD, TypeHandle::Interop_ManagedToNative);
4676             if (pAdapterMD != NULL)
4677             {
4678                 *ppRetStubMD = pAdapterMD;
4679                 return S_OK;
4680             }
4681         }
4682     }
4683
4684     //
4685     // Find out if we have the attribute
4686     //    
4687     const void *pBytes;
4688     ULONG cbBytes;
4689
4690     // Support v-table forward classic COM interop calls only
4691     if (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags) && !SF_IsWinRTStub(dwStubFlags))
4692     {
4693         if (pTargetMT->HasInstantiation())
4694         {
4695             // ManagedToNativeComInteropStubAttribute is not supported with generics
4696             return E_FAIL;
4697         }
4698
4699         if (pTargetMD->IsFCall())
4700         {
4701             // ManagedToNativeComInteropStubAttribute is not supported on FCalls (i.e. methods on legacy
4702             // interfaces forwarded to CustomMarshalers.dll such as IEnumerable::GetEnumerator)
4703             return E_FAIL;
4704         }
4705         _ASSERTE(pTargetMD->IsComPlusCall());
4706         
4707         if (pTargetMD->IsInterface())
4708         {
4709             _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
4710             hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
4711                 pTargetMD->GetMemberDef(),
4712                 FORWARD_INTEROP_STUB_METHOD_TYPE,
4713                 &pBytes,
4714                 &cbBytes);
4715                 
4716             if (FAILED(hr)) 
4717                 RETURN hr;
4718             // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
4719             // Translate that to E_FAIL
4720             else if (hr == S_FALSE)
4721                 RETURN E_FAIL;               
4722         }
4723         else
4724         {
4725             // We are dealing with the class, use the interface MD instead
4726             // After second thought I believe we don't need to check the class MD.
4727             // We can think stubs as part of public interface, and if the interface is public,
4728             // the stubs should also be accessible
4729             MethodDesc *pInterfaceMD = pTargetMD->GetInterfaceMD();
4730             if (pInterfaceMD)
4731             {
4732                 hr = FindPredefinedILStubMethod(pInterfaceMD, dwStubFlags, ppRetStubMD);
4733                 RETURN hr;
4734             }
4735             else
4736                 RETURN E_FAIL;
4737         }
4738     }
4739     else
4740         RETURN E_FAIL;
4741         
4742     //
4743     // Parse the attribute
4744     //
4745     CustomAttributeParser parser(pBytes, cbBytes);
4746     IfFailRet(parser.SkipProlog());
4747
4748     LPCUTF8 pTypeName;
4749     ULONG cbTypeName;
4750     IfFailRet(parser.GetNonEmptyString(&pTypeName, &cbTypeName));
4751
4752     LPCUTF8 pMethodName;
4753     ULONG cbMethodName;
4754     IfFailRet(parser.GetNonEmptyString(&pMethodName, &cbMethodName));
4755
4756     StackSString typeName(SString::Utf8, pTypeName, cbTypeName);
4757     StackSString methodName(SString::Utf8, pMethodName, cbMethodName);
4758
4759     //
4760     // Retrieve the type
4761     //
4762     TypeHandle stubClassType;
4763     stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
4764
4765     MethodTable *pStubClassMT = stubClassType.AsMethodTable();
4766
4767     StackSString stubClassName;
4768     pStubClassMT->_GetFullyQualifiedNameForClassNestedAware(stubClassName);
4769     
4770     StackSString targetInterfaceName;
4771     pTargetMT->_GetFullyQualifiedNameForClassNestedAware(targetInterfaceName);
4772     
4773     // Restrict to same assembly only to reduce test cost
4774     if (stubClassType.GetAssembly() != pTargetMT->GetAssembly())
4775     {
4776         COMPlusThrow(
4777             kArgumentException, 
4778             IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY,
4779             stubClassName.GetUnicode(),
4780             targetInterfaceName.GetUnicode()
4781             );
4782     }
4783
4784     if (stubClassType.HasInstantiation())
4785     {
4786         COMPlusThrow(
4787             kArgumentException, 
4788             IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC,
4789             stubClassName.GetUnicode()
4790             );
4791     }
4792     
4793     if (stubClassType.IsInterface())
4794     {
4795         COMPlusThrow(
4796             kArgumentException, 
4797             IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE,
4798             stubClassName.GetUnicode()
4799             );
4800     }
4801     
4802     //
4803     // Locate the MethodDesc for the stub method
4804     //
4805     MethodDesc *pStubMD = NULL;
4806
4807     {
4808         PCCOR_SIGNATURE pTargetSig = NULL;
4809         DWORD pcTargetSig = 0;
4810         
4811         SigTypeContext typeContext; // NO generics supported
4812
4813         pTargetMD->GetSig(&pTargetSig, &pcTargetSig);
4814         
4815         MetaSig msig(pTargetSig, 
4816                      pcTargetSig,
4817                      pTargetMD->GetModule(), 
4818                      &typeContext);
4819         _ASSERTE(msig.HasThis());
4820         
4821         SigBuilder stubSigBuilder;
4822
4823         //
4824         // Append calling Convention, NumOfArgs + 1,
4825         //
4826         stubSigBuilder.AppendByte(msig.GetCallingConvention() & ~IMAGE_CEE_CS_CALLCONV_HASTHIS);
4827         stubSigBuilder.AppendData(msig.NumFixedArgs() + 1);
4828
4829         //
4830         // Append return type
4831         //
4832         SigPointer pReturn = msig.GetReturnProps();
4833         LPBYTE pReturnTypeBegin = (LPBYTE)pReturn.GetPtr();
4834         IfFailThrow(pReturn.SkipExactlyOne());
4835         LPBYTE pReturnTypeEnd = (LPBYTE)pReturn.GetPtr();
4836         
4837         stubSigBuilder.AppendBlob(pReturnTypeBegin, pReturnTypeEnd - pReturnTypeBegin);
4838
4839         //
4840         // Append 'this'
4841         //
4842         stubSigBuilder.AppendElementType(ELEMENT_TYPE_CLASS);            
4843         stubSigBuilder.AppendToken(pTargetMT->GetCl());
4844
4845         //
4846         // Copy rest of the arguments
4847         //
4848         if (msig.NextArg() != ELEMENT_TYPE_END)
4849         {
4850             SigPointer pFirstArg = msig.GetArgProps();
4851             LPBYTE pArgBegin = (LPBYTE) pFirstArg.GetPtr();
4852             LPBYTE pArgEnd = (LPBYTE) pTargetSig + pcTargetSig;
4853
4854             stubSigBuilder.AppendBlob(pArgBegin, pArgEnd - pArgBegin);
4855         }
4856
4857         //
4858         // Allocate new memory and copy over
4859         //
4860         DWORD pcStubSig = 0;
4861         PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE) stubSigBuilder.GetSignature(&pcStubSig);
4862
4863         //
4864         // Find method using name + signature
4865         //
4866         StackScratchBuffer buffer;
4867         LPCUTF8 szMethodNameUTF8 = methodName.GetUTF8(buffer);
4868         pStubMD = MemberLoader::FindMethod(stubClassType.GetMethodTable(),
4869             szMethodNameUTF8, 
4870             pStubSig,
4871             pcStubSig,
4872             pTargetMT->GetModule());
4873             
4874         if (pStubMD == NULL)
4875         {
4876             CQuickBytes qbSig;
4877             
4878             PrettyPrintSig(
4879                 pStubSig,
4880                 pcStubSig,
4881                 szMethodNameUTF8,
4882                 &qbSig,
4883                 pTargetMD->GetMDImport(),
4884                 NULL);
4885
4886             // Unfortunately the PrettyPrintSig doesn't print 'static' when the function is static
4887             // so we need to append 'static' here. No need to localize
4888             SString signature(SString::Utf8, (LPCUTF8)"static ");
4889             signature.AppendUTF8((LPCUTF8) qbSig.Ptr());
4890             
4891             COMPlusThrow(
4892                 kMissingMethodException, 
4893                 IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING,
4894                 signature.GetUnicode(),
4895                 stubClassName.GetUnicode()
4896                 );       
4897        
4898         }
4899     }
4900
4901     //
4902     // Check the Stub MD    
4903     //
4904     
4905     // Verify that the target interop method can call the stub method
4906
4907     _ASSERTE(pTargetMD != NULL);
4908
4909     StaticAccessCheckContext accessContext(pTargetMD, pTargetMT);
4910
4911     if (!ClassLoader::CanAccess(
4912             &accessContext, 
4913             pStubClassMT,
4914             stubClassType.GetAssembly(), 
4915             pStubMD->GetAttrs(),
4916             pStubMD,
4917             NULL))
4918     {
4919         StackSString interopMethodName(SString::Utf8, pTargetMD->GetName());
4920         
4921         COMPlusThrow(
4922             kMethodAccessException, 
4923             IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD,
4924             interopMethodName.GetUnicode(),
4925             methodName.GetUnicode()
4926             );
4927     }
4928
4929     // The FindMethod call will make sure that it is static by matching signature.
4930     // So there is no need to check and throw
4931     _ASSERTE(pStubMD->IsStatic());
4932     
4933     *ppRetStubMD = pStubMD;
4934
4935     RETURN S_OK;
4936 }
4937 #endif // FEATURE_COMINTEROP
4938
4939 MethodDesc* CreateInteropILStub(
4940                          ILStubState*       pss,
4941                          StubSigDesc*       pSigDesc,
4942                          CorNativeLinkType  nlType,
4943                          CorNativeLinkFlags nlFlags,
4944                          CorPinvokeMap      unmgdCallConv,
4945                          DWORD              dwStubFlags,            // NDirectStubFlags
4946                          int                nParamTokens,
4947                          mdParamDef*        pParamTokenArray,
4948                          int                iLCIDArg
4949                            )
4950 {
4951     CONTRACT(MethodDesc*)
4952     {
4953         STANDARD_VM_CHECK;
4954
4955         PRECONDITION(CheckPointer(pSigDesc));
4956         POSTCONDITION(CheckPointer(RETVAL));
4957     }
4958     CONTRACT_END;
4959
4960
4961     ///////////////////////////////
4962     //
4963     // MethodDesc creation 
4964     //
4965     ///////////////////////////////
4966     
4967     MethodDesc*     pStubMD = NULL;
4968
4969     Module*         pModule = pSigDesc->m_pModule;
4970     Module*         pLoaderModule = pSigDesc->m_pLoaderModule;
4971     MethodDesc*     pTargetMD = pSigDesc->m_pMD;
4972     //
4973     // pTargetMD may be null in the case of calli pinvoke 
4974     // and vararg pinvoke.
4975     //
4976
4977 #ifdef FEATURE_COMINTEROP
4978     //
4979     // Try to locate predefined IL stub either defined in user code or hardcoded in CLR
4980     // If there is one, use the pointed method as the stub.
4981     // Skip pTargetMD == NULL case for reverse interop calls
4982     //
4983     if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD)))
4984     {
4985 #ifndef CROSSGEN_COMPILE
4986         // We are about to execute method in pStubMD which could be in another module.
4987         // Call EnsureActive before make the call
4988         // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here
4989         pStubMD->EnsureActive();
4990
4991         if (pStubMD->IsPreImplemented())
4992             RestoreNGENedStub(pStubMD);
4993 #endif
4994
4995         RETURN pStubMD;
4996     }
4997 #endif // FEATURE_COMINTEROP
4998
4999     // Otherwise, fall back to generating IL stub on-the-fly
5000     NDirectStubParameters    params(pSigDesc->m_sig,
5001                                &pSigDesc->m_typeContext,
5002                                pModule,
5003                                pLoaderModule,
5004                                nlType,
5005                                nlFlags,
5006                                unmgdCallConv,
5007                                dwStubFlags,
5008                                nParamTokens,
5009                                pParamTokenArray,
5010                                iLCIDArg
5011                                );
5012
5013     // The following two ILStubCreatorHelperHolder are to recover the status when an
5014     // exception happen during the generation of the IL stubs. We need to free the
5015     // memory allocated and restore the ILStubCache.
5016     //
5017     // The following block is logically divided into two phases. The first phase is 
5018     // CreateOrGet IL Stub phase which we take a domain level lock. The second phase
5019     // is IL generation phase which we take a MethodDesc level lock. Taking two locks
5020     // is mainly designed for performance.
5021     //
5022     // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
5023     // allocated memory during the creation of MethodDesc so that we are able to remove
5024     // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
5025
5026     // When removing IL Stub from Cache, we have a constraint that only the thread which
5027     // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
5028     // remove it from cache if OOM occurs
5029
5030     {
5031         ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, &params);
5032
5033         // take the domain level lock
5034         ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock());
5035
5036         {
5037             // The holder will free the allocated MethodDesc and restore the ILStubCache
5038             // if exception happen.
5039             ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper);
5040             pStubMD = pCreateOrGetStubHolder->GetStubMD();
5041
5042             ///////////////////////////////
5043             //
5044             // IL generation
5045             //
5046             ///////////////////////////////
5047
5048             {
5049                 // take the MethodDesc level locker
5050                 ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5051
5052                 ListLockEntryLockHolder pEntryLock(pEntry, FALSE);
5053
5054                 // We can release the holder for the first phase now
5055                 pCreateOrGetStubHolder.SuppressRelease();
5056
5057                 {
5058                     // The holder will free the allocated MethodDesc and restore the ILStubCache
5059                     // if exception happen. The reason to get the holder again is to 
5060                     ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper);
5061
5062                     if (!pEntryLock.DeadlockAwareAcquire())
5063                     {
5064                         // the IL generation is not recursive!
5065                         UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5066                     }
5067
5068                     if (SF_IsSharedStub(params.m_dwStubFlags))
5069                     {
5070                         // Assure that pStubMD we have now has not been destroyed by other threads
5071                         pGenILHolder->GetStubMethodDesc();
5072
5073                         while (pStubMD != pGenILHolder->GetStubMD())
5074                         {
5075                             pStubMD = pGenILHolder->GetStubMD();
5076
5077                             pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5078                             pEntryLock.Assign(pEntry, FALSE);
5079
5080                             if (!pEntryLock.DeadlockAwareAcquire())
5081                             {
5082                                 // the IL generation is not recursive!
5083                                 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5084                             }
5085
5086                             pGenILHolder->GetStubMethodDesc();
5087                         }
5088                     }
5089
5090                     for (;;)
5091                     {
5092                         // We have the entry lock now, we can release the global lock
5093                         pILStubLock.Release();
5094
5095                         if (pEntry->m_hrResultCode != S_FALSE)
5096                         {
5097                             // We came in to generate the IL but someone 
5098                             // beat us so there's nothing to do
5099                             break;
5100                         }
5101
5102                         ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
5103
5104                         CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc()));
5105
5106                         if (pResolver->IsILGenerated())
5107                         {
5108                             // this stub already has its IL generated
5109                             break;
5110                         }
5111
5112                         //
5113                         // Check that the stub signature and MethodDesc are compatible.  The JIT
5114                         // interface functions depend on this.
5115                         //
5116                         
5117                         {
5118                             SigPointer ptr = pSigDesc->m_sig.CreateSigPointer();
5119
5120                             ULONG callConvInfo;
5121                             IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo));
5122
5123                             BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS);
5124
5125                             // CreateNDirectStubWorker will throw an exception for these cases.
5126                             BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags);
5127
5128                             if (fSigIsStatic || fCanHaveThis)
5129                             {
5130                                 CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic);
5131                             }
5132                         }
5133
5134                         {
5135                             ILStubGenHolder sgh(pResolver);
5136
5137                             pResolver->SetStubMethodDesc(pStubMD);
5138                             pResolver->SetStubTargetMethodDesc(pTargetMD);
5139
5140                             CreateNDirectStubWorker(pss,
5141                                                     pSigDesc,
5142                                                     nlType,
5143                                                     nlFlags,
5144                                                     unmgdCallConv,
5145                                                     dwStubFlags,
5146                                                     pStubMD,
5147                                                     pParamTokenArray,
5148                                                     iLCIDArg);
5149
5150                             pResolver->SetTokenLookupMap(pss->GetTokenLookupMap());
5151
5152                             pResolver->SetStubTargetMethodSig(
5153                                 pss->GetStubTargetMethodSig(), 
5154                                 pss->GetStubTargetMethodSigLength());
5155
5156                             // we successfully generated the IL stub
5157                             sgh.SuppressRelease();
5158                         }
5159
5160                         pEntry->m_hrResultCode = S_OK;
5161                         break;
5162                     }
5163
5164                     // Link the MethodDesc onto the method table with the lock taken
5165                     NDirect::AddMethodDescChunkWithLockTaken(&params, pStubMD);
5166
5167                     pGenILHolder.SuppressRelease();
5168                 }
5169             }
5170         }
5171         ilStubCreatorHelper.SuppressRelease();
5172     }
5173
5174 #if defined(_TARGET_X86_)
5175     if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg())
5176     {
5177         // copy the stack arg byte count from the stub MD to the target MD - this number is computed
5178         // during stub generation and is copied to all target MDs that share the stub
5179         // (we don't set it for varargs - the number is call site specific)
5180         // also copy the "takes parameters with copy constructors" flag which is needed to generate
5181         // appropriate intercept stub
5182
5183         WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
5184         BOOL fHasCopyCtorArgs = pStubMD->AsDynamicMethodDesc()->HasCopyCtorArgs();
5185
5186         if (pTargetMD->IsNDirect())
5187         {
5188             NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
5189             
5190             pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
5191             pTargetNMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5192         }
5193 #ifdef FEATURE_COMINTEROP
5194         else
5195         {
5196             if (SF_IsCOMStub(dwStubFlags))
5197             {
5198                 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD);
5199
5200                 if (pComInfo != NULL)
5201                 {
5202                     pComInfo->SetStackArgumentSize(cbStackArgSize);
5203                     pComInfo->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5204                 }
5205             }
5206         }
5207 #endif // FEATURE_COMINTEROP
5208     }
5209 #endif // defined(_TARGET_X86_)
5210
5211     RETURN pStubMD;
5212 }
5213
5214 MethodDesc* NDirect::CreateCLRToNativeILStub(
5215                 StubSigDesc*       pSigDesc,
5216                 CorNativeLinkType  nlType,
5217                 CorNativeLinkFlags nlFlags,
5218                 CorPinvokeMap      unmgdCallConv,
5219                 DWORD              dwStubFlags) // NDirectStubFlags
5220 {
5221     CONTRACT(MethodDesc*)
5222     {
5223         STANDARD_VM_CHECK;
5224
5225         PRECONDITION(CheckPointer(pSigDesc));
5226         POSTCONDITION(CheckPointer(RETVAL));
5227     }
5228     CONTRACT_END;
5229
5230     int         iLCIDArg = 0;
5231     int         numArgs = 0;
5232     int         numParamTokens = 0;
5233     mdParamDef* pParamTokenArray = NULL;
5234
5235     CreateNDirectStubAccessMetadata(pSigDesc,
5236                                     unmgdCallConv,
5237                                     &dwStubFlags,
5238                                     &iLCIDArg,
5239                                     &numArgs);
5240     
5241     Module *pModule = pSigDesc->m_pModule;
5242     numParamTokens = numArgs + 1;
5243     pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5244     CollateParamTokens(pModule->GetMDImport(), pSigDesc->m_tkMethodDef, numArgs, pParamTokenArray);
5245
5246     // for interop vectors that have declarative security, we need
5247     //      to update the stub flags to ensure a unique stub hash
5248     //      is generated based on the marshalling signature AND
5249     //      any declarative security.
5250     // IMPORTANT: This will only inject the security callouts for
5251     //      interop functionality which has a non-null target MethodDesc.
5252     //      Currently, this is known to exclude things like native
5253     //      function ptrs. It is assumed that if the target is not
5254     //      attribute'able for metadata, then it cannot have declarative
5255     //      security - and that the target is not attributable if it was
5256     //      not passed to this function.
5257     MethodDesc *pMD = pSigDesc->m_pMD;
5258     if (pMD != NULL && SF_IsForwardStub(dwStubFlags))
5259     {
5260         // In an AppX process there is only one fully trusted AppDomain, so there is never any need to insert
5261         // a security callout on the stubs.
5262         if (!AppX::IsAppXProcess())
5263         {
5264 #ifdef FEATURE_COMINTEROP
5265             if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5266             {
5267                 // To preserve Whidbey behavior, we only enforce the implicit demand for
5268                 // unmanaged code permission.
5269                 MethodTable* pMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
5270                 if (pMT->ClassRequiresUnmanagedCodeCheck() &&
5271                     !pMD->HasSuppressUnmanagedCodeAccessAttr())
5272                 {
5273                     dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5274                 }
5275             }
5276             else
5277 #endif // FEATURE_COMPINTEROP
5278             if (pMD->IsInterceptedForDeclSecurity())
5279             {
5280                 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5281             }
5282         }
5283     }
5284
5285     NewHolder<ILStubState> pStubState;
5286
5287 #ifdef FEATURE_COMINTEROP
5288     if (SF_IsCOMStub(dwStubFlags))
5289     {
5290         if (SF_IsReverseStub(dwStubFlags))
5291         {
5292             pStubState = new COMToCLR_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5293         }
5294         else
5295         {
5296             pStubState = new CLRToCOM_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5297         }
5298     }
5299     else
5300 #endif
5301     {
5302         pStubState = new PInvoke_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, pMD);
5303     }
5304
5305     MethodDesc* pStubMD;
5306     pStubMD = CreateInteropILStub(
5307                 pStubState,
5308                 pSigDesc,
5309                 nlType,
5310                 nlFlags,
5311                 unmgdCallConv,
5312                 dwStubFlags,
5313                 numParamTokens,
5314                 pParamTokenArray,
5315                 iLCIDArg);
5316
5317
5318
5319     RETURN pStubMD;
5320 }
5321
5322 #ifdef FEATURE_COMINTEROP
5323 MethodDesc* NDirect::CreateFieldAccessILStub(
5324                 PCCOR_SIGNATURE    szMetaSig,
5325                 DWORD              cbMetaSigSize,
5326                 Module*            pModule,
5327                 mdFieldDef         fd,
5328                 DWORD              dwStubFlags, // NDirectStubFlags
5329                 FieldDesc*         pFD)
5330 {
5331     CONTRACT(MethodDesc*)
5332     {
5333         STANDARD_VM_CHECK;
5334
5335         PRECONDITION(CheckPointer(szMetaSig));
5336         PRECONDITION(CheckPointer(pModule));
5337         PRECONDITION(CheckPointer(pFD, NULL_OK));
5338         PRECONDITION(SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags));
5339         POSTCONDITION(CheckPointer(RETVAL));
5340     }
5341     CONTRACT_END;
5342
5343     int numArgs = (SF_IsFieldSetterStub(dwStubFlags) ? 1 : 0);
5344     int numParamTokens = numArgs + 1;
5345
5346     // make sure we capture marshaling metadata
5347     mdParamDef* pParamTokenArray = (mdParamDef *)_alloca(numParamTokens * sizeof(mdParamDef));
5348     pParamTokenArray[0] = mdParamDefNil;
5349     pParamTokenArray[numArgs] = (mdParamDef)fd;
5350
5351     // fields are never preserve-sig
5352     dwStubFlags |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
5353
5354     // convert field signature to getter/setter signature
5355     SigBuilder sigBuilder;
5356
5357     sigBuilder.AppendData(IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS);
5358     sigBuilder.AppendData(numArgs);
5359
5360     if (SF_IsFieldSetterStub(dwStubFlags))
5361     {
5362         // managed setter returns void
5363         sigBuilder.AppendElementType(ELEMENT_TYPE_VOID);
5364     }
5365
5366     CONSISTENCY_CHECK(*szMetaSig == IMAGE_CEE_CS_CALLCONV_FIELD);
5367
5368     sigBuilder.AppendBlob((const PVOID)(szMetaSig + 1), cbMetaSigSize - 1);
5369     szMetaSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbMetaSigSize);
5370
5371     StubSigDesc sigDesc(NULL, Signature(szMetaSig, cbMetaSigSize), pModule);
5372
5373 #ifdef _DEBUG
5374     sigDesc.m_pDebugName = pFD->GetDebugName();
5375     sigDesc.m_pDebugClassName = pFD->GetEnclosingMethodTable()->GetDebugClassName();
5376 #endif // _DEBUG
5377
5378     Signature signature(szMetaSig, cbMetaSigSize);
5379     NewHolder<ILStubState> pStubState = new COMToCLRFieldAccess_ILStubState(pModule, signature, &sigDesc.m_typeContext, dwStubFlags, pFD);
5380
5381     MethodDesc* pStubMD;
5382     pStubMD = CreateInteropILStub(
5383                 pStubState,
5384                 &sigDesc,
5385                 (CorNativeLinkType)0,
5386                 (CorNativeLinkFlags)0,
5387                 (CorPinvokeMap)0,
5388                 dwStubFlags,
5389                 numParamTokens,
5390                 pParamTokenArray,
5391                 -1);
5392
5393     RETURN pStubMD;
5394 }
5395 #endif // FEATURE_COMINTEROP
5396
5397 MethodDesc* NDirect::CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
5398                          DWORD dwStubFlags,
5399                          MethodDesc* pMD)
5400 {
5401     STANDARD_VM_CONTRACT;
5402     
5403     StubSigDesc sigDesc(pMD, pSigInfo);
5404
5405     if (SF_IsWinRTDelegateStub(dwStubFlags))
5406     {
5407         _ASSERTE(pMD->IsEEImpl());
5408
5409         return CreateCLRToNativeILStub(&sigDesc,
5410                                        (CorNativeLinkType)0,
5411                                        (CorNativeLinkFlags)0,
5412                                        (CorPinvokeMap)0,
5413                                        (pSigInfo->GetStubFlags() | dwStubFlags) & ~NDIRECTSTUB_FL_DELEGATE);
5414     }
5415     else
5416     {
5417         return CreateCLRToNativeILStub(&sigDesc,
5418                                        pSigInfo->GetCharSet(), 
5419                                        pSigInfo->GetLinkFlags(), 
5420                                        pSigInfo->GetCallConv(), 
5421                                        pSigInfo->GetStubFlags() | dwStubFlags);
5422     }
5423 }
5424
5425 MethodDesc* NDirect::GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags)
5426 {
5427     STANDARD_VM_CONTRACT;
5428
5429     MethodDesc* pStubMD = NULL;
5430
5431     if (!pNMD->IsVarArgs() || SF_IsForNumParamBytes(dwStubFlags))
5432     {
5433         if (pNMD->IsClassConstructorTriggeredByILStub())
5434         {
5435             dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
5436         }
5437
5438         pStubMD = CreateCLRToNativeILStub(
5439             pSigInfo, 
5440             dwStubFlags & ~NDIRECTSTUB_FL_FOR_NUMPARAMBYTES, 
5441             pNMD);
5442     }
5443
5444     return pStubMD;
5445 }
5446
5447 MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
5448 {
5449     STANDARD_VM_CONTRACT;
5450
5451     BOOL fGcMdaEnabled = FALSE;
5452 #ifdef MDA_SUPPORTED
5453     if (MDA_GET_ASSISTANT(GcManagedToUnmanaged) || MDA_GET_ASSISTANT(GcUnmanagedToManaged))
5454     {
5455         // We never generate checks for these MDAs to NGEN'ed stubs so if they are
5456         // enabled, a new stub must be generated (the perf impact is huge anyway).
5457         fGcMdaEnabled = TRUE;
5458     }
5459 #endif // MDA_SUPPORTED
5460
5461 #ifdef FEATURE_COMINTEROP
5462     if (SF_IsReverseCOMStub(dwStubFlags))
5463     {
5464         if (fGcMdaEnabled)
5465             return NULL;
5466
5467         // reverse COM stubs live in a hash table
5468         StubMethodHashTable *pHash = pMD->GetLoaderModule()->GetStubMethodHashTable();
5469         return (pHash == NULL ? NULL : pHash->FindMethodDesc(pMD));
5470     }
5471     else
5472 #endif // FEATURE_COMINTEROP
5473     if (pMD->IsNDirect())
5474     {
5475         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5476         return ((fGcMdaEnabled && !pNMD->IsQCall()) ? NULL : pNMD->ndirect.m_pStubMD.GetValueMaybeNull());
5477     }
5478 #ifdef FEATURE_COMINTEROP
5479     else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5480     {
5481 #ifdef MDA_SUPPORTED
5482         if (MDA_GET_ASSISTANT(RaceOnRCWCleanup))
5483         {
5484             // we never generate this callout to NGEN'ed stubs
5485             return NULL;
5486         }
5487 #endif // MDA_SUPPORTED
5488
5489         if (NDirect::IsHostHookEnabled())
5490         {
5491             MethodTable *pMT = pMD->GetMethodTable();
5492             if (pMT->IsProjectedFromWinRT() || pMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative))
5493             {
5494                 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5495                 // must be rejected if we are hosted.
5496                 return NULL;
5497             }
5498         }
5499
5500         if (fGcMdaEnabled)
5501             return NULL;
5502
5503         ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
5504         return (pComInfo == NULL ? NULL : pComInfo->m_pStubMD.GetValueMaybeNull());
5505     }
5506 #endif // FEATURE_COMINTEROP
5507     else if (pMD->IsEEImpl())
5508     {
5509         if (fGcMdaEnabled)
5510             return NULL;
5511
5512         DelegateEEClass *pClass = (DelegateEEClass *)pMD->GetClass();
5513         if (SF_IsReverseStub(dwStubFlags))
5514         {
5515             return pClass->m_pReverseStubMD;
5516         }
5517         else
5518         {
5519 #ifdef FEATURE_COMINTEROP
5520             if (SF_IsWinRTDelegateStub(dwStubFlags))
5521             {
5522                 if (NDirect::IsHostHookEnabled() && pMD->GetMethodTable()->IsProjectedFromWinRT())
5523                 {
5524                     // WinRT NGENed stubs are optimized for the non-hosted scenario and
5525                     // must be rejected if we are hosted.
5526                     return NULL;
5527                 }
5528
5529                 return pClass->m_pComPlusCallInfo->m_pStubMD.GetValueMaybeNull();
5530             }
5531             else
5532 #endif // FEATURE_COMINTEROP
5533             {
5534                 return pClass->m_pForwardStubMD;
5535             }
5536         }
5537     }
5538     else if (pMD->IsIL())
5539     {
5540         // these are currently only created at runtime, not at NGEN time
5541         return NULL;
5542     }
5543     else
5544     {
5545         UNREACHABLE_MSG("unexpected type of MethodDesc");
5546     }
5547 }
5548
5549 #ifndef CROSSGEN_COMPILE
5550
5551 PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5552 {
5553     CONTRACT(PCODE)
5554     {
5555         STANDARD_VM_CHECK;
5556
5557         PRECONDITION(CheckPointer(pManagedMD));
5558         POSTCONDITION(RETVAL != NULL);
5559     }
5560     CONTRACT_END;
5561
5562     // pStubMD, if provided, must be preimplemented.
5563     CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5564
5565     if (NULL == *ppStubMD)
5566     {
5567         PInvokeStaticSigInfo sigInfo(pManagedMD);
5568         *ppStubMD = NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pManagedMD);
5569     }
5570
5571     RETURN JitILStub(*ppStubMD);
5572 }
5573
5574 PCODE NDirect::GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5575 {
5576     STANDARD_VM_CONTRACT;
5577
5578     PCODE pStub = NULL;
5579
5580     // pStubMD, if provided, must be preimplemented.
5581     CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5582
5583     if (NULL == *ppStubMD)
5584     {
5585         PInvokeStaticSigInfo sigInfo;
5586         NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo, /* throwOnError = */ !SF_IsForNumParamBytes(dwStubFlags));
5587
5588         *ppStubMD = NDirect::GetILStubMethodDesc(pNMD, &sigInfo, dwStubFlags);
5589     }
5590
5591     if (SF_IsForNumParamBytes(dwStubFlags))
5592         return NULL;
5593
5594     if (*ppStubMD)
5595     {
5596         pStub = JitILStub(*ppStubMD);
5597     }
5598     else
5599     {
5600         CONSISTENCY_CHECK(pNMD->IsVarArgs());
5601         
5602         //
5603         // varargs goes through vararg NDirect stub
5604         //
5605         pStub = TheVarargNDirectStub(pNMD->HasRetBuffArg());
5606     }
5607
5608 #ifdef FEATURE_MIXEDMODE // IJW
5609     if (pNMD->IsEarlyBound())
5610     {
5611         pNMD->InitEarlyBoundNDirectTarget();
5612     }
5613     else
5614 #endif
5615     {
5616         NDirectLink(pNMD);
5617     }
5618
5619     //
5620     // NOTE: there is a race in updating this MethodDesc.  We depend on all 
5621     // threads getting back the same DynamicMethodDesc for a particular
5622     // NDirectMethodDesc, in that case, the locking around the actual JIT
5623     // operation will prevent the code from being jitted more than once.  
5624     // By the time we get here, all threads get the same address of code 
5625     // back from the JIT operation and they all just fill in the same value
5626     // here.
5627     //
5628     // In the NGEN case, all threads will get the same preimplemented code
5629     // address much like the JIT case.
5630     //
5631
5632     return pStub;
5633 }
5634
5635 PCODE JitILStub(MethodDesc* pStubMD)
5636 {
5637     STANDARD_VM_CONTRACT;
5638
5639     PCODE pCode = pStubMD->GetNativeCode();
5640
5641     if (pCode == NULL)
5642     {
5643         ///////////////////////////////
5644         //
5645         // Code generation
5646         //
5647         ///////////////////////////////
5648
5649
5650         if (pStubMD->IsDynamicMethod())
5651         {
5652             //
5653             // A dynamically generated IL stub
5654             //
5655             
5656             CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
5657             pCode = pStubMD->MakeJitWorker(NULL, jitFlags);
5658
5659             _ASSERTE(pCode == pStubMD->GetNativeCode());            
5660         }
5661         else
5662         {     
5663             //
5664             // A static IL stub that is pointing to a static method in user assembly
5665             // Compile it and return the native code
5666             //
5667
5668             // This returns the stable entry point
5669             pCode = pStubMD->DoPrestub(NULL);
5670
5671             _ASSERTE(pCode == pStubMD->GetStableEntryPoint());            
5672         }        
5673     }
5674
5675     if (!pStubMD->IsDynamicMethod()) 
5676     {
5677         // We need an entry point that can be called multiple times
5678         pCode = pStubMD->GetMultiCallableAddrOfCode();
5679     }
5680
5681     return pCode;
5682 }
5683
5684 MethodDesc* RestoreNGENedStub(MethodDesc* pStubMD)
5685 {
5686     CONTRACTL
5687     {
5688         STANDARD_VM_CHECK;
5689         PRECONDITION(CheckPointer(pStubMD));
5690     }
5691     CONTRACTL_END;
5692
5693 #ifdef FEATURE_PREJIT
5694     pStubMD->CheckRestore();
5695
5696     PCODE pCode = pStubMD->GetPreImplementedCode();
5697     if (pCode != NULL)
5698     {
5699         TADDR pFixupList = pStubMD->GetFixupList();
5700         if (pFixupList != NULL)
5701         {
5702             Module* pZapModule = pStubMD->GetZapModule();
5703             _ASSERTE(pZapModule != NULL);
5704             if (!pZapModule->FixupDelayList(pFixupList))
5705             {
5706                 _ASSERTE(!"FixupDelayList failed");
5707                 ThrowHR(COR_E_BADIMAGEFORMAT);
5708             }
5709         }
5710
5711 #if defined(HAVE_GCCOVER)
5712         if (GCStress<cfg_instr_ngen>::IsEnabled())
5713             SetupGcCoverage(pStubMD, (BYTE*) pCode);
5714 #endif // HAVE_GCCOVER
5715
5716     }
5717     else
5718     {
5719         // We only pass a non-NULL pStubMD to GetStubForILStub() below if pStubMD is preimplemeneted.
5720         pStubMD = NULL;
5721     }
5722 #endif // FEATURE_PREJIT
5723
5724     return pStubMD;
5725 }
5726
5727 PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags, MethodDesc **ppStubMD)
5728 {
5729     CONTRACT(PCODE)
5730     {
5731         STANDARD_VM_CHECK;
5732
5733         PRECONDITION(CheckPointer(pMD));
5734         PRECONDITION(pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl() || pMD->IsIL());
5735     }
5736     CONTRACT_END;
5737
5738     PCODE                   pStub = NULL;
5739     MethodDesc*             pStubMD = NULL;
5740
5741     pStubMD = GetStubMethodDescFromInteropMethodDesc(pMD, dwStubFlags);
5742     if (pStubMD != NULL)
5743     {
5744         pStubMD = RestoreNGENedStub(pStubMD);
5745     }
5746
5747     if ((NULL == pStubMD) && (SF_IsNGENedStub(dwStubFlags)))
5748     {
5749         // Return NULL -- the caller asked only for an ngened stub and 
5750         // one does not exist, so don't do any more work.
5751         CONSISTENCY_CHECK(pStub == NULL);
5752     }
5753     else
5754     if (pMD->IsNDirect())
5755     {
5756         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5757         pStub = NDirect::GetStubForILStub(pNMD, &pStubMD, dwStubFlags);
5758     }
5759 #ifdef FEATURE_COMINTEROP
5760     else
5761     if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5762     {
5763         pStub = ComPlusCall::GetStubForILStub(pMD, &pStubMD);
5764     }
5765 #endif // FEATURE_COMINTEROP
5766     else
5767     if (pMD->IsEEImpl())
5768     {
5769         CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
5770         EEImplMethodDesc* pDelegateMD = (EEImplMethodDesc*)pMD;
5771         pStub = COMDelegate::GetStubForILStub(pDelegateMD, &pStubMD, dwStubFlags);
5772     }
5773     else
5774     if (pMD->IsIL())
5775     {
5776         CONSISTENCY_CHECK(SF_IsReverseStub(dwStubFlags));
5777         pStub = NDirect::GetStubForILStub(pMD, &pStubMD, dwStubFlags);
5778     }
5779     else
5780     {
5781         UNREACHABLE_MSG("unexpected MethodDesc type");
5782     }
5783
5784     if (pStubMD != NULL && pStubMD->IsILStub() && pStubMD->AsDynamicMethodDesc()->IsStubNeedsCOMStarted())
5785     {
5786         // the stub uses COM so make sure that it is started
5787         EnsureComStarted();
5788     }
5789
5790     if (ppStubMD != NULL)
5791         *EnsureWritablePages(ppStubMD) = pStubMD;
5792
5793     RETURN pStub;
5794 }
5795
5796 #ifdef FEATURE_COMINTEROP
5797 void CreateCLRToDispatchCOMStub(
5798             MethodDesc *    pMD,
5799             DWORD           dwStubFlags)             // NDirectStubFlags
5800 {
5801     CONTRACTL
5802     {
5803         STANDARD_VM_CHECK;
5804
5805         PRECONDITION(CheckPointer(pMD));
5806     }
5807     CONTRACTL_END;
5808
5809     _ASSERTE(SF_IsCOMLateBoundStub(dwStubFlags) || SF_IsCOMEventCallStub(dwStubFlags));
5810
5811     // If we are dealing with a COM event call, then we need to initialize the
5812     // COM event call information.
5813     if (SF_IsCOMEventCallStub(dwStubFlags))
5814     {
5815         _ASSERTE(pMD->IsComPlusCall()); //  no generic COM eventing
5816         ((ComPlusCallMethodDesc *)pMD)->InitComEventCallInfo();
5817     }
5818
5819     // Get the call signature information
5820     StubSigDesc sigDesc(pMD);
5821
5822     int         iLCIDArg = 0;
5823     int         numArgs = 0;
5824     int         numParamTokens = 0;
5825     mdParamDef* pParamTokenArray = NULL;
5826
5827     CreateNDirectStubAccessMetadata(&sigDesc,
5828                                     (CorPinvokeMap)0,
5829                                     &dwStubFlags,
5830                                     &iLCIDArg,
5831                                     &numArgs);
5832
5833     numParamTokens = numArgs + 1;
5834     pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5835     CollateParamTokens(sigDesc.m_pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray);
5836
5837     DispatchStubState MyStubState;
5838
5839     CreateNDirectStubWorker(&MyStubState,
5840                             &sigDesc,
5841                             (CorNativeLinkType)0,
5842                             (CorNativeLinkFlags)0,
5843                             (CorPinvokeMap)0,
5844                             dwStubFlags | NDIRECTSTUB_FL_COM,
5845                             pMD,
5846                             pParamTokenArray,
5847                             iLCIDArg);
5848
5849     _ASSERTE(pMD->IsComPlusCall()); // no generic disp-calls
5850     ((ComPlusCallMethodDesc *)pMD)->InitRetThunk();
5851 }
5852
5853
5854 #endif // FEATURE_COMINTEROP
5855
5856 /*static*/
5857 LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod)
5858 {
5859     // GetProcAddress cannot be called while preemptive GC is disabled.
5860     // It requires the OS to take the loader lock.
5861     CONTRACT(LPVOID)
5862     {
5863         STANDARD_VM_CHECK;
5864         PRECONDITION(CheckPointer(pMD));
5865         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5866     }
5867     CONTRACT_END;
5868
5869     g_IBCLogger.LogNDirectCodeAccess(pMD);
5870
5871 #ifdef MDA_SUPPORTED
5872     MDA_TRIGGER_ASSISTANT(PInvokeLog, LogPInvoke(pMD, hMod));
5873 #endif
5874
5875     RETURN pMD->FindEntryPoint(hMod);
5876 }
5877
5878 VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget)
5879 {
5880     CONTRACTL
5881     {
5882         THROWS;
5883         GC_TRIGGERS;
5884         MODE_ANY;
5885
5886         PRECONDITION(IsNDirect());
5887         PRECONDITION(pTarget != NULL);
5888     }
5889     CONTRACTL_END;
5890
5891     Stub *pInterceptStub = NULL;
5892
5893     BOOL fHook = FALSE;
5894
5895     // Host hooks are not supported for Mac CoreCLR.
5896     if (NDirect::IsHostHookEnabled())
5897     {
5898 #ifdef _WIN64
5899         // we will call CallNeedsHostHook on every invocation for back compat
5900         fHook = TRUE;
5901 #else // _WIN64
5902         fHook = CallNeedsHostHook((size_t)pTarget);
5903 #endif // _WIN64
5904
5905 #ifdef _DEBUG
5906         if (g_pConfig->ShouldGenerateStubForHost())
5907         {
5908             fHook = TRUE;
5909         }
5910 #endif
5911     }
5912
5913 #ifdef _TARGET_X86_
5914
5915
5916 #ifdef MDA_SUPPORTED
5917     if (!IsQCall() && MDA_GET_ASSISTANT(PInvokeStackImbalance))
5918     {
5919         pInterceptStub = GenerateStubForMDA(pTarget, pInterceptStub, fHook);
5920     }
5921 #endif // MDA_SUPPORTED
5922
5923 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
5924     if (fHook)
5925     {
5926         pInterceptStub = GenerateStubForHost(pTarget, pInterceptStub);
5927     }
5928 #endif // FEATURE_INCLUDE_ALL_INTERFACES
5929
5930 #endif // _TARGET_X86_
5931
5932
5933     NDirectWriteableData* pWriteableData = GetWriteableData();
5934     EnsureWritablePages(pWriteableData);
5935     g_IBCLogger.LogNDirectCodeAccess(this);
5936
5937     if (pInterceptStub != NULL WIN64_ONLY(|| fHook))
5938     {
5939         ndirect.m_pNativeNDirectTarget = pTarget;
5940         
5941 #if defined(_TARGET_X86_)
5942         pTarget = (PVOID)pInterceptStub->GetEntryPoint();
5943
5944         LPVOID oldTarget = GetNDirectImportThunkGlue()->GetEntrypoint();
5945         if (FastInterlockCompareExchangePointer(&pWriteableData->m_pNDirectTarget, pTarget,
5946                                                 oldTarget) != oldTarget)
5947         {
5948             pInterceptStub->DecRef();
5949         }
5950 #else
5951         _ASSERTE(pInterceptStub == NULL); // we don't intercept for anything else than host on !_TARGET_X86_
5952 #ifdef FEATURE_INCLUDE_ALL_INTERFACES 
5953         pWriteableData->m_pNDirectTarget = (LPVOID)GetEEFuncEntryPoint(PInvokeStubForHost);
5954 #endif // FEATURE_INCLUDE_ALL_INTERFACES 
5955 #endif
5956     }
5957     else
5958     {
5959         pWriteableData->m_pNDirectTarget = pTarget;
5960     }
5961 }
5962
5963
5964 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
5965 BOOL NDirect::IsHostHookEnabled()
5966 {
5967     WRAPPER_NO_CONTRACT;
5968     //
5969     // WARNING: The non-debug portion of this logic is inlined into UMThunkStubAMD64!
5970     //
5971     return CLRTaskHosted() INDEBUG(|| g_pConfig->ShouldGenerateStubForHost());
5972 }
5973
5974 EXTERN_C BOOL CallNeedsHostHook(size_t target)
5975 {
5976     BOOL fHook = FALSE;
5977     IHostTaskManager *pManager = CorHost2::GetHostTaskManager();
5978     if (pManager)
5979     {
5980         HRESULT hr;
5981         BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
5982         hr = pManager->CallNeedsHostHook(target,&fHook);
5983         END_SO_TOLERANT_CODE_CALLING_HOST;
5984         _ASSERTE (hr == S_OK);
5985     }
5986 #ifdef _DEBUG
5987     else
5988     {
5989         if (g_pConfig->ShouldGenerateStubForHost())
5990         {
5991             fHook = TRUE;
5992         }
5993     }
5994 #endif
5995     return fHook;
5996 }
5997 #endif // FEATURE_INCLUDE_ALL_INTERFACES
5998
5999 #if defined(_TARGET_X86_) && defined(MDA_SUPPORTED)
6000 EXTERN_C VOID __stdcall PInvokeStackImbalanceWorker(StackImbalanceCookie *pSICookie, DWORD dwPostESP)
6001 {
6002     STATIC_CONTRACT_THROWS;
6003     STATIC_CONTRACT_GC_TRIGGERS;
6004     STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6005
6006     // make sure we restore the original Win32 last error before leaving this function - we are
6007     // called right after returning from the P/Invoke target and the error has not been saved yet
6008     BEGIN_PRESERVE_LAST_ERROR;
6009
6010     MdaPInvokeStackImbalance* pProbe = MDA_GET_ASSISTANT(PInvokeStackImbalance);
6011
6012     // This MDA must be active if we generated a call to PInvokeStackImbalanceHelper
6013     _ASSERTE(pProbe);
6014
6015     pProbe->CheckStack(pSICookie, dwPostESP);
6016
6017     END_PRESERVE_LAST_ERROR;
6018 }
6019 #endif // _TARGET_X86_ && MDA_SUPPORTED
6020
6021
6022 // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places
6023 // if earlier loads fail and those later loads obliterate error codes.
6024 //
6025 // This tracker object will keep track of the error code in accordance to priority:
6026 //
6027 //   low-priority:      unknown error code (should never happen)
6028 //   medium-priority:   dll not found
6029 //   high-priority:     dll found but error during loading
6030 //   
6031 // We will overwrite the previous load's error code only if the new error code is higher priority.
6032 //
6033
6034 class LoadLibErrorTracker
6035 {
6036 private:
6037     static const DWORD const_priorityNotFound     = 10;
6038     static const DWORD const_priorityAccessDenied = 20;
6039     static const DWORD const_priorityCouldNotLoad = 99999;
6040 public:
6041     LoadLibErrorTracker()
6042     {
6043         LIMITED_METHOD_CONTRACT;
6044         m_hr = E_FAIL;
6045         m_priorityOfLastError = 0;
6046     }
6047
6048     VOID TrackErrorCode(DWORD dwLastError)
6049     {
6050         LIMITED_METHOD_CONTRACT;
6051
6052         DWORD priority;
6053
6054         switch (dwLastError)
6055         {
6056             case ERROR_FILE_NOT_FOUND:
6057             case ERROR_PATH_NOT_FOUND:
6058             case ERROR_MOD_NOT_FOUND:
6059             case ERROR_DLL_NOT_FOUND:
6060                 priority = const_priorityNotFound;
6061                 break;
6062
6063             // If we can't access a location, we can't know if the dll's there or if it's good.
6064             // Still, this is probably more unusual (and thus of more interest) than a dll-not-found
6065             // so give it an intermediate priority.
6066             case ERROR_ACCESS_DENIED:
6067                 priority = const_priorityAccessDenied;
6068
6069             // Assume all others are "dll found but couldn't load."
6070             default:
6071                 priority = const_priorityCouldNotLoad;
6072                 break;
6073         }
6074
6075         UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError));
6076     }
6077
6078     // Sets the error code to HRESULT as could not load DLL
6079     void TrackHR_CouldNotLoad(HRESULT hr)
6080     {
6081         UpdateHR(const_priorityCouldNotLoad, hr);
6082     }
6083     
6084     HRESULT GetHR()
6085     {
6086         return m_hr;
6087     }
6088
6089     void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath)
6090     {
6091         STANDARD_VM_CONTRACT;
6092
6093         HRESULT theHRESULT = GetHR();
6094         if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT))
6095         {
6096             COMPlusThrow(kBadImageFormatException);
6097         }
6098         else
6099         {
6100             SString hrString;
6101             GetHRMsg(theHRESULT, hrString);
6102             COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, libraryNameOrPath.GetUnicode(), hrString);
6103         }
6104
6105         __UNREACHABLE();
6106     }
6107
6108 private:
6109     void UpdateHR(DWORD priority, HRESULT hr)
6110     {
6111         if (priority > m_priorityOfLastError)
6112         {
6113             m_hr                  = hr;
6114             m_priorityOfLastError = priority;
6115         }
6116     }
6117
6118     HRESULT m_hr;
6119     DWORD   m_priorityOfLastError;
6120 };  // class LoadLibErrorTracker
6121
6122 //  Local helper function for the LoadLibraryModule function below
6123 static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
6124 {
6125     STANDARD_VM_CONTRACT;
6126
6127     HMODULE hmod = NULL;
6128
6129 #ifndef FEATURE_PAL
6130
6131     if ((flags & 0xFFFFFF00) != 0
6132         )
6133     {
6134         hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00);
6135         if(hmod != NULL)
6136         {
6137             return hmod;
6138         }
6139
6140         DWORD dwLastError = GetLastError();
6141         if (dwLastError != ERROR_INVALID_PARAMETER)
6142         {
6143             pErrorTracker->TrackErrorCode(dwLastError);
6144             return hmod;
6145         }
6146     }
6147
6148     hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF);
6149     
6150 #else // !FEATURE_PAL
6151     hmod = CLRLoadLibrary(name);
6152 #endif // !FEATURE_PAL
6153         
6154     if (hmod == NULL)
6155     {
6156         pErrorTracker->TrackErrorCode(GetLastError());
6157     }
6158     
6159     return hmod;
6160 }
6161
6162 //  Local helper function for the LoadLibraryFromPath function below
6163 static HMODULE LocalLoadLibraryDirectHelper(LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6164 {
6165     STANDARD_VM_CONTRACT;
6166
6167 #ifndef FEATURE_PAL
6168     return LocalLoadLibraryHelper(name, flags, pErrorTracker);
6169 #else // !FEATURE_PAL
6170     // Load the library directly, and don't register it yet with PAL. The system library handle is required here, not the PAL
6171     // handle. The system library handle is registered with PAL to get a PAL handle in LoadLibraryModuleViaHost().
6172     HMODULE hmod = PAL_LoadLibraryDirect(name);
6173
6174     if (hmod == NULL)
6175     {
6176         pErrorTracker->TrackErrorCode(GetLastError());
6177     }
6178
6179     return hmod;
6180 #endif // !FEATURE_PAL
6181 }
6182
6183
6184
6185 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
6186 #define TOHEX(a)   ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
6187
6188
6189 // static
6190 HMODULE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
6191 {
6192     STANDARD_VM_CONTRACT;
6193
6194     LoadLibErrorTracker errorTracker;
6195     const HMODULE systemModuleHandle =
6196         LocalLoadLibraryDirectHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
6197     if (systemModuleHandle == nullptr)
6198     {
6199         SString libraryPathSString(libraryPath);
6200         errorTracker.Throw(libraryPathSString);
6201     }
6202     return systemModuleHandle;
6203 }
6204
6205 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6206 /* static */
6207 HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName)
6208 {
6209     STANDARD_VM_CONTRACT;
6210     //Dynamic Pinvoke Support:
6211     //Check if we  need to provide the host a chance to provide the unmanaged dll 
6212
6213 #ifndef PLATFORM_UNIX
6214     // Prevent Overriding of Windows API sets.
6215     // This is replicating quick check from the OS implementation of api sets.
6216     if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6217     {
6218         return NULL;
6219     }
6220 #endif
6221
6222     LPVOID hmod = NULL;
6223     CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
6224     Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6225    
6226     PEFile *pManifestFile = pAssembly->GetManifestFile();
6227     PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
6228
6229     //Step 0: Check if  the assembly was bound using TPA. 
6230     //        The Binding Context can be null or an overridden TPA context
6231     if (pBindingContext == NULL)
6232     {
6233         pBindingContext = nullptr;
6234
6235         // If the assembly does not have a binder associated with it explicitly, then check if it is
6236         // a dynamic assembly, or not, since they can have a fallback load context associated with them.
6237         if (pManifestFile->IsDynamic())
6238         {
6239             pBindingContext = pManifestFile->GetFallbackLoadContextBinder();
6240         } 
6241     }
6242
6243     // If we do not have any binder associated, then return to the default resolution mechanism.
6244     if (pBindingContext == nullptr)
6245     {
6246         return NULL;
6247     }    
6248
6249     UINT_PTR assemblyBinderID = 0;
6250     IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6251         
6252     ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6253
6254     // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
6255     if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
6256     {
6257         return NULL;
6258     }
6259
6260 #ifdef FEATURE_COMINTEROP
6261     CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
6262     if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
6263     {
6264         // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
6265         // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
6266         //
6267         // For this, we should use the standard mechanism to make pinvoke call as well.
6268         return NULL;
6269     }
6270 #endif // FEATURE_COMINTEROP
6271     
6272     //Step 1: If the assembly was not bound using TPA,
6273     //        Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
6274     //        The custom assembly context a chance to load the unmanaged dll.
6275     
6276     GCX_COOP();
6277             
6278     STRINGREF pUnmanagedDllName;
6279     pUnmanagedDllName = StringObject::NewString(wszLibName);
6280         
6281     GCPROTECT_BEGIN(pUnmanagedDllName);
6282
6283     // Get the pointer to the managed assembly load context
6284     INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6285
6286     // Prepare to invoke  System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
6287     PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
6288     DECLARE_ARGHOLDER_ARRAY(args, 2);
6289     args[ARGNUM_0]  = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
6290     args[ARGNUM_1]  = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6291
6292     // Make the call
6293     CALL_MANAGED_METHOD(hmod,LPVOID,args);
6294
6295     GCPROTECT_END();
6296
6297 #ifdef FEATURE_PAL
6298     if (hmod != nullptr)
6299     {
6300         // Register the system library handle with PAL and get a PAL library handle
6301         hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6302     }
6303 #endif // FEATURE_PAL
6304
6305     return (HMODULE)hmod;
6306 }
6307 #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6308
6309 // Try to load the module alongside the assembly where the PInvoke was declared.
6310 HMODULE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6311 {
6312     STANDARD_VM_CONTRACT;
6313
6314     HMODULE hmod = NULL;
6315
6316     SString path = pAssembly->GetManifestFile()->GetPath();
6317
6318     SString::Iterator lastPathSeparatorIter = path.End();
6319     if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
6320     {
6321         lastPathSeparatorIter++;
6322         path.Truncate(lastPathSeparatorIter);
6323
6324         path.Append(libName);
6325         hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
6326     }
6327
6328     return hmod;
6329 }
6330
6331 // Try to load the module from the native DLL search directories
6332 HMODULE NDirect::LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6333 {
6334     STANDARD_VM_CONTRACT;
6335
6336     HMODULE hmod = NULL;
6337
6338     if (pDomain->HasNativeDllSearchDirectories())
6339     {
6340         AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
6341         while (hmod == NULL && pathIter.Next())
6342         {
6343             SString qualifiedPath(*(pathIter.GetPath()));
6344             qualifiedPath.Append(libName);
6345             if (!Path::IsRelative(qualifiedPath))
6346             {
6347                 hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
6348             }
6349         }
6350     }
6351
6352     return hmod;
6353 }
6354
6355 HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
6356 {
6357     CONTRACTL
6358     {
6359         STANDARD_VM_CHECK;
6360         PRECONDITION( CheckPointer( pMD ) );
6361     }
6362     CONTRACTL_END;
6363     
6364     LPCUTF8 name = pMD->GetLibName();
6365     if ( !name || !*name )
6366         return NULL;
6367     
6368     ModuleHandleHolder hmod;
6369
6370     DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
6371
6372     PREFIX_ASSUME( name != NULL );
6373     MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
6374
6375     AppDomain* pDomain = GetAppDomain();
6376
6377 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6378     // AssemblyLoadContext is not supported in AppX mode and thus,
6379     // we should not perform PInvoke resolution via it when operating in
6380     // AppX mode.
6381     if (!AppX::IsAppXProcess())
6382     {
6383         hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName);
6384     }
6385 #endif  //FEATURE_HOST_ASSEMBLY_RESOLVER
6386     
6387     
6388     if(hmod == NULL)
6389     {
6390        hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
6391     }
6392
6393     if(hmod != NULL)
6394     {
6395        return hmod.Extract();
6396     }
6397
6398
6399 #ifdef FEATURE_PAL
6400     // In the PAL version of CoreCLR, the CLR module itself exports the functionality
6401     // that the Windows version obtains from kernel32 and friends.  In order to avoid
6402     // picking up the wrong instance, we perform this redirection first.
6403     // This is also true for CoreSystem builds, where mscorlib p/invokes are forwarded through coreclr
6404     // itself so we can control CoreSystem library/API name re-mapping from one central location.
6405     if (SString::_wcsicmp(wszLibName, MAIN_CLR_MODULE_NAME_W) == 0)
6406         hmod = GetCLRModule();
6407 #endif // FEATURE_PAL
6408
6409 #if !defined(PLATFORM_UNIX)
6410     if (hmod == NULL)
6411     {
6412         // Try to go straight to System32 for Windows API sets. This is replicating quick check from
6413         // the OS implementation of api sets.
6414         if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6415         {
6416             hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
6417         }
6418     }
6419 #endif // FEATURE_CORESYSTEM && !FEATURE_PAL
6420
6421     if (hmod == NULL)
6422     {
6423         // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path 
6424         hmod = LoadFromNativeDllSearchDirectories(pDomain, wszLibName, loadWithAlteredPathFlags, pErrorTracker);
6425     }
6426
6427     DWORD dllImportSearchPathFlag = 0;
6428     BOOL searchAssemblyDirectory = TRUE;
6429     bool libNameIsRelativePath = Path::IsRelative(wszLibName);
6430     if (hmod == NULL)
6431     {
6432         // First checks if the method has DefaultDllImportSearchPathsAttribute. If method has the attribute
6433         // then dllImportSearchPathFlag is set to its value.
6434         // Otherwise checks if the assembly has the attribute. 
6435         // If assembly has the attribute then flag ise set to its value.
6436         BOOL attributeIsFound = FALSE;
6437
6438         if (pMD->HasDefaultDllImportSearchPathsAttribute())
6439         {
6440             dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
6441             searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
6442             attributeIsFound = TRUE;
6443         }
6444         else 
6445         {
6446             Module * pModule = pMD->GetModule();
6447
6448             if(pModule->HasDefaultDllImportSearchPathsAttribute())
6449             {
6450                 dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
6451                 searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
6452                 attributeIsFound = TRUE;
6453             }
6454         }
6455
6456
6457         if (!libNameIsRelativePath)
6458         {
6459             DWORD flags = loadWithAlteredPathFlags;
6460             if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
6461             {
6462                 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
6463                 // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
6464                 flags |= dllImportSearchPathFlag;
6465             }
6466
6467             hmod = LocalLoadLibraryHelper(wszLibName, flags, pErrorTracker);
6468         }
6469         else if (searchAssemblyDirectory)
6470         {
6471             Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6472             hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, wszLibName, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6473
6474         }
6475     }
6476
6477     // This call searches the application directory instead of the location for the library.
6478     if (hmod == NULL)
6479     {
6480         hmod = LocalLoadLibraryHelper(wszLibName, dllImportSearchPathFlag, pErrorTracker);
6481     }
6482
6483     // This may be an assembly name
6484     if (!hmod)
6485     {
6486         // Format is "fileName, assemblyDisplayName"
6487         MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
6488         char *szComma = strchr(szLibName, ',');
6489         if (szComma)
6490         {
6491             *szComma = '\0';
6492             while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
6493
6494             AssemblySpec spec;
6495             if (SUCCEEDED(spec.Init(szComma)))
6496             {
6497                 // Need to perform case insensitive hashing.
6498                 CQuickBytes qbLC;
6499                 {
6500                     UTF8_TO_LOWER_CASE(szLibName, qbLC);
6501                     szLibName = (LPUTF8) qbLC.Ptr();
6502                 }
6503
6504                 Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
6505                 Module *pModule = pAssembly->FindModuleByName(szLibName);
6506
6507                 hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6508             }
6509         }
6510     }
6511
6512 #ifdef FEATURE_PAL
6513     if (hmod == NULL)
6514     {
6515         // P/Invokes are often declared with variations on the actual library name.
6516         // For example, it's common to leave off the extension/suffix of the library
6517         // even if it has one, or to leave off a prefix like "lib" even if it has one
6518         // (both of these are typically done to smooth over cross-platform differences). 
6519         // We try to dlopen with such variations on the original.
6520         const char* const prefixSuffixCombinations[] =
6521         {
6522             "%s%s%s",     // prefix+name+suffix
6523             "%.0s%s%s",   // name+suffix
6524             "%s%s%.0s",   // prefix+name
6525         };
6526
6527         const int NUMBER_OF_LIB_NAME_VARIATIONS = COUNTOF(prefixSuffixCombinations);
6528
6529         // Try to load from places we tried above, but this time with variations on the
6530         // name including the prefix, suffix, and both.
6531         for (int i = 0; i < NUMBER_OF_LIB_NAME_VARIATIONS; i++)
6532         {
6533             SString currLibNameVariation;
6534             currLibNameVariation.Printf(prefixSuffixCombinations[i], PAL_SHLIB_PREFIX, name, PAL_SHLIB_SUFFIX);
6535
6536             if (libNameIsRelativePath && searchAssemblyDirectory)
6537             {
6538                 Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly();
6539                 hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6540                 if (hmod != NULL)
6541                     break;
6542             }
6543
6544             hmod = LoadFromNativeDllSearchDirectories(pDomain, currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
6545             if (hmod != NULL)
6546                 break;
6547
6548             hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlag, pErrorTracker);
6549             if (hmod != NULL)
6550                 break;
6551         }
6552     }
6553 #endif // FEATURE_PAL
6554
6555     // After all this, if we have a handle add it to the cache.
6556     if (hmod)
6557     {
6558         pDomain->AddUnmanagedImageToCache(wszLibName, hmod);
6559     }
6560
6561     return hmod.Extract();
6562 }
6563
6564 //---------------------------------------------------------
6565 // Loads the DLL and finds the procaddress for an N/Direct call.
6566 //---------------------------------------------------------
6567 /* static */
6568 VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
6569 {
6570     CONTRACTL
6571     {
6572         STANDARD_VM_CHECK;
6573         PRECONDITION(CheckPointer(pMD));
6574     }
6575     CONTRACTL_END;
6576
6577     //
6578     // On the phone, we only allow platform assemblies to define pinvokes
6579     // unless the host has asked us otherwise.
6580     //
6581
6582     if (pMD->IsClassConstructorTriggeredAtLinkTime())
6583     {
6584         pMD->GetMethodTable()->CheckRunClassInitThrowing();
6585     }
6586
6587     if (pMD->IsQCall())
6588     {
6589         LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget;
6590
6591         // Do not repeat the lookup if the QCall was hardbound during ngen
6592         if (pvTarget == NULL)
6593         {
6594             pvTarget = ECall::GetQCallImpl(pMD);
6595         }
6596         else
6597         {
6598             _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD));
6599         }
6600
6601         pMD->SetNDirectTarget(pvTarget);
6602         return;
6603     }
6604
6605     // Loading unmanaged dlls can trigger dllmains which certainly count as code execution!
6606     pMD->EnsureActive();
6607
6608     LoadLibErrorTracker errorTracker;
6609
6610     BOOL fSuccess = FALSE;
6611     HINSTANCE hmod = LoadLibraryModule( pMD, &errorTracker );
6612     if ( hmod )
6613     {
6614         LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
6615         if (pvTarget)
6616         {
6617
6618 #ifdef MDA_SUPPORTED
6619             MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke);
6620             if (pOverlapCheck && pOverlapCheck->ShouldHook(pMD))
6621             {
6622                 LPVOID pNewTarget = pOverlapCheck->Register(hmod,pvTarget);
6623                 if (pNewTarget)
6624                 {
6625                     pvTarget = pNewTarget;
6626                 }
6627             }
6628 #endif
6629             pMD->SetNDirectTarget(pvTarget);
6630             fSuccess = TRUE;
6631         }
6632     }
6633
6634     if (!fSuccess)
6635     {
6636         if (pMD->GetLibName() == NULL)
6637             COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME);
6638         
6639         StackSString ssLibName(SString::Utf8, pMD->GetLibName());
6640
6641         if (!hmod)
6642         {
6643             errorTracker.Throw(ssLibName);
6644         }
6645
6646         WCHAR wszEPName[50];
6647         if(WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0)
6648         {
6649             wszEPName[0] = W('?');
6650             wszEPName[1] = W('\0');
6651         }
6652
6653         COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS, ssLibName.GetUnicode(), wszEPName);
6654     }
6655 }
6656
6657
6658 //---------------------------------------------------------
6659 // One-time init
6660 //---------------------------------------------------------
6661 /*static*/ void NDirect::Init()
6662 {
6663     CONTRACTL
6664     {
6665         THROWS;
6666         GC_TRIGGERS;
6667         MODE_ANY;
6668         INJECT_FAULT(COMPlusThrowOM());
6669     }
6670     CONTRACTL_END;
6671
6672 }
6673
6674
6675 //==========================================================================
6676 // This function is reached only via NDirectImportThunk. It's purpose
6677 // is to ensure that the target DLL is fully loaded and ready to run.
6678 //
6679 // FUN FACTS: Though this function is actually entered in unmanaged mode,
6680 // it can reenter managed mode and throw a COM+ exception if the DLL linking
6681 // fails.
6682 //==========================================================================
6683
6684
6685 EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD)
6686 {
6687     LPVOID ret = NULL;
6688
6689     BEGIN_PRESERVE_LAST_ERROR;
6690
6691     CONTRACTL
6692     {
6693         THROWS;
6694         GC_TRIGGERS;
6695         MODE_PREEMPTIVE;
6696         SO_TOLERANT;
6697     }
6698     CONTRACTL_END;
6699
6700     INSTALL_MANAGED_EXCEPTION_DISPATCHER;
6701     // this function is called by CLR to native assembly stubs which are called by 
6702     // managed code as a result, we need an unwind and continue handler to translate 
6703     // any of our internal exceptions into managed exceptions.
6704     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
6705
6706 #ifdef FEATURE_MIXEDMODE // IJW
6707     if (pMD->IsEarlyBound())
6708     {
6709         if (!pMD->IsZapped())
6710         {
6711             // we need the MD to be populated in case we decide to build an intercept
6712             // stub to wrap the target in InitEarlyBoundNDirectTarget
6713             PInvokeStaticSigInfo sigInfo;
6714             NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
6715         }
6716
6717         pMD->InitEarlyBoundNDirectTarget();
6718     }
6719     else
6720 #endif // FEATURE_MIXEDMODE
6721     {
6722         //
6723         // Otherwise we're in an inlined pinvoke late bound MD
6724         //
6725         INDEBUG(Thread *pThread = GetThread());
6726         {
6727             _ASSERTE(pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr());
6728
6729             CONSISTENCY_CHECK(pMD->IsNDirect());
6730             //
6731             // With IL stubs, we don't have to do anything but ensure the DLL is loaded.
6732             //
6733
6734             if (!pMD->GetModule()->GetSecurityDescriptor()->CanCallUnmanagedCode())
6735                 Security::ThrowSecurityException(g_SecurityPermissionClassName, SPFLAGSUNMANAGEDCODE);
6736
6737             if (!pMD->IsZapped())
6738             {
6739                 PInvokeStaticSigInfo sigInfo;
6740                 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
6741             }
6742             else
6743             {
6744                 // must have been populated at NGEN time
6745                 _ASSERTE(pMD->GetLibName() != NULL);
6746             }
6747
6748             pMD->CheckRestore();
6749
6750             NDirect::NDirectLink(pMD);
6751         }
6752     }
6753
6754     ret = pMD->GetNDirectTarget();
6755
6756     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
6757     UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
6758
6759     END_PRESERVE_LAST_ERROR;
6760
6761     return ret;
6762 }
6763
6764 //===========================================================================
6765 //  Support for Pinvoke Calli instruction
6766 //
6767 //===========================================================================
6768
6769 EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
6770 {
6771     BEGIN_PRESERVE_LAST_ERROR;
6772
6773     STATIC_CONTRACT_THROWS;
6774     STATIC_CONTRACT_GC_TRIGGERS;
6775     STATIC_CONTRACT_MODE_COOPERATIVE;
6776     STATIC_CONTRACT_ENTRY_POINT;
6777
6778     MAKE_CURRENT_THREAD_AVAILABLE();
6779
6780 #ifdef _DEBUG
6781     Thread::ObjectRefFlush(CURRENT_THREAD);
6782 #endif
6783
6784     FrameWithCookie<PrestubMethodFrame> frame(pTransitionBlock, pMD);
6785     PrestubMethodFrame * pFrame = &frame;
6786
6787     pFrame->Push(CURRENT_THREAD);
6788
6789     _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
6790     _ASSERTE(pMD == pFrame->GetFunction());
6791
6792     GetILStubForCalli(pVASigCookie, pMD);
6793
6794     pFrame->Pop(CURRENT_THREAD);
6795
6796     END_PRESERVE_LAST_ERROR;
6797 }
6798
6799 EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
6800 {
6801     BEGIN_PRESERVE_LAST_ERROR;
6802
6803     STATIC_CONTRACT_THROWS;
6804     STATIC_CONTRACT_GC_TRIGGERS;
6805     STATIC_CONTRACT_MODE_COOPERATIVE;
6806     STATIC_CONTRACT_ENTRY_POINT;
6807
6808     MAKE_CURRENT_THREAD_AVAILABLE();
6809
6810 #ifdef _DEBUG
6811     Thread::ObjectRefFlush(CURRENT_THREAD);
6812 #endif
6813
6814     FrameWithCookie<PInvokeCalliFrame> frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget);
6815     PInvokeCalliFrame * pFrame = &frame;
6816
6817     pFrame->Push(CURRENT_THREAD);
6818
6819     _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
6820
6821     GetILStubForCalli(pVASigCookie, NULL);
6822
6823     pFrame->Pop(CURRENT_THREAD);
6824
6825     END_PRESERVE_LAST_ERROR;
6826 }
6827
6828 PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
6829 {
6830     CONTRACT(PCODE)
6831     {
6832         THROWS;
6833         GC_TRIGGERS;
6834         ENTRY_POINT;
6835         MODE_ANY;
6836         PRECONDITION(CheckPointer(pVASigCookie));
6837         PRECONDITION(CheckPointer(pMD, NULL_OK));
6838         POSTCONDITION(RETVAL != NULL);
6839     }
6840     CONTRACT_END;
6841
6842     PCODE pTempILStub = NULL;
6843
6844     INSTALL_MANAGED_EXCEPTION_DISPATCHER;
6845     // this function is called by CLR to native assembly stubs which are called by 
6846     // managed code as a result, we need an unwind and continue handler to translate 
6847     // any of our internal exceptions into managed exceptions.
6848     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
6849
6850     // Force a GC if the stress level is high enough
6851     GCStress<cfg_any>::MaybeTrigger();
6852
6853     GCX_PREEMP();
6854
6855     Signature signature = pVASigCookie->signature;
6856     CorPinvokeMap unmgdCallConv = pmNoMangle;
6857     
6858     DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
6859     
6860     // The MethodDesc pointer may in fact be the unmanaged target, see PInvokeStubs.asm.
6861     if (pMD == NULL || (UINT_PTR)pMD & 0x1)
6862     {
6863         pMD = NULL;
6864         dwStubFlags |= NDIRECTSTUB_FL_UNMANAGED_CALLI;
6865
6866         // need to convert the CALLI signature to stub signature with managed calling convention
6867         switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->signature))
6868         {
6869             case IMAGE_CEE_CS_CALLCONV_C:
6870                     unmgdCallConv = pmCallConvCdecl;
6871                     break;
6872             case IMAGE_CEE_CS_CALLCONV_STDCALL:
6873                     unmgdCallConv = pmCallConvStdcall;
6874                     break;
6875             case IMAGE_CEE_CS_CALLCONV_THISCALL:
6876                     unmgdCallConv = pmCallConvThiscall;
6877                     break;
6878             case IMAGE_CEE_CS_CALLCONV_FASTCALL:
6879                     unmgdCallConv = pmCallConvFastcall;
6880                     break;
6881             default:
6882                     COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
6883         }
6884
6885         LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
6886         PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
6887         CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
6888         
6889         // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT
6890         *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK;
6891         *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT;
6892
6893         signature = Signature(new_sig, signature.GetRawSigLen());
6894     }
6895     else
6896     {
6897         _ASSERTE(pMD->IsNDirect());
6898         dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
6899
6900         // vararg P/Invoke must be cdecl
6901         unmgdCallConv = pmCallConvCdecl;
6902
6903         if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
6904         {
6905             dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
6906         }
6907     }
6908
6909     mdMethodDef md;
6910     CorNativeLinkFlags nlFlags;
6911     CorNativeLinkType  nlType;
6912
6913     if (pMD != NULL)
6914     {
6915         PInvokeStaticSigInfo sigInfo(pMD);
6916
6917         md = pMD->GetMemberDef();
6918         nlFlags = sigInfo.GetLinkFlags();
6919         nlType  = sigInfo.GetCharSet();
6920     }
6921     else
6922     {
6923         md = mdMethodDefNil;
6924         nlFlags = nlfNone;
6925         nlType  = nltAnsi;
6926     }
6927
6928     StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule);
6929
6930     MethodDesc* pStubMD = NDirect::CreateCLRToNativeILStub(&sigDesc,
6931                                     nlType, 
6932                                     nlFlags, 
6933                                     unmgdCallConv,
6934                                     dwStubFlags);
6935
6936     pTempILStub = JitILStub(pStubMD);
6937
6938     InterlockedCompareExchangeT<PCODE>(&pVASigCookie->pNDirectILStub,
6939                                                     pTempILStub,
6940                                                     NULL);
6941
6942     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
6943     UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
6944
6945     RETURN pVASigCookie->pNDirectILStub;
6946 }
6947
6948 #endif // CROSSGEN_COMPILE
6949
6950 #endif // #ifndef DACCESS_COMPILE
6951
6952 //
6953 // Truncates a SString by first converting it to unicode and truncate it 
6954 // if it is larger than size. "..." will be appened if it is truncated.
6955 //
6956 void TruncateUnicodeString(SString &string, COUNT_T bufSize)
6957 {
6958     string.Normalize();
6959     if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize)
6960     {
6961         _ASSERTE(bufSize / sizeof(WCHAR) > 4);
6962         string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4);
6963         string.Append(W("..."));
6964     }
6965 }