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