924a50fe9d5dd81ab17d122b4033e53d9a051dcf
[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             nlt = nltUnicode; break;
2969         case nltAuto:
2970 #ifdef PLATFORM_WINDOWS
2971             nlt = nltUnicode;
2972 #else
2973             nlt = nltAnsi; // We don't have a utf8 charset in metadata yet, but ANSI == UTF-8 off-Windows
2974 #endif
2975         break;
2976         default:
2977             hr = E_FAIL; goto ErrExit;
2978         }
2979         SetCharSet ( nlt );
2980         SetBestFitMapping (namedArgs[MDA_BestFitMapping].val.u1);
2981         SetThrowOnUnmappableChar (namedArgs[MDA_ThrowOnUnmappableChar].val.u1);
2982         if (namedArgs[MDA_SetLastError].val.u1) 
2983             SetLinkFlags ((CorNativeLinkFlags)(nlfLastError | GetLinkFlags()));
2984     }
2985
2986             
2987 ErrExit:    
2988     if (hr != S_OK)
2989         SetError(IDS_EE_NDIRECT_BADNATL);   
2990
2991     InitCallConv(callConv, pMD->IsVarArg()); 
2992
2993     if (throwOnError)
2994         ReportErrors();   
2995 }
2996
2997 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
2998     Signature sig, Module* pModule, ThrowOnError throwOnError)
2999 {
3000     CONTRACTL
3001     {
3002         THROWS;
3003         GC_NOTRIGGER;
3004         MODE_ANY;
3005
3006         PRECONDITION(CheckPointer(pModule));
3007     }
3008     CONTRACTL_END;
3009
3010     PreInit(pModule, NULL);
3011     m_sig = sig;
3012     SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
3013     InitCallConv((CorPinvokeMap)0, FALSE);
3014     
3015     if (throwOnError)
3016         ReportErrors();    
3017 }
3018
3019 void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LPCUTF8 *ppEntryPointName)
3020 {
3021     CONTRACTL
3022     {
3023         THROWS;
3024         GC_NOTRIGGER;
3025         MODE_ANY;
3026
3027         PRECONDITION(CheckPointer(pMD));
3028
3029         // These preconditions to prevent multithreaded regression 
3030         // where pMD->ndirect.m_szLibName was passed in directly, cleared 
3031         // by this API, then accessed on another thread before being reset here.
3032         PRECONDITION(CheckPointer(ppLibName, NULL_OK) && (!ppLibName || *ppLibName == NULL)); 
3033         PRECONDITION(CheckPointer(ppEntryPointName, NULL_OK) && (!ppEntryPointName || *ppEntryPointName == NULL));
3034     }
3035     CONTRACTL_END;
3036
3037     // initialize data members to defaults
3038     PreInit(pMD);
3039
3040     // System.Runtime.InteropServices.DllImportAttribute
3041     IMDInternalImport  *pInternalImport = pMD->GetMDImport();
3042     CorPinvokeMap mappingFlags = pmMaxValue;
3043     mdModuleRef modref = mdModuleRefNil;
3044     if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
3045     {
3046 #if !defined(CROSSGEN_COMPILE) // IJW
3047         // The guessing heuristic has been broken with NGen for a long time since we stopped loading
3048         // images at NGen time using full LoadLibrary. The DLL references are not resolved correctly
3049         // without full LoadLibrary.
3050         //
3051         // Disable the heuristic consistently during NGen so that it does not kick in by accident.
3052         if (!IsCompilationProcess())
3053             BestGuessNDirectDefaults(pMD);
3054 #endif
3055
3056         InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
3057         return;
3058     }
3059     
3060     // out parameter pEntryPointName
3061     if (ppEntryPointName && *ppEntryPointName == NULL)
3062         *ppEntryPointName = pMD->GetName();
3063     
3064     // out parameter pLibName
3065     if (ppLibName != NULL)
3066     {
3067         if (FAILED(pInternalImport->GetModuleRefProps(modref, ppLibName)))
3068         {
3069             SetError(IDS_CLASSLOAD_BADFORMAT);
3070             return;
3071         }
3072     }
3073     
3074     // m_callConv
3075     InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
3076     
3077     // m_bestFit
3078     CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
3079     if (bestFitMask == pmBestFitEnabled)
3080         SetBestFitMapping (TRUE);
3081     else if (bestFitMask == pmBestFitDisabled)
3082         SetBestFitMapping (FALSE);
3083
3084     // m_bThrowOnUnmappableChar
3085     CorPinvokeMap unmappableMask = (CorPinvokeMap)(mappingFlags & pmThrowOnUnmappableCharMask);
3086     if (unmappableMask == pmThrowOnUnmappableCharEnabled)
3087         SetThrowOnUnmappableChar (TRUE);
3088     else if (unmappableMask == pmThrowOnUnmappableCharDisabled)
3089         SetThrowOnUnmappableChar (FALSE);
3090
3091     // inkFlags : CorPinvoke -> CorNativeLinkFlags
3092     if (mappingFlags & pmSupportsLastError)
3093         SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3094     if (mappingFlags & pmNoMangle)
3095         SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfNoMangle));
3096
3097     // Keep in sync with the handling of CorNativeLinkType in
3098     // PInvokeStaticSigInfo::PInvokeStaticSigInfo.
3099     
3100     // charset : CorPinvoke -> CorNativeLinkType
3101     CorPinvokeMap charSetMask = (CorPinvokeMap)(mappingFlags & (pmCharSetNotSpec | pmCharSetAnsi | pmCharSetUnicode | pmCharSetAuto));
3102     if (charSetMask == pmCharSetNotSpec || charSetMask == pmCharSetAnsi)
3103     {
3104         SetCharSet (nltAnsi);
3105     }
3106     else if (charSetMask == pmCharSetUnicode)
3107     {
3108         SetCharSet (nltUnicode);
3109     }
3110     else if (charSetMask == pmCharSetAuto)
3111     {
3112 #ifdef PLATFORM_WINDOWS
3113         SetCharSet(nltUnicode);
3114 #else
3115         SetCharSet(nltAnsi); // We don't have a utf8 charset in metadata yet, but ANSI == UTF-8 off-Windows
3116 #endif
3117     }
3118     else
3119     {
3120         SetError(IDS_EE_NDIRECT_BADNATL);
3121     }
3122 }
3123
3124 #if !defined(CROSSGEN_COMPILE) // IJW
3125
3126 // This function would work, but be unused on Unix. Ifdefing out to avoid build errors due to the unused function.
3127 #if !defined (FEATURE_PAL)
3128 static LPBYTE FollowIndirect(LPBYTE pTarget)
3129 {
3130     CONTRACT(LPBYTE)
3131     {
3132         NOTHROW;
3133         GC_NOTRIGGER;
3134         MODE_ANY;
3135         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3136     }
3137     CONTRACT_END;
3138
3139     LPBYTE pRet = NULL;
3140
3141     EX_TRY
3142     {
3143         AVInRuntimeImplOkayHolder AVOkay;
3144
3145 #ifdef _TARGET_X86_
3146         if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3147         {
3148             pRet = **(LPBYTE**)(pTarget + 2);
3149         }
3150 #elif defined(_TARGET_AMD64_)
3151         if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3152         {
3153             INT64 rva = *(INT32*)(pTarget + 2);
3154             pRet = *(LPBYTE*)(pTarget + 6 + rva);
3155         }
3156 #endif
3157     }
3158     EX_CATCH
3159     {
3160         // Catch AVs here.
3161     }
3162     EX_END_CATCH(SwallowAllExceptions);
3163
3164     RETURN pRet;
3165 }
3166 #endif // !FEATURE_PAL
3167
3168 BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
3169 {
3170     CONTRACTL
3171     {
3172         NOTHROW;
3173         GC_NOTRIGGER;
3174         MODE_ANY;
3175     }
3176     CONTRACTL_END;
3177
3178 #if !defined(FEATURE_PAL)
3179     static LPBYTE pGetLastError = NULL;
3180     if (!pGetLastError)
3181     {
3182         // No need to use a holder here, since no cleanup is necessary.
3183         HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
3184         if (hMod)
3185         {
3186             pGetLastError = (LPBYTE)GetProcAddress(hMod, "GetLastError");
3187             if (!pGetLastError)
3188             {
3189                 // This should never happen but better to be cautious.
3190                 pGetLastError = (LPBYTE)-1;
3191             }
3192         }
3193         else
3194         {
3195             // We failed to get the module handle for kernel32.dll. This is almost impossible
3196             // however better to err on the side of caution.
3197             pGetLastError = (LPBYTE)-1;
3198         }
3199     }
3200
3201     if (pTarget == pGetLastError)
3202         return TRUE;
3203
3204     if (pTarget == NULL)
3205         return FALSE;
3206
3207     LPBYTE pTarget2 = FollowIndirect(pTarget);
3208     if (pTarget2)
3209     {
3210         // jmp [xxxx] - could be an import thunk
3211         return pTarget2 == pGetLastError;
3212     }
3213 #endif // !FEATURE_PAL
3214
3215     return FALSE;
3216 }
3217
3218 DWORD STDMETHODCALLTYPE FalseGetLastError()
3219 {
3220     WRAPPER_NO_CONTRACT;
3221
3222     return GetThread()->m_dwLastError;
3223 }
3224
3225 void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
3226 {
3227     CONTRACTL
3228     {
3229         NOTHROW;
3230         GC_NOTRIGGER;
3231         MODE_ANY;
3232     }
3233     CONTRACTL_END;
3234
3235     if (!pMD->IsNDirect())
3236         return;
3237
3238     NDirectMethodDesc* pMDD = (NDirectMethodDesc*)pMD;
3239
3240     if (!pMDD->IsEarlyBound())
3241         return;
3242
3243     LPVOID pTarget = NULL;
3244
3245     // NOTE: If we get inside this block, and this is a call to GetLastError, 
3246     //  then InitEarlyBoundNDirectTarget has not been run yet.
3247     if (pMDD->NDirectTargetIsImportThunk())
3248     {
3249         // Get the unmanaged callsite.
3250         pTarget = (LPVOID)pMDD->GetModule()->GetInternalPInvokeTarget(pMDD->GetRVA());
3251
3252         // If this is a call to GetLastError, then we haven't overwritten m_pNativeNDirectTarget yet.
3253         if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)pTarget))
3254             pTarget = (BYTE*)FalseGetLastError;
3255     }
3256     else
3257     {
3258         pTarget = pMDD->GetNativeNDirectTarget();
3259     }
3260 }
3261
3262 #endif // !CROSSGEN_COMPILE
3263
3264 inline CorPinvokeMap GetDefaultCallConv(BOOL bIsVarArg)
3265 {
3266 #ifdef PLATFORM_UNIX
3267     return pmCallConvCdecl;
3268 #else // PLATFORM_UNIX
3269     return bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3270 #endif // !PLATFORM_UNIX
3271 }
3272
3273 void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
3274 {
3275     CONTRACTL
3276     {
3277         NOTHROW;
3278         GC_NOTRIGGER;
3279         MODE_ANY;
3280     }
3281     CONTRACTL_END
3282
3283     // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
3284     if (callConv == pmCallConvWinapi)
3285         callConv = GetDefaultCallConv(bIsVarArg);
3286
3287     CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
3288     BOOL fSuccess = MetaSig::GetUnmanagedCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv);
3289
3290     if (!fSuccess)
3291     {
3292         SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format
3293     }
3294
3295     // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
3296     // to do this before we check to make sure the PInvoke map calling convention and the 
3297     // signature calling convention match for compatibility reasons.
3298     if (sigCallConv == pmCallConvWinapi)
3299         sigCallConv = GetDefaultCallConv(bIsVarArg);
3300
3301     if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
3302         SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
3303
3304     if (callConv == 0 && sigCallConv == 0)
3305         m_callConv = GetDefaultCallConv(bIsVarArg);
3306     else if (callConv != 0)
3307         m_callConv = callConv;
3308     else
3309         m_callConv = sigCallConv;
3310
3311     if (bIsVarArg && m_callConv != pmCallConvCdecl)
3312         SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
3313 }
3314
3315 void PInvokeStaticSigInfo::ReportErrors()
3316 {
3317     CONTRACTL
3318     {
3319         THROWS;
3320         GC_NOTRIGGER;
3321         MODE_ANY;
3322     }
3323     CONTRACTL_END;
3324
3325     if (m_error != 0)
3326         COMPlusThrow(kTypeLoadException, m_error);      
3327 }
3328
3329
3330 //---------------------------------------------------------
3331 // Does a class or method have a NAT_L CustomAttribute?
3332 //
3333 // S_OK    = yes
3334 // S_FALSE = no
3335 // FAILED  = unknown because something failed.
3336 //---------------------------------------------------------
3337 /*static*/
3338 HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs)
3339 {
3340     CONTRACTL
3341     {
3342         NOTHROW;
3343         GC_NOTRIGGER;
3344         MODE_ANY;
3345
3346         PRECONDITION(CheckPointer(pInternalImport));
3347         PRECONDITION(TypeFromToken(token) == mdtMethodDef);
3348     }
3349     CONTRACTL_END;
3350
3351     // Check method flags first before trying to find the custom value
3352     if (!IsReallyMdPinvokeImpl(dwMemberAttrs))
3353         return S_FALSE;
3354
3355     DWORD   mappingFlags;
3356     LPCSTR  pszImportName;
3357     mdModuleRef modref;
3358
3359     if (SUCCEEDED(pInternalImport->GetPinvokeMap(token, &mappingFlags, &pszImportName, &modref)))
3360         return S_OK;
3361
3362     return S_FALSE;
3363 }
3364
3365
3366 // Either MD or signature & module must be given.
3367 /*static*/
3368 BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*/, Module *pModule /*= NULL*/)
3369 {
3370     CONTRACTL
3371     {
3372         STANDARD_VM_CHECK;
3373         PRECONDITION(pMD != NULL || (pSig != NULL && pModule != NULL));
3374     }
3375     CONTRACTL_END;
3376
3377     // As a by-product, when returning FALSE we will also set the native stack size to the MD if it's
3378     // an NDirectMethodDesc. This number is needed to link the P/Invoke (it determines the @n entry
3379     // point name suffix and affects alignment thunk generation on the Mac). If this method returns
3380     // TRUE, the stack size will be set when building the marshaling IL stub.
3381     DWORD dwStackSize = 0;
3382     CorPinvokeMap callConv = (CorPinvokeMap)0;
3383
3384     if (pMD != NULL)
3385     {
3386         if (pMD->IsNDirect() || pMD->IsComPlusCall())
3387         {
3388             // HRESULT swapping is handled by stub
3389             if ((pMD->GetImplAttrs() & miPreserveSig) == 0)
3390                 return TRUE;
3391         }
3392
3393         // SetLastError is handled by stub
3394         PInvokeStaticSigInfo sigInfo(pMD);
3395         if (sigInfo.GetLinkFlags() & nlfLastError)
3396             return TRUE;
3397
3398         // LCID argument is handled by stub
3399         if (GetLCIDParameterIndex(pMD) != -1)
3400             return TRUE;
3401
3402         // making sure that cctor has run may be handled by stub
3403         if (pMD->IsNDirect() && ((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
3404             return TRUE;
3405
3406         callConv = sigInfo.GetCallConv();
3407     }
3408
3409     if (pSig == NULL)
3410     {
3411         PREFIX_ASSUME(pMD != NULL);
3412
3413         pSig = pMD->GetSig();
3414         pModule = pMD->GetModule();
3415     }
3416
3417     // Check to make certain that the signature only contains types that marshal trivially
3418     SigPointer ptr(pSig);
3419     IfFailThrow(ptr.GetCallingConvInfo(NULL));
3420     ULONG numArgs;
3421     IfFailThrow(ptr.GetData(&numArgs));
3422     numArgs++;   // +1 for return type
3423
3424     // We'll need to parse parameter native types
3425     mdParamDef *pParamTokenArray = (mdParamDef *)_alloca(numArgs * sizeof(mdParamDef));
3426     IMDInternalImport *pMDImport = pModule->GetMDImport();
3427
3428     SigTypeContext emptyTypeContext;
3429
3430     mdMethodDef methodToken = mdMethodDefNil;
3431     if (pMD != NULL)
3432     {
3433         methodToken = pMD->GetMemberDef();
3434     }
3435     CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
3436
3437     for (ULONG i = 0; i < numArgs; i++)
3438     {
3439         SigPointer arg = ptr;
3440         CorElementType type;
3441         IfFailThrow(arg.PeekElemType(&type));
3442
3443         switch (type)
3444         {
3445             case ELEMENT_TYPE_PTR:
3446             {
3447                 IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR
3448                 IfFailThrow(arg.PeekElemType(&type));
3449
3450                 if (type == ELEMENT_TYPE_VALUETYPE)
3451                 {
3452                     if ((arg.HasCustomModifier(pModule,
3453                                               "Microsoft.VisualC.NeedsCopyConstructorModifier",
3454                                               ELEMENT_TYPE_CMOD_REQD)) ||
3455                         (arg.HasCustomModifier(pModule,
3456                                               "System.Runtime.CompilerServices.IsCopyConstructed",
3457                                               ELEMENT_TYPE_CMOD_REQD)))
3458                     {
3459                         return TRUE;
3460                     }
3461                 }
3462                 if (i > 0) dwStackSize += sizeof(SLOT);
3463                 break;
3464             }
3465
3466             case ELEMENT_TYPE_INTERNAL:
3467
3468                 // this check is not functional in DAC and provides no security against a malicious dump
3469                 // the DAC is prepared to receive an invalid type handle
3470 #ifndef DACCESS_COMPILE
3471                 if (pModule->IsSigInIL(arg.GetPtr()))
3472                     THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
3473 #endif
3474
3475                 /* Fall thru */
3476
3477             case ELEMENT_TYPE_VALUETYPE:
3478             {
3479                 TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext);
3480
3481                 // JIT can handle internal blittable value types
3482                 if (!hndArgType.IsBlittable() && !hndArgType.IsEnum())
3483                 {
3484                     return TRUE;
3485                 }
3486
3487 #ifdef FEATURE_READYTORUN_COMPILER
3488                 if (IsReadyToRunCompilation())
3489                 {
3490                     if (!hndArgType.AsMethodTable()->IsLayoutInCurrentVersionBubble())
3491                         return TRUE;
3492                 }
3493 #endif
3494
3495                 // return value is fine as long as it can be normalized to an integer
3496                 if (i == 0)
3497                 {
3498                     CorElementType normalizedType = hndArgType.GetInternalCorElementType();
3499                     if (normalizedType == ELEMENT_TYPE_VALUETYPE)
3500                     {
3501                         // it is a structure even after normalization
3502                         return TRUE;
3503                     }
3504                 }
3505                 else
3506                 {
3507                     dwStackSize += StackElemSize(hndArgType.GetSize());
3508                 }
3509                 break;
3510             }
3511             
3512             case ELEMENT_TYPE_BOOLEAN:
3513             case ELEMENT_TYPE_CHAR:
3514             {
3515                 // Bool requires marshaling
3516                 // Char may require marshaling (MARSHAL_TYPE_ANSICHAR)
3517                 return TRUE;
3518             }
3519
3520             default:
3521             {
3522                 if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
3523                 {
3524                     if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
3525                 }
3526                 else
3527                 {
3528                     // other non-primitive type - requires marshaling
3529                     return TRUE;
3530                 }
3531             }
3532         }
3533
3534         // check for explicit MarshalAs
3535         NativeTypeParamInfo paramInfo;
3536
3537         if (pParamTokenArray[i] != mdParamDefNil)
3538         {
3539             if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, &paramInfo) ||
3540                 paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT)
3541             {
3542                 // Presence of MarshalAs does not necessitate marshaling (it could as well be the default
3543                 // for the type), but it's a good enough heuristic. We definitely don't want to duplicate
3544                 // the logic from code:MarshalInfo.MarshalInfo here.
3545                 return TRUE;
3546             }
3547         }
3548
3549         IfFailThrow(ptr.SkipExactlyOne());
3550     }
3551
3552     if (!FitsInU2(dwStackSize))
3553         return TRUE;
3554
3555     // do not set the stack size for varargs - the number is call site specific
3556     if (pMD != NULL && !pMD->IsVarArg())
3557     {
3558         if (pMD->IsNDirect())
3559         {
3560             ((NDirectMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize), callConv);
3561         }
3562 #ifdef FEATURE_COMINTEROP
3563         else if (pMD->IsComPlusCall())
3564         {
3565             // calling convention is always stdcall
3566             ((ComPlusCallMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize));
3567         }
3568 #endif // FEATURE_COMINTEROP
3569     }
3570
3571     return FALSE;
3572 }
3573
3574
3575 // factorization of CreateNDirectStubWorker
3576 static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig&           msig,
3577                                                      mdParamDef*        params,
3578                                                      CorNativeLinkType  nlType,
3579                                                      CorNativeLinkFlags nlFlags,
3580                                                      UINT               argidx,  // this is used for reverse pinvoke hresult swapping
3581                                                      StubState*         pss,
3582                                                      BOOL               isInstanceMethod,
3583                                                      int                argOffset,
3584                                                      DWORD              dwStubFlags,
3585                                                      MethodDesc         *pMD,
3586                                                      UINT&              nativeStackOffset,
3587                                                      bool&              fStubNeedsCOM,
3588                                                      int                nativeArgIndex
3589                                                      DEBUG_ARG(LPCUTF8  pDebugName)
3590                                                      DEBUG_ARG(LPCUTF8  pDebugClassName)
3591                                                      )
3592 {
3593     CONTRACTL
3594     {
3595         STANDARD_VM_CHECK;
3596
3597         PRECONDITION(CheckPointer(params));
3598         PRECONDITION(CheckPointer(pss));
3599         PRECONDITION(CheckPointer(pMD, NULL_OK));
3600     }
3601     CONTRACTL_END;
3602
3603     MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3604
3605     MarshalInfo::MarshalScenario ms;
3606 #ifdef FEATURE_COMINTEROP
3607     if (SF_IsCOMStub(dwStubFlags))
3608     {
3609         if (SF_IsWinRTStub(dwStubFlags))
3610             ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3611         else
3612             ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3613     }
3614     else
3615 #endif // FEATURE_COMINTEROP
3616     {
3617         ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
3618     }
3619
3620 #ifdef FEATURE_COMINTEROP
3621     if (SF_IsWinRTCtorStub(dwStubFlags))
3622     {
3623         _ASSERTE(msig.GetReturnType() == ELEMENT_TYPE_VOID);
3624         _ASSERTE(SF_IsHRESULTSwapping(dwStubFlags));
3625         
3626         pss->MarshalFactoryReturn();
3627         nativeStackOffset += sizeof(LPVOID);
3628         if (SF_IsWinRTCompositionStub(dwStubFlags))
3629         {
3630             nativeStackOffset += 2 * sizeof(LPVOID);
3631         }
3632     }
3633     else
3634 #endif // FEATURE_COMINTEROP
3635     if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
3636     {
3637         MarshalInfo returnInfo(msig.GetModule(),
3638                                 msig.GetReturnProps(),
3639                                 msig.GetSigTypeContext(),
3640                                 params[0],
3641                                 ms,
3642                                 nlType,
3643                                 nlFlags,
3644                                 FALSE,
3645                                 argidx,
3646                                 msig.NumFixedArgs(),
3647                                 SF_IsBestFit(dwStubFlags),
3648                                 SF_IsThrowOnUnmappableChar(dwStubFlags),
3649                                 TRUE,
3650                                 isInstanceMethod,
3651                                 pMD,
3652                                 TRUE
3653                                 DEBUG_ARG(pDebugName)
3654                                 DEBUG_ARG(pDebugClassName)
3655                                 DEBUG_ARG(0)
3656                                 );
3657
3658         marshalType = returnInfo.GetMarshalType();
3659
3660         fStubNeedsCOM |= returnInfo.MarshalerRequiresCOM();
3661
3662 #ifdef FEATURE_COMINTEROP
3663         if (marshalType == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3664         {
3665             // Hidden length arrays are only valid with HRESULT swapping
3666             if (!SF_IsHRESULTSwapping(dwStubFlags))
3667             {
3668                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3669             }
3670
3671             // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3672             returnInfo.SetHiddenLengthParamIndex(static_cast<UINT16>(nativeArgIndex));
3673
3674             // Inject the hidden argument so that it winds up at the end of the method signature
3675             pss->MarshalHiddenLengthArgument(&returnInfo, TRUE);
3676             nativeStackOffset += returnInfo.GetHiddenLengthParamStackSize();
3677
3678             if (SF_IsReverseStub(dwStubFlags))
3679             {
3680                 ++argOffset;
3681             }
3682         }
3683
3684         if (SF_IsCOMStub(dwStubFlags))
3685         {
3686             // We don't support native methods that return VARIANTs, non-blittable structs, GUIDs, or DECIMALs directly.
3687             if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT ||
3688                 marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS ||
3689                 marshalType == MarshalInfo::MARSHAL_TYPE_GUID ||
3690                 marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL)
3691             {
3692                 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3693                 {
3694                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3695                 }
3696             }
3697
3698             pss->MarshalReturn(&returnInfo, argOffset);
3699         }
3700         else
3701 #endif // FEATURE_COMINTEROP
3702         {
3703             if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
3704                     || marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS
3705                     || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
3706                     || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
3707 #ifdef FEATURE_COMINTEROP                    
3708                     || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
3709 #endif // FEATURE_COMINTEROP
3710                 )
3711             {
3712                 if (SF_IsHRESULTSwapping(dwStubFlags))
3713                 {
3714                     // V1 restriction: we could implement this but it's late in the game to do so.
3715                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3716                 }
3717             }
3718             else if (marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY
3719                     || marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET
3720                     || marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
3721 #ifdef FEATURE_COMINTEROP
3722                     || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
3723 #endif // FEATURE_COMINTEROP
3724             )
3725             {
3726                 // Each of these types are non-blittable and according to its managed size should be returned in a return buffer on x86 in stdcall.
3727                 // However, its native size is small enough to be returned by-value.
3728                 // We don't know the native type representation early enough to get this correct, so we throw an exception here.
3729                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3730             }
3731             else if (IsUnsupportedTypedrefReturn(msig))
3732             {
3733                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3734             }
3735
3736 #ifdef FEATURE_COMINTEROP
3737             if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
3738             {
3739                 // No support for returning variants. This is a V1 restriction, due to the late date,
3740                 // don't want to add the special-case code to support this in light of low demand.
3741                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NOVARIANTRETURN);
3742             }
3743 #endif // FEATURE_COMINTEROP
3744
3745             pss->MarshalReturn(&returnInfo, argOffset);
3746         }
3747     }
3748
3749     return marshalType;
3750 }
3751
3752 static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
3753 {
3754     LIMITED_METHOD_CONTRACT;
3755 #ifdef _TARGET_X86_
3756     if (fThisCall)
3757     {
3758         // -1 means that the argument is not on the stack
3759         return (stackSize >= sizeof(SLOT) ? (stackSize - sizeof(SLOT)) : (UINT)-1);
3760     }
3761 #endif // _TARGET_X86_
3762     return stackSize;
3763 }
3764
3765 #ifdef FEATURE_COMINTEROP
3766
3767 struct HiddenParameterInfo
3768 {
3769     MarshalInfo *pManagedParam;     // Managed parameter which required the hidden parameter
3770     int          nativeIndex;       // 0 based index into the native method signature where the hidden parameter should be injected
3771 };
3772
3773 // Get the indexes of any hidden length parameters to be marshaled for the method
3774 //
3775 // At return, each value in the ppParamIndexes array is a 0 based index into the native method signature where
3776 // the length parameter for a hidden length array should be passed.  The MarshalInfo objects will also be
3777 // updated such that they all have explicit marshaling information.
3778 //
3779 // The caller is responsible for freeing the memory pointed to by ppParamIndexes
3780 void CheckForHiddenParameters(DWORD cParamMarshalInfo,
3781                               __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo,
3782                               __out DWORD *pcHiddenNativeParameters,
3783                               __out HiddenParameterInfo **ppHiddenNativeParameters)
3784 {
3785     CONTRACTL
3786     {
3787         STANDARD_VM_CHECK;
3788         PRECONDITION(CheckPointer(pParamMarshalInfo));
3789         PRECONDITION(CheckPointer(pcHiddenNativeParameters));
3790         PRECONDITION(CheckPointer(ppHiddenNativeParameters));
3791     }
3792     CONTRACTL_END;
3793
3794     NewArrayHolder<HiddenParameterInfo> hiddenParamInfo(new HiddenParameterInfo[cParamMarshalInfo]);
3795     DWORD foundInfoCount = 0;
3796
3797     for (DWORD iParam = 0; iParam < cParamMarshalInfo; ++iParam)
3798     {
3799         // Look for hidden length arrays, which all require additional parameters to be added
3800         if (pParamMarshalInfo[iParam].GetMarshalType() == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3801         {
3802             DWORD currentNativeIndex = iParam + foundInfoCount;
3803
3804             // The location of the length parameter is implicitly just before the array pointer.
3805             // We'll give it our current index, and bumping the found count will push us back a slot.
3806
3807             // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3808             pParamMarshalInfo[iParam].SetHiddenLengthParamIndex(static_cast<UINT16>(currentNativeIndex));
3809
3810             hiddenParamInfo[foundInfoCount].nativeIndex = pParamMarshalInfo[iParam].HiddenLengthParamIndex();
3811             hiddenParamInfo[foundInfoCount].pManagedParam = &(pParamMarshalInfo[iParam]);
3812             ++foundInfoCount;
3813         }
3814     }
3815
3816     *pcHiddenNativeParameters = foundInfoCount;
3817     *ppHiddenNativeParameters = hiddenParamInfo.Extract();
3818 }
3819
3820 bool IsHiddenParameter(int nativeArgIndex,
3821                        DWORD cHiddenParameters,
3822                        __in_ecount(cHiddenParameters) HiddenParameterInfo *pHiddenParameters,
3823                        __out HiddenParameterInfo **ppHiddenParameterInfo)
3824 {
3825     CONTRACTL
3826     {
3827         STANDARD_VM_CHECK;
3828         PRECONDITION(cHiddenParameters == 0 || CheckPointer(pHiddenParameters));
3829         PRECONDITION(CheckPointer(ppHiddenParameterInfo));
3830     }
3831     CONTRACTL_END;
3832
3833     *ppHiddenParameterInfo = NULL;
3834
3835     for (DWORD i = 0; i < cHiddenParameters; ++i)
3836     {
3837         _ASSERTE(pHiddenParameters[i].nativeIndex != -1);
3838         if (pHiddenParameters[i].nativeIndex == nativeArgIndex)
3839         {
3840             *ppHiddenParameterInfo = &(pHiddenParameters[i]);
3841             return true;
3842         }
3843     }
3844
3845     return false;
3846 }
3847
3848 #endif // FEATURE_COMINTEROP
3849
3850 //---------------------------------------------------------
3851 // Creates a new stub for a N/Direct call. Return refcount is 1.
3852 // Note that this function may now throw if it fails to create
3853 // a stub.
3854 //---------------------------------------------------------
3855 static void CreateNDirectStubWorker(StubState*         pss,
3856                                     StubSigDesc*       pSigDesc,
3857                                     CorNativeLinkType  nlType,
3858                                     CorNativeLinkFlags nlFlags,
3859                                     CorPinvokeMap      unmgdCallConv,
3860                                     DWORD              dwStubFlags,
3861                                     MethodDesc         *pMD,
3862                                     mdParamDef*        pParamTokenArray,
3863                                     int                iLCIDArg
3864                                     )
3865 {
3866     CONTRACTL
3867     {
3868         STANDARD_VM_CHECK;
3869
3870         PRECONDITION(CheckPointer(pss));
3871         PRECONDITION(CheckPointer(pSigDesc));
3872         PRECONDITION(CheckPointer(pMD, NULL_OK));
3873         PRECONDITION(!pMD || pMD->IsILStub() || (0 != pMD->GetMethodTable()->IsDelegate()) == SF_IsDelegateStub(dwStubFlags));
3874     }
3875     CONTRACTL_END;
3876
3877     SF_ConsistencyCheck(dwStubFlags);
3878
3879 #ifdef _DEBUG
3880     if (g_pConfig->ShouldBreakOnInteropStubSetup(pSigDesc->m_pDebugName))
3881         CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName));
3882 #endif // _DEBUG
3883
3884     Stub* pstub = NULL;
3885
3886     if (SF_IsCOMStub(dwStubFlags))
3887     {
3888         _ASSERTE(0 == nlType);
3889         _ASSERTE(0 == nlFlags);
3890         _ASSERTE(0 == unmgdCallConv);
3891     }
3892     else
3893     {
3894         _ASSERTE(nlType == nltAnsi || nlType == nltUnicode);
3895     }
3896     Module *pModule = pSigDesc->m_pModule;
3897
3898     //
3899     // Set up signature walking objects.
3900     //
3901
3902     MetaSig msig(pSigDesc->m_sig, 
3903                  pModule, 
3904                  &pSigDesc->m_typeContext);
3905
3906     if (SF_IsVarArgStub(dwStubFlags))
3907         msig.SetTreatAsVarArg();
3908
3909     bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
3910
3911     pss->SetLastError(nlFlags & nlfLastError);
3912
3913     // This has been in the product since forward P/Invoke via delegates was
3914     // introduced. It's wrong, but please keep it for backward compatibility.
3915     if (SF_IsDelegateStub(dwStubFlags))
3916         pss->SetLastError(TRUE);
3917
3918     pss->BeginEmit(dwStubFlags);
3919
3920     if (-1 != iLCIDArg)
3921     {
3922         // LCID is not supported on WinRT
3923         _ASSERTE(!SF_IsWinRTStub(dwStubFlags));
3924
3925         // The code to handle the LCID  will call MarshalLCID before calling MarshalArgument
3926         // on the argument the LCID should go after. So we just bump up the index here.
3927         iLCIDArg++;
3928     }
3929
3930     int numArgs = msig.NumFixedArgs();
3931
3932     // thiscall must have at least one parameter (the "this")
3933     if (fThisCall && numArgs == 0)
3934         COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
3935
3936     //
3937     // Now, emit the IL.
3938     //
3939
3940     int argOffset = 0;
3941
3942     MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3943
3944     //
3945     // Marshal the return value.
3946     //
3947
3948     UINT nativeStackSize = (SF_IsCOMStub(dwStubFlags) ? sizeof(SLOT) : 0);
3949     bool fHasCopyCtorArgs = false;
3950     bool fStubNeedsCOM = SF_IsCOMStub(dwStubFlags);
3951     
3952     // Normally we would like this to be false so that we use the correct signature 
3953     // in the IL_STUB, (i.e if it returns a value class then the signature will use that)
3954     // When this bool is true we change the return type to void and explicitly add a
3955     // return buffer argument as the first argument so as to match the native calling convention correctly.
3956     BOOL fMarshalReturnValueFirst = FALSE;
3957
3958     BOOL fReverseWithReturnBufferArg = FALSE;
3959     bool isInstanceMethod = fStubNeedsCOM || fThisCall;
3960     
3961     // We can only change fMarshalReturnValueFirst to true when we are NOT doing HRESULT-swapping!
3962     // When we are HRESULT-swapping, the managed return type is actually the type of the last parameter and not the return type.
3963     // The native return type of an HRESULT-swapped function is an HRESULT, which never uses a return-buffer argument.
3964     // Since the managed return type is actually the last parameter, we need to marshal it after the last parameter in the managed signature
3965     // to make sure we match the native signature correctly (when marshalling parameters, we add them to the native stub signature).
3966     if (!SF_IsHRESULTSwapping(dwStubFlags))
3967     {
3968         // We cannot just use pSig.GetReturnType() here since it will return ELEMENT_TYPE_VALUETYPE for enums.
3969         bool isReturnTypeValueType = msig.GetRetTypeHandleThrowing().GetVerifierCorElementType() == ELEMENT_TYPE_VALUETYPE;
3970 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
3971         // JIT32 has problems in generating code for pinvoke ILStubs which do a return in return buffer.
3972         // Therefore instead we change the signature of calli to return void and make the return buffer as first
3973         // argument. This matches the ABI i.e. return buffer is passed as first arg. So native target will get the
3974         // return buffer in correct register.
3975         // The return structure secret arg comes first, however byvalue return is processed at
3976         // the end because it could be the HRESULT-swapped argument which always comes last.
3977
3978 #ifdef UNIX_X86_ABI
3979         // For functions with value type class, managed and unmanaged calling convention differ
3980         fMarshalReturnValueFirst = HasRetBuffArgUnmanagedFixup(&msig);
3981 #elif defined(_TARGET_ARM_)
3982         fMarshalReturnValueFirst = HasRetBuffArg(&msig);
3983 #else
3984         // 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).
3985         fMarshalReturnValueFirst = HasRetBuffArg(&msig) || (isInstanceMethod && isReturnTypeValueType);
3986 #endif // UNIX_X86_ABI
3987 #elif defined(_TARGET_AMD64_) || defined (_TARGET_ARM64_)
3988         fMarshalReturnValueFirst = isInstanceMethod && isReturnTypeValueType;
3989 #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
3990 #ifdef _WIN32
3991         fReverseWithReturnBufferArg = fMarshalReturnValueFirst && SF_IsReverseStub(dwStubFlags);
3992 #endif
3993     }
3994
3995     //
3996     // Marshal the arguments
3997     //
3998     MarshalInfo::MarshalScenario ms;
3999 #ifdef FEATURE_COMINTEROP
4000     if (SF_IsCOMStub(dwStubFlags))
4001     {
4002         if (SF_IsWinRTStub(dwStubFlags))
4003             ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
4004         else
4005             ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
4006     }
4007     else
4008 #endif // FEATURE_COMINTEROP
4009     {
4010         ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
4011     }
4012
4013     // Build up marshaling information for each of the method's parameters
4014     SIZE_T cbParamMarshalInfo;
4015     if (!ClrSafeInt<SIZE_T>::multiply(sizeof(MarshalInfo), numArgs, cbParamMarshalInfo))
4016     {
4017         COMPlusThrowHR(COR_E_OVERFLOW);
4018     }
4019
4020     NewArrayHolder<BYTE> pbParamMarshalInfo(new BYTE[cbParamMarshalInfo]);
4021     MarshalInfo *pParamMarshalInfo = reinterpret_cast<MarshalInfo *>(pbParamMarshalInfo.GetValue());
4022
4023     MetaSig paramInfoMSig(msig);
4024     for (int i = 0; i < numArgs; ++i)
4025     {
4026         paramInfoMSig.NextArg();
4027         new(&(pParamMarshalInfo[i])) MarshalInfo(paramInfoMSig.GetModule(),
4028                                                  paramInfoMSig.GetArgProps(),
4029                                                  paramInfoMSig.GetSigTypeContext(),
4030                                                  pParamTokenArray[i + 1],
4031                                                  ms,
4032                                                  nlType,
4033                                                  nlFlags,
4034                                                  TRUE,
4035                                                  i + 1,
4036                                                  numArgs,
4037                                                  SF_IsBestFit(dwStubFlags),
4038                                                  SF_IsThrowOnUnmappableChar(dwStubFlags),
4039                                                  TRUE,
4040                                                  isInstanceMethod ? TRUE : FALSE,
4041                                                  pMD,
4042                                                  TRUE
4043                                                  DEBUG_ARG(pSigDesc->m_pDebugName)
4044                                                  DEBUG_ARG(pSigDesc->m_pDebugClassName)
4045                                                  DEBUG_ARG(i + 1));
4046     }
4047
4048 #ifdef FEATURE_COMINTEROP
4049     // Check to see if we need to inject any additional hidden parameters
4050     DWORD cHiddenNativeParameters;
4051     NewArrayHolder<HiddenParameterInfo> pHiddenNativeParameters;
4052     CheckForHiddenParameters(numArgs, pParamMarshalInfo, &cHiddenNativeParameters, &pHiddenNativeParameters);
4053
4054     // Hidden parameters and LCID do not mix
4055     _ASSERTE(!(cHiddenNativeParameters > 0 && iLCIDArg != -1));
4056 #endif // FEATURE_COMINTEROP
4057
4058     // Marshal the parameters
4059     int argidx = 1;
4060     int nativeArgIndex = 0;
4061
4062     // If we are generating a return buffer on a member function that is marked as thiscall (as opposed to being a COM method)
4063     // then we need to marshal the this parameter first and the return buffer second.
4064     // We don't need to do this for COM methods because the "this" is implied as argument 0 by the signature of the stub.
4065     if (fThisCall && fMarshalReturnValueFirst)
4066     {
4067         msig.NextArg();
4068
4069         MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4070         pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4071         nativeStackSize += info.GetNativeArgSize();
4072
4073         fStubNeedsCOM |= info.MarshalerRequiresCOM();
4074
4075         // make sure that the first parameter is enregisterable
4076         if (info.GetNativeArgSize() > sizeof(SLOT))
4077             COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4078
4079         argidx++;
4080     }
4081
4082     // If we're doing a native->managed call and are generating a return buffer,
4083     // 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).
4084     if (fReverseWithReturnBufferArg)
4085     {
4086         ++argOffset;
4087     }
4088     
4089     if (fMarshalReturnValueFirst)
4090     {
4091         marshalType = DoMarshalReturnValue(msig,
4092                                            pParamTokenArray,
4093                                            nlType,
4094                                            nlFlags,
4095                                            0,
4096                                            pss,
4097                                            isInstanceMethod,
4098                                            argOffset,
4099                                            dwStubFlags,
4100                                            pMD,
4101                                            nativeStackSize,
4102                                            fStubNeedsCOM,
4103                                            0
4104                                            DEBUG_ARG(pSigDesc->m_pDebugName)
4105                                            DEBUG_ARG(pSigDesc->m_pDebugClassName)
4106                                            );
4107
4108         if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE ||
4109             marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY ||
4110             marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET ||
4111             marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF ||
4112             marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
4113 #ifdef FEATURE_COMINTEROP
4114          || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
4115 #endif // FEATURE_COMINTEROP
4116             )
4117         {
4118             // These are special non-blittable types returned by-ref in managed,
4119             // but marshaled as primitive values returned by-value in unmanaged.
4120         }
4121         else
4122         {
4123             // This is an ordinary value type - see if it is returned by-ref.
4124             MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4125             if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4126             {
4127                 nativeStackSize += sizeof(LPVOID);
4128             }
4129         }
4130     }
4131
4132     while (argidx <= numArgs)
4133     {
4134 #ifdef FEATURE_COMINTEROP
4135         HiddenParameterInfo *pHiddenParameter;
4136         // Check to see if we need to inject a hidden parameter
4137         if (IsHiddenParameter(nativeArgIndex, cHiddenNativeParameters, pHiddenNativeParameters, &pHiddenParameter))
4138         {
4139             pss->MarshalHiddenLengthArgument(pHiddenParameter->pManagedParam, FALSE);
4140             nativeStackSize += pHiddenParameter->pManagedParam->GetHiddenLengthParamStackSize();
4141
4142             if (SF_IsReverseStub(dwStubFlags))
4143             {
4144                 ++argOffset;
4145             }
4146         }
4147         else
4148 #endif // FEATURE_COMINTEROP
4149         {
4150             //
4151             // Check to see if this is the parameter after which we need to insert the LCID.
4152             //
4153             if (argidx == iLCIDArg)
4154             {
4155                 pss->MarshalLCID(argidx);
4156                 nativeStackSize += sizeof(LPVOID);
4157
4158                 if (SF_IsReverseStub(dwStubFlags))
4159                     argOffset++;
4160             }
4161
4162             msig.NextArg();
4163
4164             MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4165
4166 #ifdef FEATURE_COMINTEROP
4167             // For the hidden-length array, length parameters must occur before the parameter containing the array pointer
4168             _ASSERTE(info.GetMarshalType() != MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY || nativeArgIndex > info.HiddenLengthParamIndex());
4169 #endif // FEATURE_COMINTEROP
4170
4171             pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4172             nativeStackSize += info.GetNativeArgSize();
4173
4174             fStubNeedsCOM |= info.MarshalerRequiresCOM();
4175
4176             if (fThisCall && argidx == 1)
4177             {
4178                 // make sure that the first parameter is enregisterable
4179                 if (info.GetNativeArgSize() > sizeof(SLOT))
4180                     COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4181             }
4182
4183             fHasCopyCtorArgs = info.GetMarshalType() == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR ? TRUE : FALSE;
4184
4185             argidx++;
4186         }
4187         
4188         ++nativeArgIndex;
4189     }
4190
4191     // Check to see if this is the parameter after which we need to insert the LCID.
4192     if (argidx == iLCIDArg)
4193     {
4194         pss->MarshalLCID(argidx);
4195         nativeStackSize += sizeof(LPVOID);
4196
4197         if (SF_IsReverseStub(dwStubFlags))
4198             argOffset++;
4199     }
4200
4201     if (!fMarshalReturnValueFirst)
4202     {
4203         // This could be a HRESULT-swapped argument so it must come last.
4204         marshalType = DoMarshalReturnValue(msig,
4205                              pParamTokenArray,
4206                              nlType,
4207                              nlFlags,
4208                              argidx,
4209                              pss,
4210                              isInstanceMethod,
4211                              argOffset,
4212                              dwStubFlags,
4213                              pMD,
4214                              nativeStackSize,
4215                              fStubNeedsCOM,
4216                              nativeArgIndex
4217                              DEBUG_ARG(pSigDesc->m_pDebugName)
4218                              DEBUG_ARG(pSigDesc->m_pDebugClassName)
4219                              );
4220
4221         // If the return value is a SafeHandle or CriticalHandle, mark the stub method.
4222         // Interop methods that use this stub will have an implicit reliability contract
4223         // (see code:TAStackCrawlCallBack).
4224         if (!SF_IsHRESULTSwapping(dwStubFlags))
4225         {
4226             if (marshalType == MarshalInfo::MARSHAL_TYPE_SAFEHANDLE ||
4227                 marshalType == MarshalInfo::MARSHAL_TYPE_CRITICALHANDLE)
4228             {
4229                 if (pMD->IsDynamicMethod())
4230                     pMD->AsDynamicMethodDesc()->SetUnbreakable(true);
4231             }
4232         }
4233     }
4234
4235     if (SF_IsHRESULTSwapping(dwStubFlags))
4236     {
4237         if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
4238             nativeStackSize += sizeof(LPVOID);
4239     }
4240
4241     if (pMD->IsDynamicMethod())
4242     {
4243         // Set the native stack size to the IL stub MD. It is needed for alignment
4244         // thunk generation on the Mac and stdcall name decoration on Windows.
4245         // We do not store it directly in the interop MethodDesc here because due 
4246         // to sharing we come here only for the first call with given signature and 
4247         // the target MD may even be NULL.
4248
4249 #ifdef _TARGET_X86_
4250         if (fThisCall)
4251         {
4252             _ASSERTE(nativeStackSize >= sizeof(SLOT));
4253             nativeStackSize -= sizeof(SLOT);
4254         }
4255 #else // _TARGET_X86_
4256         //
4257         // The algorithm to compute nativeStackSize on the fly is x86-specific.
4258         // Recompute the correct size for other platforms from the stub signature.
4259         //
4260         if (SF_IsForwardStub(dwStubFlags))
4261         {
4262             // It would be nice to compute the correct value for forward stubs too.
4263             // The value is only used in MarshalNative::NumParamBytes right now,
4264             // and changing what MarshalNative::NumParamBytes returns is 
4265             // a potential breaking change.
4266         }
4267         else
4268         {
4269             // native stack size is updated in code:ILStubState.SwapStubSignatures
4270         }
4271 #endif // _TARGET_X86_
4272
4273         if (!FitsInU2(nativeStackSize))
4274             COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
4275
4276         DynamicMethodDesc *pDMD = pMD->AsDynamicMethodDesc();
4277
4278         pDMD->SetNativeStackArgSize(static_cast<WORD>(nativeStackSize));
4279         pDMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
4280         pDMD->SetStubNeedsCOMStarted(fStubNeedsCOM);
4281     }
4282
4283     // FinishEmit needs to know the native stack arg size so we call it after the number
4284     // has been set in the stub MD (code:DynamicMethodDesc.SetNativeStackArgSize)
4285     pss->FinishEmit(pMD);
4286 }
4287
4288 class NDirectStubHashBlob : public ILStubHashBlobBase
4289 {
4290 public:
4291     Module*     m_pModule;
4292
4293     WORD        m_unmgdCallConv;
4294     BYTE        m_nlType;                   // C_ASSERTS are in NDirect::CreateHashBlob
4295     BYTE        m_nlFlags;
4296
4297     DWORD       m_StubFlags;
4298
4299     INT32       m_iLCIDArg;
4300     INT32       m_nParams;
4301     BYTE        m_rgbSigAndParamData[1];
4302     // (dwParamAttr, cbNativeType)          // length: number of parameters
4303     // NativeTypeBlob                       // length: number of parameters
4304     // BYTE     m_rgbSigData[];             // length: determined by sig walk
4305 };
4306
4307 // For better performance and less memory fragmentation,
4308 // I'm using structure here to avoid allocating 3 different arrays.
4309 struct ParamInfo
4310 {
4311     DWORD dwParamAttr;
4312     ULONG cbNativeType;
4313     PCCOR_SIGNATURE pvNativeType;
4314 };  
4315
4316 ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams)
4317 {
4318     STANDARD_VM_CONTRACT;
4319
4320     NDirectStubHashBlob*    pBlob;
4321
4322     IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport();
4323
4324     CQuickBytes paramInfoBytes;
4325     paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens);
4326     ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr();
4327     ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens);
4328
4329     size_t cbNativeTypeTotal = 0;
4330     
4331     //
4332     // Collect information for function parameters
4333     //     
4334     for (int idx = 0; idx < pParams->m_nParamTokens; idx++)
4335     {
4336         mdParamDef token = pParams->m_pParamTokenArray[idx];
4337         if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token)
4338         {
4339             USHORT usSequence_Ignore;       // We don't need usSequence in the hash as the param array is already sorted
4340             LPCSTR szParamName_Ignore;
4341             IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, &paramInfos[idx].dwParamAttr, &szParamName_Ignore));
4342
4343             if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal)
4344             {
4345                 IfFailThrow(pInternalImport->GetFieldMarshal(token, &paramInfos[idx].pvNativeType, &paramInfos[idx].cbNativeType));
4346                 cbNativeTypeTotal += paramInfos[idx].cbNativeType;
4347             }
4348         }
4349     }
4350
4351     SigPointer sigPtr = pParams->m_sig.CreateSigPointer();
4352     
4353     // note that ConvertToInternalSignature also resolves generics so different instantiations will get different
4354     // hash blobs for methods that have generic parameters in their signature
4355     SigBuilder sigBuilder;
4356     sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE);
4357
4358     DWORD cbSig;
4359     PVOID pSig = sigBuilder.GetSignature(&cbSig);
4360
4361     //
4362     // Build hash blob for IL stub sharing
4363     //
4364     S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) +
4365                             S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) +   // Parameter attributes
4366                             S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) +   // Native type blob size
4367                             S_SIZE_T(cbNativeTypeTotal) +                                   // Native type blob data
4368                             S_SIZE_T(cbSig);                                                // Signature
4369                             
4370     if (cbSizeOfBlob.IsOverflow())
4371         COMPlusThrowHR(COR_E_OVERFLOW);
4372
4373     static_assert_no_msg(nltMaxValue   <= 0xFF);
4374     static_assert_no_msg(nlfMaxValue   <= 0xFF);
4375     static_assert_no_msg(pmMaxValue    <= 0xFFFF);
4376
4377     NewArrayHolder<BYTE> pBytes = new BYTE[cbSizeOfBlob.Value()];
4378     // zero out the hash bytes to ensure all bit fields are deterministically set
4379     ZeroMemory(pBytes, cbSizeOfBlob.Value());
4380     pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes;
4381
4382     pBlob->m_pModule                = NULL;
4383
4384     if (SF_IsNGENedStub(pParams->m_dwStubFlags))
4385     {
4386         // don't share across modules if we are ngening the stub
4387         pBlob->m_pModule = pParams->m_pModule;
4388     }
4389
4390     pBlob->m_cbSizeOfBlob           = cbSizeOfBlob.Value();
4391     pBlob->m_unmgdCallConv          = static_cast<WORD>(pParams->m_unmgdCallConv);
4392     pBlob->m_nlType                 = static_cast<BYTE>(pParams->m_nlType);
4393     pBlob->m_nlFlags                = static_cast<BYTE>(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub
4394     pBlob->m_iLCIDArg               = pParams->m_iLCIDArg;
4395
4396     pBlob->m_StubFlags              = pParams->m_dwStubFlags;
4397     pBlob->m_nParams                = pParams->m_nParamTokens;
4398
4399     BYTE* pBlobParams               = &pBlob->m_rgbSigAndParamData[0];
4400
4401     //
4402     // Write (dwParamAttr, cbNativeType) for parameters
4403     //
4404     // Note that these need to be aligned and it is why they are written before the byte blobs
4405     // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs
4406     //
4407     _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0);
4408     _ASSERTE(sizeof(DWORD) == sizeof(ULONG));
4409     
4410     for (int i = 0; i < pParams->m_nParamTokens; ++i)
4411     {
4412         // We only care about In/Out/HasFieldMarshal
4413         // Other attr are about optional/default values which are not used in marshalling,
4414         // but only used in compilers        
4415         *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal);
4416         pBlobParams += sizeof(DWORD);
4417
4418         *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType;
4419         pBlobParams += sizeof(ULONG);
4420     }
4421
4422     //
4423     // Write native type blob for parameters
4424     //
4425     for (int i = 0; i < pParams->m_nParamTokens; ++i)
4426     {
4427         memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType);
4428         pBlobParams += paramInfos[i].cbNativeType;
4429     }
4430     
4431     //
4432     // Copy signature
4433     // 
4434     memcpy(pBlobParams, pSig, cbSig);
4435
4436     // Verify that we indeed have reached the end
4437     _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value());
4438
4439     pBytes.SuppressRelease();
4440     return (ILStubHashBlob*)pBlob;
4441 }
4442
4443 // static inline
4444 ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams)
4445 {
4446     CONTRACTL
4447     {
4448         THROWS;
4449         GC_NOTRIGGER;
4450         MODE_ANY;
4451     }
4452     CONTRACTL_END;
4453
4454     // Use the m_pLoaderModule instead of m_pModule
4455     // They could be different for methods on generic types.
4456     return pParams->m_pLoaderModule->GetILStubCache();
4457 }
4458
4459 // static
4460 MethodDesc* NDirect::GetStubMethodDesc(
4461     MethodDesc *pTargetMD,
4462     NDirectStubParameters* pParams,
4463     ILStubHashBlob* pHashParams,
4464     AllocMemTracker* pamTracker,
4465     bool& bILStubCreator,
4466     MethodDesc* pLastMD)
4467 {
4468     CONTRACT(MethodDesc*)
4469     {
4470         STANDARD_VM_CHECK;
4471
4472         PRECONDITION(CheckPointer(pParams));
4473         PRECONDITION(!pParams->m_sig.IsEmpty());
4474         PRECONDITION(CheckPointer(pParams->m_pModule));
4475         PRECONDITION(CheckPointer(pTargetMD, NULL_OK));
4476         POSTCONDITION(CheckPointer(RETVAL));
4477     }
4478     CONTRACT_END;
4479
4480     MethodDesc*     pMD;
4481
4482     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4483
4484     pMD = pCache->GetStubMethodDesc(pTargetMD,
4485                                     pHashParams, 
4486                                     pParams->m_dwStubFlags, 
4487                                     pParams->m_pModule, 
4488                                     pParams->m_sig.GetRawSig(),
4489                                     pParams->m_sig.GetRawSigLen(),
4490                                     pamTracker,
4491                                     bILStubCreator,
4492                                     pLastMD);
4493
4494     RETURN pMD;
4495 }
4496
4497
4498 // static
4499 void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams)
4500 {
4501     CONTRACTL
4502     {
4503         STANDARD_VM_CHECK;
4504
4505         PRECONDITION(CheckPointer(pParams));
4506         PRECONDITION(CheckPointer(pHashParams));
4507         PRECONDITION(!pParams->m_sig.IsEmpty());
4508         PRECONDITION(CheckPointer(pParams->m_pModule));
4509     }
4510     CONTRACTL_END;
4511
4512     LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams));
4513
4514     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4515
4516     pCache->DeleteEntry(pHashParams);
4517 }
4518
4519 // static
4520 void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD)
4521 {
4522     CONTRACTL
4523     {
4524         STANDARD_VM_CHECK;
4525
4526         PRECONDITION(CheckPointer(pParams));
4527         PRECONDITION(!pParams->m_sig.IsEmpty());
4528         PRECONDITION(CheckPointer(pParams->m_pModule));
4529     }
4530     CONTRACTL_END;
4531
4532     ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4533
4534     pCache->AddMethodDescChunkWithLockTaken(pMD);
4535 }
4536
4537 //
4538 // Additional factorization of CreateNDirectStub.  This hoists all the metadata accesses
4539 // into one location so that we can leave CreateNDirectStubWorker to just generate the 
4540 // IL.  This allows us to cache a stub based on the inputs to CreateNDirectStubWorker
4541 // instead of having to generate the IL first before doing the caching.
4542 //
4543 void CreateNDirectStubAccessMetadata(StubSigDesc*       pSigDesc,       // IN
4544                                      CorPinvokeMap      unmgdCallConv,  // IN
4545                                      DWORD*             pdwStubFlags,   // IN/OUT
4546                                      int*               piLCIDArg,      // OUT
4547                                      int*               pNumArgs        // OUT
4548                                      )
4549 {
4550     STANDARD_VM_CONTRACT;
4551
4552     if (SF_IsCOMStub(*pdwStubFlags))
4553     {
4554         _ASSERTE(0 == unmgdCallConv);
4555     }
4556     else
4557     {
4558         if (unmgdCallConv != pmCallConvStdcall &&
4559             unmgdCallConv != pmCallConvCdecl &&
4560             unmgdCallConv != pmCallConvThiscall)
4561         {
4562             COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
4563         }
4564     }
4565     
4566 #ifdef FEATURE_COMINTEROP
4567     if (SF_IsDelegateStub(*pdwStubFlags))
4568     {
4569         _ASSERTE(!SF_IsWinRTStub(*pdwStubFlags));
4570         if (pSigDesc->m_pMD->GetMethodTable()->IsProjectedFromWinRT())
4571         {
4572             // We do not allow P/Invoking via WinRT delegates to better segregate WinRT
4573             // from classic interop scenarios.
4574             COMPlusThrow(kMarshalDirectiveException, IDS_EE_DELEGATEPINVOKE_WINRT);
4575         }
4576     }
4577 #endif // FEATURE_COMINTEROP
4578
4579     MetaSig msig(pSigDesc->m_sig, 
4580                  pSigDesc->m_pModule, 
4581                  &pSigDesc->m_typeContext);
4582
4583     if (SF_IsVarArgStub(*pdwStubFlags))
4584         msig.SetTreatAsVarArg();
4585
4586     (*pNumArgs) = msig.NumFixedArgs();
4587     
4588     IMDInternalImport* pInternalImport = pSigDesc->m_pModule->GetMDImport();
4589
4590     _ASSERTE(!SF_IsHRESULTSwapping(*pdwStubFlags));
4591
4592     mdMethodDef md = pSigDesc->m_tkMethodDef;
4593     if (md != mdMethodDefNil)
4594     {
4595         DWORD           dwDescrOffset;
4596         DWORD           dwImplFlags;
4597         IfFailThrow(pInternalImport->GetMethodImplProps(
4598             md, 
4599             &dwDescrOffset, 
4600             &dwImplFlags));
4601         
4602 #ifdef FEATURE_COMINTEROP
4603         if (SF_IsWinRTStub(*pdwStubFlags))
4604         {
4605             // All WinRT methods do HRESULT swapping
4606             if (IsMiPreserveSig(dwImplFlags))
4607             {
4608                 COMPlusThrow(kMarshalDirectiveException, IDS_EE_PRESERVESIG_WINRT);
4609             }
4610
4611             (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4612         }
4613         else
4614 #endif // FEATURE_COMINTEROP
4615         if (SF_IsReverseStub(*pdwStubFlags))
4616         {
4617             // only COM-to-CLR call supports hresult swapping in the reverse direction
4618             if (SF_IsCOMStub(*pdwStubFlags) && !IsMiPreserveSig(dwImplFlags))
4619             {
4620                 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4621             }
4622         }
4623         else
4624         {
4625             // fwd pinvoke, fwd com interop support hresult swapping.
4626             // delegate to an unmanaged method does not.
4627             if (!IsMiPreserveSig(dwImplFlags) && !SF_IsDelegateStub(*pdwStubFlags))
4628             {
4629                 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4630             }
4631         }
4632     }
4633
4634     if (pSigDesc->m_pMD != NULL)
4635     {
4636         (*piLCIDArg) = GetLCIDParameterIndex(pSigDesc->m_pMD);
4637     }
4638     else
4639     {
4640         (*piLCIDArg) = -1;
4641     }
4642
4643     // Check to see if we need to do LCID conversion.
4644     if ((*piLCIDArg) != -1 && (*piLCIDArg) > (*pNumArgs))
4645     {
4646         COMPlusThrow(kIndexOutOfRangeException, IDS_EE_INVALIDLCIDPARAM);
4647     }
4648
4649     if (SF_IsCOMStub(*pdwStubFlags) && !SF_IsWinRTStaticStub(*pdwStubFlags))
4650     {
4651         CONSISTENCY_CHECK(msig.HasThis());
4652     }
4653     else
4654     {
4655         if (msig.HasThis() && !SF_IsDelegateStub(*pdwStubFlags))
4656         {
4657             COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC);
4658         }
4659     }
4660 }
4661
4662 void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError /*= TRUE*/)
4663 {
4664     if (pNMD->IsSynchronized() && throwOnError)
4665         COMPlusThrow(kTypeLoadException, IDS_EE_NOSYNCHRONIZED);
4666
4667     WORD ndirectflags = 0;
4668     if (pNMD->MethodDesc::IsVarArg())
4669         ndirectflags |= NDirectMethodDesc::kVarArgs;
4670
4671     LPCUTF8 szLibName = NULL, szEntryPointName = NULL;
4672     new (pSigInfo) PInvokeStaticSigInfo(pNMD, &szLibName, &szEntryPointName,
4673         (throwOnError ? PInvokeStaticSigInfo::THROW_ON_ERROR : PInvokeStaticSigInfo::NO_THROW_ON_ERROR));
4674
4675     if (pSigInfo->GetCharSet() == nltAnsi)
4676         ndirectflags |= NDirectMethodDesc::kNativeAnsi;
4677
4678     CorNativeLinkFlags linkflags = pSigInfo->GetLinkFlags();    
4679     if (linkflags & nlfLastError)
4680         ndirectflags |= NDirectMethodDesc::kLastError;
4681     if (linkflags & nlfNoMangle)
4682         ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
4683     
4684     CorPinvokeMap callConv = pSigInfo->GetCallConv();
4685     if (callConv == pmCallConvStdcall)
4686         ndirectflags |= NDirectMethodDesc::kStdCall;
4687     if (callConv == pmCallConvThiscall)
4688         ndirectflags |= NDirectMethodDesc::kThisCall;
4689
4690     if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
4691     {
4692         ndirectflags |= NDirectMethodDesc::kIsQCall;
4693     }
4694     else
4695     {
4696         EnsureWritablePages(&pNMD->ndirect);
4697         pNMD->ndirect.m_pszLibName.SetValueMaybeNull(szLibName);
4698         pNMD->ndirect.m_pszEntrypointName.SetValueMaybeNull(szEntryPointName);
4699     }
4700
4701 #ifdef _TARGET_X86_
4702     if (ndirectflags & NDirectMethodDesc::kStdCall)
4703     {
4704         // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling.
4705         MetaSig msig(pNMD);
4706         ArgIterator argit(&msig);
4707         if (argit.HasRetBuffArg())
4708         {
4709             MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4710             if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4711             {
4712                 ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf;
4713             }
4714         }
4715     }
4716 #endif // _TARGET_X86_
4717
4718     // Call this exactly ONCE per thread. Do not publish incomplete prestub flags
4719     // or you will introduce a race condition.
4720     pNMD->InterlockedSetNDirectFlags(ndirectflags);
4721 }
4722
4723 #ifdef FEATURE_COMINTEROP
4724 // Find the MethodDesc of the predefined IL stub method by either
4725 // 1) looking at redirected adapter interfaces, OR
4726 // 2) looking at special attributes for the specific interop scenario (specified by dwStubFlags).
4727 // Currently only ManagedToNativeComInteropStubAttribute is supported.
4728 // It returns NULL if no such attribute(s) can be found.  
4729 // But if the attribute is found and is invalid, or something went wrong in the looking up
4730 // process, an exception will be thrown. If everything goes well, you'll get the MethodDesc
4731 // of the stub method
4732 HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD)
4733 {
4734     CONTRACT(HRESULT)
4735     {
4736         THROWS;
4737         GC_TRIGGERS;
4738         MODE_ANY;
4739         PRECONDITION(CheckPointer(pTargetMD));
4740         PRECONDITION(CheckPointer(ppRetStubMD));
4741         PRECONDITION(*ppRetStubMD == NULL);
4742     }
4743     CONTRACT_END;
4744
4745     HRESULT hr;
4746
4747     MethodTable *pTargetMT = pTargetMD->GetMethodTable();
4748
4749     // Check if this is a redirected interface - we have static stubs in mscorlib for those.
4750     if (SF_IsForwardCOMStub(dwStubFlags) && pTargetMT->IsInterface())
4751     {
4752
4753         // Redirect generic redirected interfaces to the corresponding adapter methods in mscorlib
4754         if (pTargetMT->HasInstantiation())
4755         {
4756             MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(pTargetMD, TypeHandle::Interop_ManagedToNative);
4757             if (pAdapterMD != NULL)
4758             {
4759                 *ppRetStubMD = pAdapterMD;
4760                 return S_OK;
4761             }
4762         }
4763     }
4764
4765     //
4766     // Find out if we have the attribute
4767     //    
4768     const void *pBytes;
4769     ULONG cbBytes;
4770
4771     // Support v-table forward classic COM interop calls only
4772     if (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags) && !SF_IsWinRTStub(dwStubFlags))
4773     {
4774         if (pTargetMT->HasInstantiation())
4775         {
4776             // ManagedToNativeComInteropStubAttribute is not supported with generics
4777             return E_FAIL;
4778         }
4779
4780         if (pTargetMD->IsFCall())
4781         {
4782             // ManagedToNativeComInteropStubAttribute is not supported on FCalls (i.e. methods on legacy
4783             // interfaces forwarded to CustomMarshalers.dll such as IEnumerable::GetEnumerator)
4784             return E_FAIL;
4785         }
4786         _ASSERTE(pTargetMD->IsComPlusCall());
4787         
4788         if (pTargetMD->IsInterface())
4789         {
4790             _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
4791             hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
4792                 pTargetMD->GetMemberDef(),
4793                 FORWARD_INTEROP_STUB_METHOD_TYPE,
4794                 &pBytes,
4795                 &cbBytes);
4796                 
4797             if (FAILED(hr)) 
4798                 RETURN hr;
4799             // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
4800             // Translate that to E_FAIL
4801             else if (hr == S_FALSE)
4802                 RETURN E_FAIL;               
4803         }
4804         else
4805         {
4806             // We are dealing with the class, use the interface MD instead
4807             // After second thought I believe we don't need to check the class MD.
4808             // We can think stubs as part of public interface, and if the interface is public,
4809             // the stubs should also be accessible
4810             MethodDesc *pInterfaceMD = pTargetMD->GetInterfaceMD();
4811             if (pInterfaceMD)
4812             {
4813                 hr = FindPredefinedILStubMethod(pInterfaceMD, dwStubFlags, ppRetStubMD);
4814                 RETURN hr;
4815             }
4816             else
4817                 RETURN E_FAIL;
4818         }
4819     }
4820     else
4821         RETURN E_FAIL;
4822         
4823     //
4824     // Parse the attribute
4825     //
4826     CustomAttributeParser parser(pBytes, cbBytes);
4827     IfFailRet(parser.SkipProlog());
4828
4829     LPCUTF8 pTypeName;
4830     ULONG cbTypeName;
4831     IfFailRet(parser.GetNonEmptyString(&pTypeName, &cbTypeName));
4832
4833     LPCUTF8 pMethodName;
4834     ULONG cbMethodName;
4835     IfFailRet(parser.GetNonEmptyString(&pMethodName, &cbMethodName));
4836
4837     StackSString typeName(SString::Utf8, pTypeName, cbTypeName);
4838     StackSString methodName(SString::Utf8, pMethodName, cbMethodName);
4839
4840     //
4841     // Retrieve the type
4842     //
4843     TypeHandle stubClassType;
4844     stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
4845
4846     MethodTable *pStubClassMT = stubClassType.AsMethodTable();
4847
4848     StackSString stubClassName;
4849     pStubClassMT->_GetFullyQualifiedNameForClassNestedAware(stubClassName);
4850     
4851     StackSString targetInterfaceName;
4852     pTargetMT->_GetFullyQualifiedNameForClassNestedAware(targetInterfaceName);
4853     
4854     // Restrict to same assembly only to reduce test cost
4855     if (stubClassType.GetAssembly() != pTargetMT->GetAssembly())
4856     {
4857         COMPlusThrow(
4858             kArgumentException, 
4859             IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY,
4860             stubClassName.GetUnicode(),
4861             targetInterfaceName.GetUnicode()
4862             );
4863     }
4864
4865     if (stubClassType.HasInstantiation())
4866     {
4867         COMPlusThrow(
4868             kArgumentException, 
4869             IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC,
4870             stubClassName.GetUnicode()
4871             );
4872     }
4873     
4874     if (stubClassType.IsInterface())
4875     {
4876         COMPlusThrow(
4877             kArgumentException, 
4878             IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE,
4879             stubClassName.GetUnicode()
4880             );
4881     }
4882     
4883     //
4884     // Locate the MethodDesc for the stub method
4885     //
4886     MethodDesc *pStubMD = NULL;
4887
4888     {
4889         PCCOR_SIGNATURE pTargetSig = NULL;
4890         DWORD pcTargetSig = 0;
4891         
4892         SigTypeContext typeContext; // NO generics supported
4893
4894         pTargetMD->GetSig(&pTargetSig, &pcTargetSig);
4895         
4896         MetaSig msig(pTargetSig, 
4897                      pcTargetSig,
4898                      pTargetMD->GetModule(), 
4899                      &typeContext);
4900         _ASSERTE(msig.HasThis());
4901         
4902         SigBuilder stubSigBuilder;
4903
4904         //
4905         // Append calling Convention, NumOfArgs + 1,
4906         //
4907         stubSigBuilder.AppendByte(msig.GetCallingConvention() & ~IMAGE_CEE_CS_CALLCONV_HASTHIS);
4908         stubSigBuilder.AppendData(msig.NumFixedArgs() + 1);
4909
4910         //
4911         // Append return type
4912         //
4913         SigPointer pReturn = msig.GetReturnProps();
4914         LPBYTE pReturnTypeBegin = (LPBYTE)pReturn.GetPtr();
4915         IfFailThrow(pReturn.SkipExactlyOne());
4916         LPBYTE pReturnTypeEnd = (LPBYTE)pReturn.GetPtr();
4917         
4918         stubSigBuilder.AppendBlob(pReturnTypeBegin, pReturnTypeEnd - pReturnTypeBegin);
4919
4920         //
4921         // Append 'this'
4922         //
4923         stubSigBuilder.AppendElementType(ELEMENT_TYPE_CLASS);            
4924         stubSigBuilder.AppendToken(pTargetMT->GetCl());
4925
4926         //
4927         // Copy rest of the arguments
4928         //
4929         if (msig.NextArg() != ELEMENT_TYPE_END)
4930         {
4931             SigPointer pFirstArg = msig.GetArgProps();
4932             LPBYTE pArgBegin = (LPBYTE) pFirstArg.GetPtr();
4933             LPBYTE pArgEnd = (LPBYTE) pTargetSig + pcTargetSig;
4934
4935             stubSigBuilder.AppendBlob(pArgBegin, pArgEnd - pArgBegin);
4936         }
4937
4938         //
4939         // Allocate new memory and copy over
4940         //
4941         DWORD pcStubSig = 0;
4942         PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE) stubSigBuilder.GetSignature(&pcStubSig);
4943
4944         //
4945         // Find method using name + signature
4946         //
4947         StackScratchBuffer buffer;
4948         LPCUTF8 szMethodNameUTF8 = methodName.GetUTF8(buffer);
4949         pStubMD = MemberLoader::FindMethod(stubClassType.GetMethodTable(),
4950             szMethodNameUTF8, 
4951             pStubSig,
4952             pcStubSig,
4953             pTargetMT->GetModule());
4954             
4955         if (pStubMD == NULL)
4956         {
4957             CQuickBytes qbSig;
4958             
4959             PrettyPrintSig(
4960                 pStubSig,
4961                 pcStubSig,
4962                 szMethodNameUTF8,
4963                 &qbSig,
4964                 pTargetMD->GetMDImport(),
4965                 NULL);
4966
4967             // Unfortunately the PrettyPrintSig doesn't print 'static' when the function is static
4968             // so we need to append 'static' here. No need to localize
4969             SString signature(SString::Utf8, (LPCUTF8)"static ");
4970             signature.AppendUTF8((LPCUTF8) qbSig.Ptr());
4971             
4972             COMPlusThrow(
4973                 kMissingMethodException, 
4974                 IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING,
4975                 signature.GetUnicode(),
4976                 stubClassName.GetUnicode()
4977                 );       
4978        
4979         }
4980     }
4981
4982     //
4983     // Check the Stub MD    
4984     //
4985     
4986     // Verify that the target interop method can call the stub method
4987
4988     _ASSERTE(pTargetMD != NULL);
4989
4990     StaticAccessCheckContext accessContext(pTargetMD, pTargetMT);
4991
4992     if (!ClassLoader::CanAccess(
4993             &accessContext, 
4994             pStubClassMT,
4995             stubClassType.GetAssembly(), 
4996             pStubMD->GetAttrs(),
4997             pStubMD,
4998             NULL))
4999     {
5000         StackSString interopMethodName(SString::Utf8, pTargetMD->GetName());
5001         
5002         COMPlusThrow(
5003             kMethodAccessException, 
5004             IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD,
5005             interopMethodName.GetUnicode(),
5006             methodName.GetUnicode()
5007             );
5008     }
5009
5010     // The FindMethod call will make sure that it is static by matching signature.
5011     // So there is no need to check and throw
5012     _ASSERTE(pStubMD->IsStatic());
5013     
5014     *ppRetStubMD = pStubMD;
5015
5016     RETURN S_OK;
5017 }
5018 #endif // FEATURE_COMINTEROP
5019
5020 MethodDesc* CreateInteropILStub(
5021                          ILStubState*       pss,
5022                          StubSigDesc*       pSigDesc,
5023                          CorNativeLinkType  nlType,
5024                          CorNativeLinkFlags nlFlags,
5025                          CorPinvokeMap      unmgdCallConv,
5026                          DWORD              dwStubFlags,            // NDirectStubFlags
5027                          int                nParamTokens,
5028                          mdParamDef*        pParamTokenArray,
5029                          int                iLCIDArg
5030                            )
5031 {
5032     CONTRACT(MethodDesc*)
5033     {
5034         STANDARD_VM_CHECK;
5035
5036         PRECONDITION(CheckPointer(pSigDesc));
5037         POSTCONDITION(CheckPointer(RETVAL));
5038     }
5039     CONTRACT_END;
5040
5041
5042     ///////////////////////////////
5043     //
5044     // MethodDesc creation 
5045     //
5046     ///////////////////////////////
5047     
5048     MethodDesc*     pStubMD = NULL;
5049
5050     Module*         pModule = pSigDesc->m_pModule;
5051     Module*         pLoaderModule = pSigDesc->m_pLoaderModule;
5052     MethodDesc*     pTargetMD = pSigDesc->m_pMD;
5053     //
5054     // pTargetMD may be null in the case of calli pinvoke 
5055     // and vararg pinvoke.
5056     //
5057
5058 #ifdef FEATURE_COMINTEROP
5059     //
5060     // Try to locate predefined IL stub either defined in user code or hardcoded in CLR
5061     // If there is one, use the pointed method as the stub.
5062     // Skip pTargetMD == NULL case for reverse interop calls
5063     //
5064     if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD)))
5065     {
5066 #ifndef CROSSGEN_COMPILE
5067         // We are about to execute method in pStubMD which could be in another module.
5068         // Call EnsureActive before make the call
5069         // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here
5070         pStubMD->EnsureActive();
5071
5072         if (pStubMD->IsPreImplemented())
5073             RestoreNGENedStub(pStubMD);
5074 #endif
5075
5076         RETURN pStubMD;
5077     }
5078 #endif // FEATURE_COMINTEROP
5079
5080     // Otherwise, fall back to generating IL stub on-the-fly
5081     NDirectStubParameters    params(pSigDesc->m_sig,
5082                                &pSigDesc->m_typeContext,
5083                                pModule,
5084                                pLoaderModule,
5085                                nlType,
5086                                nlFlags,
5087                                unmgdCallConv,
5088                                dwStubFlags,
5089                                nParamTokens,
5090                                pParamTokenArray,
5091                                iLCIDArg
5092                                );
5093
5094     // The following two ILStubCreatorHelperHolder are to recover the status when an
5095     // exception happen during the generation of the IL stubs. We need to free the
5096     // memory allocated and restore the ILStubCache.
5097     //
5098     // The following block is logically divided into two phases. The first phase is 
5099     // CreateOrGet IL Stub phase which we take a domain level lock. The second phase
5100     // is IL generation phase which we take a MethodDesc level lock. Taking two locks
5101     // is mainly designed for performance.
5102     //
5103     // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
5104     // allocated memory during the creation of MethodDesc so that we are able to remove
5105     // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
5106
5107     // When removing IL Stub from Cache, we have a constraint that only the thread which
5108     // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
5109     // remove it from cache if OOM occurs
5110
5111     {
5112         ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, &params);
5113
5114         // take the domain level lock
5115         ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock());
5116
5117         {
5118             // The holder will free the allocated MethodDesc and restore the ILStubCache
5119             // if exception happen.
5120             ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper);
5121             pStubMD = pCreateOrGetStubHolder->GetStubMD();
5122
5123             ///////////////////////////////
5124             //
5125             // IL generation
5126             //
5127             ///////////////////////////////
5128
5129             {
5130                 // take the MethodDesc level locker
5131                 ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5132
5133                 ListLockEntryLockHolder pEntryLock(pEntry, FALSE);
5134
5135                 // We can release the holder for the first phase now
5136                 pCreateOrGetStubHolder.SuppressRelease();
5137
5138                 {
5139                     // The holder will free the allocated MethodDesc and restore the ILStubCache
5140                     // if exception happen. The reason to get the holder again is to 
5141                     ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper);
5142
5143                     if (!pEntryLock.DeadlockAwareAcquire())
5144                     {
5145                         // the IL generation is not recursive!
5146                         UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5147                     }
5148
5149                     if (SF_IsSharedStub(params.m_dwStubFlags))
5150                     {
5151                         // Assure that pStubMD we have now has not been destroyed by other threads
5152                         pGenILHolder->GetStubMethodDesc();
5153
5154                         while (pStubMD != pGenILHolder->GetStubMD())
5155                         {
5156                             pStubMD = pGenILHolder->GetStubMD();
5157
5158                             pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5159                             pEntryLock.Assign(pEntry, FALSE);
5160
5161                             if (!pEntryLock.DeadlockAwareAcquire())
5162                             {
5163                                 // the IL generation is not recursive!
5164                                 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5165                             }
5166
5167                             pGenILHolder->GetStubMethodDesc();
5168                         }
5169                     }
5170
5171                     for (;;)
5172                     {
5173                         // We have the entry lock now, we can release the global lock
5174                         pILStubLock.Release();
5175
5176                         if (pEntry->m_hrResultCode != S_FALSE)
5177                         {
5178                             // We came in to generate the IL but someone 
5179                             // beat us so there's nothing to do
5180                             break;
5181                         }
5182
5183                         ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
5184
5185                         CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc()));
5186
5187                         if (pResolver->IsILGenerated())
5188                         {
5189                             // this stub already has its IL generated
5190                             break;
5191                         }
5192
5193                         //
5194                         // Check that the stub signature and MethodDesc are compatible.  The JIT
5195                         // interface functions depend on this.
5196                         //
5197                         
5198                         {
5199                             SigPointer ptr = pSigDesc->m_sig.CreateSigPointer();
5200
5201                             ULONG callConvInfo;
5202                             IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo));
5203
5204                             BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS);
5205
5206                             // CreateNDirectStubWorker will throw an exception for these cases.
5207                             BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags);
5208
5209                             if (fSigIsStatic || fCanHaveThis)
5210                             {
5211                                 CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic);
5212                             }
5213                         }
5214
5215                         {
5216                             ILStubGenHolder sgh(pResolver);
5217
5218                             pResolver->SetStubMethodDesc(pStubMD);
5219                             pResolver->SetStubTargetMethodDesc(pTargetMD);
5220
5221                             CreateNDirectStubWorker(pss,
5222                                                     pSigDesc,
5223                                                     nlType,
5224                                                     nlFlags,
5225                                                     unmgdCallConv,
5226                                                     dwStubFlags,
5227                                                     pStubMD,
5228                                                     pParamTokenArray,
5229                                                     iLCIDArg);
5230
5231                             pResolver->SetTokenLookupMap(pss->GetTokenLookupMap());
5232
5233                             pResolver->SetStubTargetMethodSig(
5234                                 pss->GetStubTargetMethodSig(), 
5235                                 pss->GetStubTargetMethodSigLength());
5236
5237                             // we successfully generated the IL stub
5238                             sgh.SuppressRelease();
5239                         }
5240
5241                         pEntry->m_hrResultCode = S_OK;
5242                         break;
5243                     }
5244
5245                     // Link the MethodDesc onto the method table with the lock taken
5246                     NDirect::AddMethodDescChunkWithLockTaken(&params, pStubMD);
5247
5248                     pGenILHolder.SuppressRelease();
5249                 }
5250             }
5251         }
5252         ilStubCreatorHelper.SuppressRelease();
5253     }
5254
5255 #if defined(_TARGET_X86_)
5256     if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg())
5257     {
5258         // copy the stack arg byte count from the stub MD to the target MD - this number is computed
5259         // during stub generation and is copied to all target MDs that share the stub
5260         // (we don't set it for varargs - the number is call site specific)
5261         // also copy the "takes parameters with copy constructors" flag which is needed to generate
5262         // appropriate intercept stub
5263
5264         WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
5265         BOOL fHasCopyCtorArgs = pStubMD->AsDynamicMethodDesc()->HasCopyCtorArgs();
5266
5267         if (pTargetMD->IsNDirect())
5268         {
5269             NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
5270             
5271             pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
5272             pTargetNMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5273         }
5274 #ifdef FEATURE_COMINTEROP
5275         else
5276         {
5277             if (SF_IsCOMStub(dwStubFlags))
5278             {
5279                 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD);
5280
5281                 if (pComInfo != NULL)
5282                 {
5283                     pComInfo->SetStackArgumentSize(cbStackArgSize);
5284                     pComInfo->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5285                 }
5286             }
5287         }
5288 #endif // FEATURE_COMINTEROP
5289     }
5290 #endif // defined(_TARGET_X86_)
5291
5292     RETURN pStubMD;
5293 }
5294
5295 MethodDesc* NDirect::CreateCLRToNativeILStub(
5296                 StubSigDesc*       pSigDesc,
5297                 CorNativeLinkType  nlType,
5298                 CorNativeLinkFlags nlFlags,
5299                 CorPinvokeMap      unmgdCallConv,
5300                 DWORD              dwStubFlags) // NDirectStubFlags
5301 {
5302     CONTRACT(MethodDesc*)
5303     {
5304         STANDARD_VM_CHECK;
5305
5306         PRECONDITION(CheckPointer(pSigDesc));
5307         POSTCONDITION(CheckPointer(RETVAL));
5308     }
5309     CONTRACT_END;
5310
5311     int         iLCIDArg = 0;
5312     int         numArgs = 0;
5313     int         numParamTokens = 0;
5314     mdParamDef* pParamTokenArray = NULL;
5315
5316     CreateNDirectStubAccessMetadata(pSigDesc,
5317                                     unmgdCallConv,
5318                                     &dwStubFlags,
5319                                     &iLCIDArg,
5320                                     &numArgs);
5321     
5322     Module *pModule = pSigDesc->m_pModule;
5323     numParamTokens = numArgs + 1;
5324     pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5325     CollateParamTokens(pModule->GetMDImport(), pSigDesc->m_tkMethodDef, numArgs, pParamTokenArray);
5326
5327     MethodDesc *pMD = pSigDesc->m_pMD;
5328
5329     NewHolder<ILStubState> pStubState;
5330
5331 #ifdef FEATURE_COMINTEROP
5332     if (SF_IsCOMStub(dwStubFlags))
5333     {
5334         if (SF_IsReverseStub(dwStubFlags))
5335         {
5336             pStubState = new COMToCLR_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5337         }
5338         else
5339         {
5340             pStubState = new CLRToCOM_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5341         }
5342     }
5343     else
5344 #endif
5345     {
5346         pStubState = new PInvoke_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, pMD);
5347     }
5348
5349     MethodDesc* pStubMD;
5350     pStubMD = CreateInteropILStub(
5351                 pStubState,
5352                 pSigDesc,
5353                 nlType,
5354                 nlFlags,
5355                 unmgdCallConv,
5356                 dwStubFlags,
5357                 numParamTokens,
5358                 pParamTokenArray,
5359                 iLCIDArg);
5360
5361
5362
5363     RETURN pStubMD;
5364 }
5365
5366 #ifdef FEATURE_COMINTEROP
5367 MethodDesc* NDirect::CreateFieldAccessILStub(
5368                 PCCOR_SIGNATURE    szMetaSig,
5369                 DWORD              cbMetaSigSize,
5370                 Module*            pModule,
5371                 mdFieldDef         fd,
5372                 DWORD              dwStubFlags, // NDirectStubFlags
5373                 FieldDesc*         pFD)
5374 {
5375     CONTRACT(MethodDesc*)
5376     {
5377         STANDARD_VM_CHECK;
5378
5379         PRECONDITION(CheckPointer(szMetaSig));
5380         PRECONDITION(CheckPointer(pModule));
5381         PRECONDITION(CheckPointer(pFD, NULL_OK));
5382         PRECONDITION(SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags));
5383         POSTCONDITION(CheckPointer(RETVAL));
5384     }
5385     CONTRACT_END;
5386
5387     int numArgs = (SF_IsFieldSetterStub(dwStubFlags) ? 1 : 0);
5388     int numParamTokens = numArgs + 1;
5389
5390     // make sure we capture marshaling metadata
5391     mdParamDef* pParamTokenArray = (mdParamDef *)_alloca(numParamTokens * sizeof(mdParamDef));
5392     pParamTokenArray[0] = mdParamDefNil;
5393     pParamTokenArray[numArgs] = (mdParamDef)fd;
5394
5395     // fields are never preserve-sig
5396     dwStubFlags |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
5397
5398     // convert field signature to getter/setter signature
5399     SigBuilder sigBuilder;
5400
5401     sigBuilder.AppendData(IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS);
5402     sigBuilder.AppendData(numArgs);
5403
5404     if (SF_IsFieldSetterStub(dwStubFlags))
5405     {
5406         // managed setter returns void
5407         sigBuilder.AppendElementType(ELEMENT_TYPE_VOID);
5408     }
5409
5410     CONSISTENCY_CHECK(*szMetaSig == IMAGE_CEE_CS_CALLCONV_FIELD);
5411
5412     sigBuilder.AppendBlob((const PVOID)(szMetaSig + 1), cbMetaSigSize - 1);
5413     szMetaSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbMetaSigSize);
5414
5415     StubSigDesc sigDesc(NULL, Signature(szMetaSig, cbMetaSigSize), pModule);
5416
5417 #ifdef _DEBUG
5418     sigDesc.m_pDebugName = pFD->GetDebugName();
5419     sigDesc.m_pDebugClassName = pFD->GetEnclosingMethodTable()->GetDebugClassName();
5420 #endif // _DEBUG
5421
5422     Signature signature(szMetaSig, cbMetaSigSize);
5423     NewHolder<ILStubState> pStubState = new COMToCLRFieldAccess_ILStubState(pModule, signature, &sigDesc.m_typeContext, dwStubFlags, pFD);
5424
5425     MethodDesc* pStubMD;
5426     pStubMD = CreateInteropILStub(
5427                 pStubState,
5428                 &sigDesc,
5429                 (CorNativeLinkType)0,
5430                 (CorNativeLinkFlags)0,
5431                 (CorPinvokeMap)0,
5432                 dwStubFlags,
5433                 numParamTokens,
5434                 pParamTokenArray,
5435                 -1);
5436
5437     RETURN pStubMD;
5438 }
5439 #endif // FEATURE_COMINTEROP
5440
5441 MethodDesc* NDirect::CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
5442                          DWORD dwStubFlags,
5443                          MethodDesc* pMD)
5444 {
5445     STANDARD_VM_CONTRACT;
5446     
5447     StubSigDesc sigDesc(pMD, pSigInfo);
5448
5449     if (SF_IsWinRTDelegateStub(dwStubFlags))
5450     {
5451         _ASSERTE(pMD->IsEEImpl());
5452
5453         return CreateCLRToNativeILStub(&sigDesc,
5454                                        (CorNativeLinkType)0,
5455                                        (CorNativeLinkFlags)0,
5456                                        (CorPinvokeMap)0,
5457                                        (pSigInfo->GetStubFlags() | dwStubFlags) & ~NDIRECTSTUB_FL_DELEGATE);
5458     }
5459     else
5460     {
5461         return CreateCLRToNativeILStub(&sigDesc,
5462                                        pSigInfo->GetCharSet(), 
5463                                        pSigInfo->GetLinkFlags(), 
5464                                        pSigInfo->GetCallConv(), 
5465                                        pSigInfo->GetStubFlags() | dwStubFlags);
5466     }
5467 }
5468
5469 MethodDesc* NDirect::GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags)
5470 {
5471     STANDARD_VM_CONTRACT;
5472
5473     MethodDesc* pStubMD = NULL;
5474
5475     if (!pNMD->IsVarArgs() || SF_IsForNumParamBytes(dwStubFlags))
5476     {
5477         if (pNMD->IsClassConstructorTriggeredByILStub())
5478         {
5479             dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
5480         }
5481
5482         pStubMD = CreateCLRToNativeILStub(
5483             pSigInfo, 
5484             dwStubFlags & ~NDIRECTSTUB_FL_FOR_NUMPARAMBYTES, 
5485             pNMD);
5486     }
5487
5488     return pStubMD;
5489 }
5490
5491 MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
5492 {
5493     STANDARD_VM_CONTRACT;
5494
5495     BOOL fGcMdaEnabled = FALSE;
5496 #ifdef MDA_SUPPORTED
5497     if (MDA_GET_ASSISTANT(GcManagedToUnmanaged) || MDA_GET_ASSISTANT(GcUnmanagedToManaged))
5498     {
5499         // We never generate checks for these MDAs to NGEN'ed stubs so if they are
5500         // enabled, a new stub must be generated (the perf impact is huge anyway).
5501         fGcMdaEnabled = TRUE;
5502     }
5503 #endif // MDA_SUPPORTED
5504
5505 #ifdef FEATURE_COMINTEROP
5506     if (SF_IsReverseCOMStub(dwStubFlags))
5507     {
5508         if (fGcMdaEnabled)
5509             return NULL;
5510
5511         // reverse COM stubs live in a hash table
5512         StubMethodHashTable *pHash = pMD->GetLoaderModule()->GetStubMethodHashTable();
5513         return (pHash == NULL ? NULL : pHash->FindMethodDesc(pMD));
5514     }
5515     else
5516 #endif // FEATURE_COMINTEROP
5517     if (pMD->IsNDirect())
5518     {
5519         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5520         return ((fGcMdaEnabled && !pNMD->IsQCall()) ? NULL : pNMD->ndirect.m_pStubMD.GetValueMaybeNull());
5521     }
5522 #ifdef FEATURE_COMINTEROP
5523     else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5524     {
5525 #ifdef MDA_SUPPORTED
5526         if (MDA_GET_ASSISTANT(RaceOnRCWCleanup))
5527         {
5528             // we never generate this callout to NGEN'ed stubs
5529             return NULL;
5530         }
5531 #endif // MDA_SUPPORTED
5532
5533         if (fGcMdaEnabled)
5534             return NULL;
5535
5536         ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
5537         return (pComInfo == NULL ? NULL : pComInfo->m_pStubMD.GetValueMaybeNull());
5538     }
5539 #endif // FEATURE_COMINTEROP
5540     else if (pMD->IsEEImpl())
5541     {
5542         if (fGcMdaEnabled)
5543             return NULL;
5544
5545         DelegateEEClass *pClass = (DelegateEEClass *)pMD->GetClass();
5546         if (SF_IsReverseStub(dwStubFlags))
5547         {
5548             return pClass->m_pReverseStubMD;
5549         }
5550         else
5551         {
5552 #ifdef FEATURE_COMINTEROP
5553             if (SF_IsWinRTDelegateStub(dwStubFlags))
5554             {
5555                 return pClass->m_pComPlusCallInfo->m_pStubMD.GetValueMaybeNull();
5556             }
5557             else
5558 #endif // FEATURE_COMINTEROP
5559             {
5560                 return pClass->m_pForwardStubMD;
5561             }
5562         }
5563     }
5564     else if (pMD->IsIL())
5565     {
5566         // these are currently only created at runtime, not at NGEN time
5567         return NULL;
5568     }
5569     else
5570     {
5571         UNREACHABLE_MSG("unexpected type of MethodDesc");
5572     }
5573 }
5574
5575 #ifndef CROSSGEN_COMPILE
5576
5577 PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5578 {
5579     CONTRACT(PCODE)
5580     {
5581         STANDARD_VM_CHECK;
5582
5583         PRECONDITION(CheckPointer(pManagedMD));
5584         POSTCONDITION(RETVAL != NULL);
5585     }
5586     CONTRACT_END;
5587
5588     // pStubMD, if provided, must be preimplemented.
5589     CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5590
5591     if (NULL == *ppStubMD)
5592     {
5593         PInvokeStaticSigInfo sigInfo(pManagedMD);
5594         *ppStubMD = NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pManagedMD);
5595     }
5596
5597     RETURN JitILStub(*ppStubMD);
5598 }
5599
5600 PCODE NDirect::GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5601 {
5602     STANDARD_VM_CONTRACT;
5603
5604     PCODE pStub = NULL;
5605
5606     // pStubMD, if provided, must be preimplemented.
5607     CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5608
5609     if (NULL == *ppStubMD)
5610     {
5611         PInvokeStaticSigInfo sigInfo;
5612         NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo, /* throwOnError = */ !SF_IsForNumParamBytes(dwStubFlags));
5613
5614         *ppStubMD = NDirect::GetILStubMethodDesc(pNMD, &sigInfo, dwStubFlags);
5615     }
5616
5617     if (SF_IsForNumParamBytes(dwStubFlags))
5618         return NULL;
5619
5620     if (*ppStubMD)
5621     {
5622         pStub = JitILStub(*ppStubMD);
5623     }
5624     else
5625     {
5626         CONSISTENCY_CHECK(pNMD->IsVarArgs());
5627         
5628         //
5629         // varargs goes through vararg NDirect stub
5630         //
5631         pStub = TheVarargNDirectStub(pNMD->HasRetBuffArg());
5632     }
5633
5634     if (pNMD->IsEarlyBound())
5635     {
5636         pNMD->InitEarlyBoundNDirectTarget();
5637     }
5638     else
5639     {
5640         NDirectLink(pNMD);
5641     }
5642
5643     //
5644     // NOTE: there is a race in updating this MethodDesc.  We depend on all 
5645     // threads getting back the same DynamicMethodDesc for a particular
5646     // NDirectMethodDesc, in that case, the locking around the actual JIT
5647     // operation will prevent the code from being jitted more than once.  
5648     // By the time we get here, all threads get the same address of code 
5649     // back from the JIT operation and they all just fill in the same value
5650     // here.
5651     //
5652     // In the NGEN case, all threads will get the same preimplemented code
5653     // address much like the JIT case.
5654     //
5655
5656     return pStub;
5657 }
5658
5659 PCODE JitILStub(MethodDesc* pStubMD)
5660 {
5661     STANDARD_VM_CONTRACT;
5662
5663     PCODE pCode = pStubMD->GetNativeCode();
5664
5665     if (pCode == NULL)
5666     {
5667         ///////////////////////////////
5668         //
5669         // Code generation
5670         //
5671         ///////////////////////////////
5672
5673
5674         if (pStubMD->IsDynamicMethod())
5675         {
5676             //
5677             // A dynamically generated IL stub
5678             //
5679             
5680             pCode = pStubMD->PrepareInitialCode();
5681
5682             _ASSERTE(pCode == pStubMD->GetNativeCode());            
5683         }
5684         else
5685         {     
5686             //
5687             // A static IL stub that is pointing to a static method in user assembly
5688             // Compile it and return the native code
5689             //
5690
5691             // This returns the stable entry point
5692             pCode = pStubMD->DoPrestub(NULL);
5693
5694             _ASSERTE(pCode == pStubMD->GetStableEntryPoint());            
5695         }        
5696     }
5697
5698     if (!pStubMD->IsDynamicMethod()) 
5699     {
5700         // We need an entry point that can be called multiple times
5701         pCode = pStubMD->GetMultiCallableAddrOfCode();
5702     }
5703
5704     return pCode;
5705 }
5706
5707 MethodDesc* RestoreNGENedStub(MethodDesc* pStubMD)
5708 {
5709     CONTRACTL
5710     {
5711         STANDARD_VM_CHECK;
5712         PRECONDITION(CheckPointer(pStubMD));
5713     }
5714     CONTRACTL_END;
5715
5716 #ifdef FEATURE_PREJIT
5717     pStubMD->CheckRestore();
5718
5719     PCODE pCode = pStubMD->GetPreImplementedCode();
5720     if (pCode != NULL)
5721     {
5722         TADDR pFixupList = pStubMD->GetFixupList();
5723         if (pFixupList != NULL)
5724         {
5725             Module* pZapModule = pStubMD->GetZapModule();
5726             _ASSERTE(pZapModule != NULL);
5727             if (!pZapModule->FixupDelayList(pFixupList))
5728             {
5729                 _ASSERTE(!"FixupDelayList failed");
5730                 ThrowHR(COR_E_BADIMAGEFORMAT);
5731             }
5732         }
5733
5734 #if defined(HAVE_GCCOVER)
5735         if (GCStress<cfg_instr_ngen>::IsEnabled())
5736             SetupGcCoverage(pStubMD, (BYTE*) pCode);
5737 #endif // HAVE_GCCOVER
5738
5739     }
5740     else
5741     {
5742         // We only pass a non-NULL pStubMD to GetStubForILStub() below if pStubMD is preimplemeneted.
5743         pStubMD = NULL;
5744     }
5745 #endif // FEATURE_PREJIT
5746
5747     return pStubMD;
5748 }
5749
5750 PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags, MethodDesc **ppStubMD)
5751 {
5752     CONTRACT(PCODE)
5753     {
5754         STANDARD_VM_CHECK;
5755
5756         PRECONDITION(CheckPointer(pMD));
5757         PRECONDITION(pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl() || pMD->IsIL());
5758     }
5759     CONTRACT_END;
5760
5761     PCODE                   pStub = NULL;
5762     MethodDesc*             pStubMD = NULL;
5763
5764     pStubMD = GetStubMethodDescFromInteropMethodDesc(pMD, dwStubFlags);
5765     if (pStubMD != NULL)
5766     {
5767         pStubMD = RestoreNGENedStub(pStubMD);
5768     }
5769
5770     if ((NULL == pStubMD) && (SF_IsNGENedStub(dwStubFlags)))
5771     {
5772         // Return NULL -- the caller asked only for an ngened stub and 
5773         // one does not exist, so don't do any more work.
5774         CONSISTENCY_CHECK(pStub == NULL);
5775     }
5776     else
5777     if (pMD->IsNDirect())
5778     {
5779         NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5780         pStub = NDirect::GetStubForILStub(pNMD, &pStubMD, dwStubFlags);
5781     }
5782 #ifdef FEATURE_COMINTEROP
5783     else
5784     if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5785     {
5786         pStub = ComPlusCall::GetStubForILStub(pMD, &pStubMD);
5787     }
5788 #endif // FEATURE_COMINTEROP
5789     else
5790     if (pMD->IsEEImpl())
5791     {
5792         CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
5793         EEImplMethodDesc* pDelegateMD = (EEImplMethodDesc*)pMD;
5794         pStub = COMDelegate::GetStubForILStub(pDelegateMD, &pStubMD, dwStubFlags);
5795     }
5796     else
5797     if (pMD->IsIL())
5798     {
5799         CONSISTENCY_CHECK(SF_IsReverseStub(dwStubFlags));
5800         pStub = NDirect::GetStubForILStub(pMD, &pStubMD, dwStubFlags);
5801     }
5802     else
5803     {
5804         UNREACHABLE_MSG("unexpected MethodDesc type");
5805     }
5806
5807     if (pStubMD != NULL && pStubMD->IsILStub() && pStubMD->AsDynamicMethodDesc()->IsStubNeedsCOMStarted())
5808     {
5809         // the stub uses COM so make sure that it is started
5810         EnsureComStarted();
5811     }
5812
5813     if (ppStubMD != NULL)
5814         *EnsureWritablePages(ppStubMD) = pStubMD;
5815
5816     RETURN pStub;
5817 }
5818
5819 #ifdef FEATURE_COMINTEROP
5820 void CreateCLRToDispatchCOMStub(
5821             MethodDesc *    pMD,
5822             DWORD           dwStubFlags)             // NDirectStubFlags
5823 {
5824     CONTRACTL
5825     {
5826         STANDARD_VM_CHECK;
5827
5828         PRECONDITION(CheckPointer(pMD));
5829     }
5830     CONTRACTL_END;
5831
5832     _ASSERTE(SF_IsCOMLateBoundStub(dwStubFlags) || SF_IsCOMEventCallStub(dwStubFlags));
5833
5834     // If we are dealing with a COM event call, then we need to initialize the
5835     // COM event call information.
5836     if (SF_IsCOMEventCallStub(dwStubFlags))
5837     {
5838         _ASSERTE(pMD->IsComPlusCall()); //  no generic COM eventing
5839         ((ComPlusCallMethodDesc *)pMD)->InitComEventCallInfo();
5840     }
5841
5842     // Get the call signature information
5843     StubSigDesc sigDesc(pMD);
5844
5845     int         iLCIDArg = 0;
5846     int         numArgs = 0;
5847     int         numParamTokens = 0;
5848     mdParamDef* pParamTokenArray = NULL;
5849
5850     CreateNDirectStubAccessMetadata(&sigDesc,
5851                                     (CorPinvokeMap)0,
5852                                     &dwStubFlags,
5853                                     &iLCIDArg,
5854                                     &numArgs);
5855
5856     numParamTokens = numArgs + 1;
5857     pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5858     CollateParamTokens(sigDesc.m_pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray);
5859
5860     DispatchStubState MyStubState;
5861
5862     CreateNDirectStubWorker(&MyStubState,
5863                             &sigDesc,
5864                             (CorNativeLinkType)0,
5865                             (CorNativeLinkFlags)0,
5866                             (CorPinvokeMap)0,
5867                             dwStubFlags | NDIRECTSTUB_FL_COM,
5868                             pMD,
5869                             pParamTokenArray,
5870                             iLCIDArg);
5871
5872     _ASSERTE(pMD->IsComPlusCall()); // no generic disp-calls
5873     ((ComPlusCallMethodDesc *)pMD)->InitRetThunk();
5874 }
5875
5876
5877 #endif // FEATURE_COMINTEROP
5878
5879 /*static*/
5880 LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod)
5881 {
5882     // GetProcAddress cannot be called while preemptive GC is disabled.
5883     // It requires the OS to take the loader lock.
5884     CONTRACT(LPVOID)
5885     {
5886         STANDARD_VM_CHECK;
5887         PRECONDITION(CheckPointer(pMD));
5888         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5889     }
5890     CONTRACT_END;
5891
5892     g_IBCLogger.LogNDirectCodeAccess(pMD);
5893
5894 #ifdef MDA_SUPPORTED
5895     MDA_TRIGGER_ASSISTANT(PInvokeLog, LogPInvoke(pMD, hMod));
5896 #endif
5897
5898     RETURN pMD->FindEntryPoint(hMod);
5899 }
5900
5901 VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget)
5902 {
5903     CONTRACTL
5904     {
5905         THROWS;
5906         GC_TRIGGERS;
5907         MODE_ANY;
5908
5909         PRECONDITION(IsNDirect());
5910         PRECONDITION(pTarget != NULL);
5911     }
5912     CONTRACTL_END;
5913
5914     Stub *pInterceptStub = NULL;
5915
5916 #ifdef _TARGET_X86_
5917
5918
5919 #ifdef MDA_SUPPORTED
5920     if (!IsQCall() && MDA_GET_ASSISTANT(PInvokeStackImbalance))
5921     {
5922         pInterceptStub = GenerateStubForMDA(pTarget, pInterceptStub);
5923     }
5924 #endif // MDA_SUPPORTED
5925
5926
5927 #endif // _TARGET_X86_
5928
5929
5930     NDirectWriteableData* pWriteableData = GetWriteableData();
5931     EnsureWritablePages(pWriteableData);
5932     g_IBCLogger.LogNDirectCodeAccess(this);
5933
5934     if (pInterceptStub != NULL)
5935     {
5936         ndirect.m_pNativeNDirectTarget = pTarget;
5937         
5938 #if defined(_TARGET_X86_)
5939         pTarget = (PVOID)pInterceptStub->GetEntryPoint();
5940
5941         LPVOID oldTarget = GetNDirectImportThunkGlue()->GetEntrypoint();
5942         if (FastInterlockCompareExchangePointer(&pWriteableData->m_pNDirectTarget, pTarget,
5943                                                 oldTarget) != oldTarget)
5944         {
5945             pInterceptStub->DecRef();
5946         }
5947 #else
5948         _ASSERTE(pInterceptStub == NULL); // we don't intercept for anything else than host on !_TARGET_X86_
5949 #endif
5950     }
5951     else
5952     {
5953         pWriteableData->m_pNDirectTarget = pTarget;
5954     }
5955 }
5956
5957
5958
5959 #if defined(_TARGET_X86_) && defined(MDA_SUPPORTED)
5960 EXTERN_C VOID __stdcall PInvokeStackImbalanceWorker(StackImbalanceCookie *pSICookie, DWORD dwPostESP)
5961 {
5962     STATIC_CONTRACT_THROWS;
5963     STATIC_CONTRACT_GC_TRIGGERS;
5964     STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
5965
5966     // make sure we restore the original Win32 last error before leaving this function - we are
5967     // called right after returning from the P/Invoke target and the error has not been saved yet
5968     BEGIN_PRESERVE_LAST_ERROR;
5969
5970     MdaPInvokeStackImbalance* pProbe = MDA_GET_ASSISTANT(PInvokeStackImbalance);
5971
5972     // This MDA must be active if we generated a call to PInvokeStackImbalanceHelper
5973     _ASSERTE(pProbe);
5974
5975     pProbe->CheckStack(pSICookie, dwPostESP);
5976
5977     END_PRESERVE_LAST_ERROR;
5978 }
5979 #endif // _TARGET_X86_ && MDA_SUPPORTED
5980
5981
5982 // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places
5983 // if earlier loads fail and those later loads obliterate error codes.
5984 //
5985 // This tracker object will keep track of the error code in accordance to priority:
5986 //
5987 //   low-priority:      unknown error code (should never happen)
5988 //   medium-priority:   dll not found
5989 //   high-priority:     dll found but error during loading
5990 //   
5991 // We will overwrite the previous load's error code only if the new error code is higher priority.
5992 //
5993
5994 class LoadLibErrorTracker
5995 {
5996 private:
5997     static const DWORD const_priorityNotFound     = 10;
5998     static const DWORD const_priorityAccessDenied = 20;
5999     static const DWORD const_priorityCouldNotLoad = 99999;
6000 public:
6001     LoadLibErrorTracker()
6002     {
6003         LIMITED_METHOD_CONTRACT;
6004         m_hr = E_FAIL;
6005         m_priorityOfLastError = 0;
6006     }
6007
6008     VOID TrackErrorCode()
6009     {
6010         LIMITED_METHOD_CONTRACT;
6011
6012         DWORD priority;
6013
6014 #ifdef FEATURE_PAL
6015
6016         SetMessage(PAL_GetLoadLibraryError());
6017 #else
6018         
6019         DWORD dwLastError = GetLastError();
6020
6021         switch (dwLastError)
6022         {
6023             case ERROR_FILE_NOT_FOUND:
6024             case ERROR_PATH_NOT_FOUND:
6025             case ERROR_MOD_NOT_FOUND:
6026             case ERROR_DLL_NOT_FOUND:
6027                 priority = const_priorityNotFound;
6028                 break;
6029
6030             // If we can't access a location, we can't know if the dll's there or if it's good.
6031             // Still, this is probably more unusual (and thus of more interest) than a dll-not-found
6032             // so give it an intermediate priority.
6033             case ERROR_ACCESS_DENIED:
6034                 priority = const_priorityAccessDenied;
6035
6036             // Assume all others are "dll found but couldn't load."
6037             default:
6038                 priority = const_priorityCouldNotLoad;
6039                 break;
6040         }
6041         UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError));
6042 #endif
6043     }
6044
6045     // Sets the error code to HRESULT as could not load DLL
6046     void TrackHR_CouldNotLoad(HRESULT hr)
6047     {
6048         UpdateHR(const_priorityCouldNotLoad, hr);
6049     }
6050     
6051     HRESULT GetHR()
6052     {
6053         return m_hr;
6054     }
6055
6056     SString& GetMessage()
6057     {
6058         return m_message;
6059     }
6060
6061     void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath)
6062     {
6063         STANDARD_VM_CONTRACT;
6064
6065 #if defined(__APPLE__)
6066         COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_MAC, libraryNameOrPath.GetUnicode(), GetMessage());
6067 #elif defined(FEATURE_PAL)
6068         COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_LINUX, libraryNameOrPath.GetUnicode(), GetMessage());
6069 #else // __APPLE__
6070         HRESULT theHRESULT = GetHR();
6071         if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT))
6072         {
6073             COMPlusThrow(kBadImageFormatException);
6074         }
6075         else
6076         {
6077             SString hrString;
6078             GetHRMsg(theHRESULT, hrString);
6079             COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB_WIN, libraryNameOrPath.GetUnicode(), hrString);
6080         }
6081 #endif // FEATURE_PAL
6082
6083         __UNREACHABLE();
6084     }
6085
6086 private:
6087     void UpdateHR(DWORD priority, HRESULT hr)
6088     {
6089         if (priority > m_priorityOfLastError)
6090         {
6091             m_hr                  = hr;
6092             m_priorityOfLastError = priority;
6093         }
6094     }
6095
6096     void SetMessage(LPCSTR message)
6097     {
6098         m_message = SString(SString::Utf8, message);
6099     }
6100
6101     HRESULT m_hr;
6102     DWORD   m_priorityOfLastError;
6103     SString  m_message;
6104 };  // class LoadLibErrorTracker
6105
6106 // Load the library directly. On Unix systems, don't register it yet with PAL. 
6107 // * External callers like AssemblyNative::InternalLoadUnmanagedDllFromPath() and the upcoming 
6108 //   System.Runtime.Interop.Marshall.LoadLibrary() need the raw system handle
6109 // * Internal callers like LoadLibraryModule() can convert this handle to a HMODULE via PAL APIs on Unix
6110 static NATIVE_LIBRARY_HANDLE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
6111 {
6112     STANDARD_VM_CONTRACT;
6113
6114     NATIVE_LIBRARY_HANDLE hmod = NULL;
6115
6116 #ifndef FEATURE_PAL
6117
6118     if ((flags & 0xFFFFFF00) != 0
6119 #ifndef FEATURE_CORESYSTEM
6120         && NDirect::SecureLoadLibrarySupported()
6121 #endif // !FEATURE_CORESYSTEM
6122         )
6123     {
6124         hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00);
6125         if (hmod != NULL)
6126         {
6127             return hmod;
6128         }
6129
6130         DWORD dwLastError = GetLastError();
6131         if (dwLastError != ERROR_INVALID_PARAMETER)
6132         {
6133             pErrorTracker->TrackErrorCode();
6134             return hmod;
6135         }
6136     }
6137
6138     hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF);
6139     
6140 #else // !FEATURE_PAL
6141     hmod = PAL_LoadLibraryDirect(name);
6142 #endif // !FEATURE_PAL
6143         
6144     if (hmod == NULL)
6145     {
6146         pErrorTracker->TrackErrorCode();
6147     }
6148     
6149     return hmod;
6150 }
6151
6152 #if !defined(FEATURE_PAL)
6153 bool         NDirect::s_fSecureLoadLibrarySupported = false;
6154 #endif
6155
6156 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
6157 #define TOHEX(a)   ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
6158
6159 #ifdef FEATURE_PAL
6160 #define PLATFORM_SHARED_LIB_SUFFIX_W PAL_SHLIB_SUFFIX_W
6161 #define PLATFORM_SHARED_LIB_PREFIX_W PAL_SHLIB_PREFIX_W
6162 #else // !FEATURE_PAL
6163 #define PLATFORM_SHARED_LIB_SUFFIX_W W(".dll")
6164 #define PLATFORM_SHARED_LIB_PREFIX_W W("")
6165 #endif // !FEATURE_PAL
6166
6167 // The Bit 0x2 has different semantics in DllImportSearchPath and LoadLibraryExA flags.
6168 // In DllImportSearchPath enum, bit 0x2 represents SearchAssemblyDirectory -- which is performed by CLR.
6169 // Unlike other bits in this enum, this bit shouldn't be directly passed on to LoadLibrary()
6170 #define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2
6171
6172 // DllImportSearchPathFlags is a special enumeration, whose values are tied closely with LoadLibrary flags.
6173 // There is no "default" value DllImportSearchPathFlags. In the absence of DllImportSearchPath attribute, 
6174 // CoreCLR's LoadLibrary implementation uses the following defaults.
6175 // Other implementations of LoadLibrary callbacks/events are free to use other default conventions.
6176 void GetDefaultDllImportSearchPathFlags(DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory)
6177 {
6178     STANDARD_VM_CONTRACT;
6179
6180     *searchAssemblyDirectory = TRUE;
6181     *dllImportSearchPathFlags = 0;
6182 }
6183
6184 // If a module has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and return true.
6185 // Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false.
6186 BOOL GetDllImportSearchPathFlags(Module *pModule, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory)
6187 {
6188     STANDARD_VM_CONTRACT;
6189
6190     if (pModule->HasDefaultDllImportSearchPathsAttribute())
6191     {
6192         *dllImportSearchPathFlags = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
6193         *searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
6194         return TRUE;
6195     }
6196
6197     GetDefaultDllImportSearchPathFlags(dllImportSearchPathFlags, searchAssemblyDirectory);
6198     return FALSE;
6199 }
6200
6201 // If a pInvoke has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true.
6202 // Otherwise, if the containing assembly has the DefaultDllImportSearchPathsAttribute, get DllImportSearchPathFlags from it, and returns true.
6203 // Otherwise, get CoreCLR's default value for DllImportSearchPathFlags, and return false.
6204 BOOL GetDllImportSearchPathFlags(NDirectMethodDesc * pMD, DWORD *dllImportSearchPathFlags, BOOL *searchAssemblyDirectory)
6205 {
6206     STANDARD_VM_CONTRACT;
6207
6208     if (pMD->HasDefaultDllImportSearchPathsAttribute())
6209     {
6210         *dllImportSearchPathFlags = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
6211         *searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
6212         return TRUE;
6213     }
6214
6215     return GetDllImportSearchPathFlags(pMD->GetModule(), dllImportSearchPathFlags, searchAssemblyDirectory);
6216 }
6217
6218 // static
6219 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError)
6220 {
6221     CONTRACTL
6222     {
6223         STANDARD_VM_CHECK;
6224         PRECONDITION(CheckPointer(libraryPath));
6225     }
6226     CONTRACTL_END;
6227
6228     LoadLibErrorTracker errorTracker;
6229     const NATIVE_LIBRARY_HANDLE hmod =
6230         LocalLoadLibraryHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
6231     
6232     if (throwOnError && (hmod == nullptr))
6233     {
6234         SString libraryPathSString(libraryPath);
6235         errorTracker.Throw(libraryPathSString);
6236     }
6237     return hmod;
6238 }
6239
6240 // static 
6241 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryByName(LPCWSTR libraryName, Assembly *callingAssembly, 
6242                                                  BOOL hasDllImportSearchFlags, DWORD dllImportSearchFlags, 
6243                                                  BOOL throwOnError)
6244 {
6245     CONTRACTL
6246     {
6247         STANDARD_VM_CHECK;
6248         PRECONDITION(CheckPointer(libraryName));
6249         PRECONDITION(CheckPointer(callingAssembly));
6250     }
6251     CONTRACTL_END;
6252
6253     LoadLibErrorTracker errorTracker;
6254
6255     // First checks if a default dllImportSearchPathFlags was passed in, if so, use that value.
6256     // Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. 
6257     // If so, use that value.
6258     BOOL searchAssemblyDirectory;
6259     DWORD dllImportSearchPathFlags;
6260
6261     if (hasDllImportSearchFlags)
6262     {
6263         dllImportSearchPathFlags = dllImportSearchFlags & ~DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
6264         searchAssemblyDirectory = dllImportSearchFlags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
6265
6266     }
6267     else
6268     {
6269         GetDllImportSearchPathFlags(callingAssembly->GetManifestModule(),
6270                                     &dllImportSearchPathFlags, &searchAssemblyDirectory);
6271     }
6272
6273     NATIVE_LIBRARY_HANDLE hmod = 
6274         LoadLibraryModuleBySearch(callingAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, &errorTracker, libraryName);
6275
6276     if (throwOnError && (hmod == nullptr))
6277     {
6278         SString libraryPathSString(libraryName);
6279         errorTracker.Throw(libraryPathSString);
6280     }
6281
6282     return hmod;
6283 }
6284
6285 // static
6286 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, PCWSTR wszLibName)
6287 {
6288     STANDARD_VM_CONTRACT;
6289    
6290     BOOL searchAssemblyDirectory;
6291     DWORD dllImportSearchPathFlags;
6292
6293     GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory);
6294
6295     Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6296     return LoadLibraryModuleBySearch(pAssembly, searchAssemblyDirectory, dllImportSearchPathFlags, pErrorTracker, wszLibName);
6297 }
6298
6299 // static
6300 void NDirect::FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle)
6301 {
6302     STANDARD_VM_CONTRACT;
6303     
6304     // FreeLibrary doesn't throw if the input is null.
6305     // This avoids further null propagation/check while freeing resources (ex: in finally blocks)
6306     if (handle == NULL)
6307         return;
6308
6309 #ifndef FEATURE_PAL
6310     BOOL retVal = FreeLibrary(handle);
6311 #else // !FEATURE_PAL
6312     BOOL retVal = PAL_FreeLibraryDirect(handle);
6313 #endif // !FEATURE_PAL
6314
6315     if (retVal == 0)
6316         COMPlusThrow(kInvalidOperationException, W("Arg_InvalidOperationException"));
6317 }
6318
6319 //static 
6320 INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError)
6321 {
6322     CONTRACTL
6323     {
6324         STANDARD_VM_CHECK;
6325         PRECONDITION(CheckPointer(handle));
6326         PRECONDITION(CheckPointer(symbolName));
6327     }
6328     CONTRACTL_END;
6329
6330     MAKE_UTF8PTR_FROMWIDE(lpstr, symbolName);
6331
6332 #ifndef FEATURE_PAL
6333     INT_PTR address = reinterpret_cast<INT_PTR>(GetProcAddress((HMODULE)handle, lpstr));
6334     if ((address == NULL) && throwOnError)
6335         COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_WIN_DLL, symbolName);
6336 #else // !FEATURE_PAL
6337     INT_PTR address = reinterpret_cast<INT_PTR>(PAL_GetProcAddressDirect((NATIVE_LIBRARY_HANDLE)handle, lpstr));
6338     if ((address == NULL) && throwOnError)
6339         COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDR_UNIX_SO, symbolName);
6340 #endif // !FEATURE_PAL
6341
6342     return address;
6343 }
6344
6345 #ifndef PLATFORM_UNIX
6346 BOOL IsWindowsAPISet(PCWSTR wszLibName)
6347 {
6348     STANDARD_VM_CONTRACT;
6349
6350     // This is replicating quick check from the OS implementation of api sets.
6351     return SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || 
6352            SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0;
6353 }
6354 #endif // !PLATFORM_UNIX
6355
6356 // static
6357 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, PCWSTR wszLibName)
6358 {
6359     STANDARD_VM_CONTRACT;
6360     //Dynamic Pinvoke Support:
6361     //Check if we  need to provide the host a chance to provide the unmanaged dll 
6362
6363 #ifndef PLATFORM_UNIX
6364     if (IsWindowsAPISet(wszLibName))
6365     {
6366         // Prevent Overriding of Windows API sets.
6367         return NULL;
6368     }
6369 #endif // !PLATFORM_UNIX
6370
6371     NATIVE_LIBRARY_HANDLE hmod = NULL;
6372     AppDomain* pDomain = GetAppDomain();
6373     CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
6374     Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6375    
6376     PEFile *pManifestFile = pAssembly->GetManifestFile();
6377     PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
6378
6379     //Step 0: Check if  the assembly was bound using TPA. 
6380     //        The Binding Context can be null or an overridden TPA context
6381     if (pBindingContext == NULL)
6382     {
6383         // If we do not have any binder associated, then return to the default resolution mechanism.
6384         return NULL;
6385     }    
6386
6387     UINT_PTR assemblyBinderID = 0;
6388     IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6389         
6390     ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6391
6392     // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
6393     if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
6394     {
6395         return NULL;
6396     }
6397
6398 #ifdef FEATURE_COMINTEROP
6399     CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
6400     if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
6401     {
6402         // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
6403         // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
6404         //
6405         // For this, we should use the standard mechanism to make pinvoke call as well.
6406         return NULL;
6407     }
6408 #endif // FEATURE_COMINTEROP
6409     
6410     //Step 1: If the assembly was not bound using TPA,
6411     //        Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
6412     //        The custom assembly context a chance to load the unmanaged dll.
6413     
6414     GCX_COOP();
6415             
6416     STRINGREF pUnmanagedDllName;
6417     pUnmanagedDllName = StringObject::NewString(wszLibName);
6418         
6419     GCPROTECT_BEGIN(pUnmanagedDllName);
6420
6421     // Get the pointer to the managed assembly load context
6422     INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6423
6424     // Prepare to invoke  System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
6425     PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
6426     DECLARE_ARGHOLDER_ARRAY(args, 2);
6427     args[ARGNUM_0]  = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
6428     args[ARGNUM_1]  = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6429
6430     // Make the call
6431     CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
6432
6433     GCPROTECT_END();
6434
6435     return hmod;
6436 }
6437
6438 // Return the AssemblyLoadContext for an assembly
6439 INT_PTR GetManagedAssemblyLoadContext(Assembly* pAssembly)
6440 {
6441     STANDARD_VM_CONTRACT;
6442
6443     PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext();
6444     if (pBindingContext == NULL)
6445     {
6446         // GetBindingContext() returns NULL for System.Private.CoreLib
6447         return NULL;
6448     }
6449
6450     UINT_PTR assemblyBinderID = 0;
6451     IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6452
6453     AppDomain *pDomain = GetAppDomain();
6454     ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6455
6456 #ifdef FEATURE_COMINTEROP
6457     if (AreSameBinderInstance(pCurrentBinder, pDomain->GetWinRtBinder()))
6458     {
6459         // No ALC associated handle with WinRT Binders.
6460         return NULL;
6461     }
6462 #endif // FEATURE_COMINTEROP
6463
6464     // The code here deals with two implementations of ICLRPrivBinder interface: 
6465     //    - CLRPrivBinderCoreCLR for the TPA binder in the default ALC, and 
6466     //    - CLRPrivBinderAssemblyLoadContext for custom ALCs.
6467     // in order obtain the associated ALC handle.
6468     INT_PTR ptrManagedAssemblyLoadContext = AreSameBinderInstance(pCurrentBinder, pDomain->GetTPABinderContext())
6469         ? ((CLRPrivBinderCoreCLR *)pCurrentBinder)->GetManagedAssemblyLoadContext() 
6470         : ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6471
6472     return ptrManagedAssemblyLoadContext;
6473 }
6474
6475 // static
6476 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaEvent(NDirectMethodDesc * pMD, PCWSTR wszLibName)
6477 {
6478     STANDARD_VM_CONTRACT;
6479
6480     NATIVE_LIBRARY_HANDLE hmod = NULL;
6481     Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6482     INT_PTR ptrManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(pAssembly);
6483
6484     if (ptrManagedAssemblyLoadContext == NULL)
6485     {
6486         return NULL;
6487     }
6488
6489     GCX_COOP();
6490
6491     struct {
6492         STRINGREF DllName;
6493         OBJECTREF AssemblyRef;
6494     } gc = { NULL, NULL };
6495
6496     GCPROTECT_BEGIN(gc);
6497
6498     gc.DllName = StringObject::NewString(wszLibName);
6499     gc.AssemblyRef = pAssembly->GetExposedObject();
6500
6501     // Prepare to invoke  System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDllUsingEvent method
6502     // While ResolveUnmanagedDllUsingEvent() could compute the AssemblyLoadContext using the AssemblyRef
6503     // argument, it will involve another pInvoke to the runtime. So AssemblyLoadContext is passed in 
6504     // as an additional argument.
6505     PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLLUSINGEVENT);
6506     DECLARE_ARGHOLDER_ARRAY(args, 3);
6507     args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.DllName);
6508     args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.AssemblyRef);
6509     args[ARGNUM_2] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6510
6511     // Make the call
6512     CALL_MANAGED_METHOD(hmod, NATIVE_LIBRARY_HANDLE, args);
6513
6514     GCPROTECT_END();
6515
6516     return hmod;
6517 }
6518
6519 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallback(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
6520 {
6521     STANDARD_VM_CONTRACT;
6522
6523     if (pMD->GetModule()->IsSystem())
6524     {
6525         // Don't attempt to callback on Corelib itself.
6526         // The LoadLibrary callback stub is managed code that requires CoreLib 
6527         return NULL;
6528     }
6529
6530     DWORD dllImportSearchPathFlags;
6531     BOOL searchAssemblyDirectory;
6532     BOOL hasDllImportSearchPathFlags = GetDllImportSearchPathFlags(pMD, &dllImportSearchPathFlags, &searchAssemblyDirectory);
6533     dllImportSearchPathFlags |= searchAssemblyDirectory ? DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY : 0;
6534
6535     Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6536     NATIVE_LIBRARY_HANDLE handle = NULL;
6537
6538     GCX_COOP();
6539
6540     struct {
6541         STRINGREF libNameRef;
6542         OBJECTREF assemblyRef;
6543     } gc = { NULL, NULL };
6544
6545     GCPROTECT_BEGIN(gc);
6546
6547     gc.libNameRef = StringObject::NewString(wszLibName);
6548     gc.assemblyRef = pAssembly->GetExposedObject();
6549
6550     PREPARE_NONVIRTUAL_CALLSITE(METHOD__NATIVELIBRARY__LOADLIBRARYCALLBACKSTUB);
6551     DECLARE_ARGHOLDER_ARRAY(args, 4);
6552     args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(gc.libNameRef);
6553     args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.assemblyRef);
6554     args[ARGNUM_2] = BOOL_TO_ARGHOLDER(hasDllImportSearchPathFlags);
6555     args[ARGNUM_3] = DWORD_TO_ARGHOLDER(dllImportSearchPathFlags);
6556
6557      // Make the call
6558     CALL_MANAGED_METHOD(handle, NATIVE_LIBRARY_HANDLE, args);
6559     GCPROTECT_END();
6560
6561     return handle;
6562 }
6563
6564 // Try to load the module alongside the assembly where the PInvoke was declared.
6565 NATIVE_LIBRARY_HANDLE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6566 {
6567     STANDARD_VM_CONTRACT;
6568
6569     NATIVE_LIBRARY_HANDLE hmod = NULL;
6570
6571     SString path = pAssembly->GetManifestFile()->GetPath();
6572
6573     SString::Iterator lastPathSeparatorIter = path.End();
6574     if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
6575     {
6576         lastPathSeparatorIter++;
6577         path.Truncate(lastPathSeparatorIter);
6578
6579         path.Append(libName);
6580         hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
6581     }
6582
6583     return hmod;
6584 }
6585
6586 // Try to load the module from the native DLL search directories
6587 NATIVE_LIBRARY_HANDLE NDirect::LoadFromNativeDllSearchDirectories(LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6588 {
6589     STANDARD_VM_CONTRACT;
6590
6591     NATIVE_LIBRARY_HANDLE hmod = NULL;
6592     AppDomain* pDomain = GetAppDomain();
6593
6594     if (pDomain->HasNativeDllSearchDirectories())
6595     {
6596         AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
6597         while (hmod == NULL && pathIter.Next())
6598         {
6599             SString qualifiedPath(*(pathIter.GetPath()));
6600             qualifiedPath.Append(libName);
6601             if (!Path::IsRelative(qualifiedPath))
6602             {
6603                 hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
6604             }
6605         }
6606     }
6607
6608     return hmod;
6609 }
6610
6611 #ifdef FEATURE_PAL
6612 static const int MaxVariationCount = 4;
6613 static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
6614 {
6615     // Supported lib name variations
6616     static auto NameFmt = W("%.0s%s%.0s");
6617     static auto PrefixNameFmt = W("%s%s%.0s");
6618     static auto NameSuffixFmt = W("%.0s%s%s");
6619     static auto PrefixNameSuffixFmt = W("%s%s%s");
6620
6621     _ASSERTE(*numberOfVariations >= MaxVariationCount);
6622
6623     int varCount = 0;
6624     if (!libNameIsRelativePath)
6625     {
6626         libNameVariations[varCount++] = NameFmt;
6627     }
6628     else
6629     {
6630         // We check if the suffix is contained in the name, because on Linux it is common to append
6631         // a version number to the library name (e.g. 'libicuuc.so.57').
6632         bool containsSuffix = false;
6633         SString::CIterator it = libName.Begin();
6634         if (libName.Find(it, PLATFORM_SHARED_LIB_SUFFIX_W))
6635         {
6636             it += COUNTOF(PLATFORM_SHARED_LIB_SUFFIX_W);
6637             containsSuffix = it == libName.End() || *it == (WCHAR)'.';
6638         }
6639
6640         // If the path contains a path delimiter, we don't add a prefix
6641         it = libName.Begin();
6642         bool containsDelim = libName.Find(it, DIRECTORY_SEPARATOR_STR_W);
6643
6644         if (containsSuffix)
6645         {
6646             libNameVariations[varCount++] = NameFmt;
6647
6648             if (!containsDelim)
6649                 libNameVariations[varCount++] = PrefixNameFmt;
6650
6651             libNameVariations[varCount++] = NameSuffixFmt;
6652
6653             if (!containsDelim)
6654                 libNameVariations[varCount++] = PrefixNameSuffixFmt;
6655         }
6656         else
6657         {
6658             libNameVariations[varCount++] = NameSuffixFmt;
6659
6660             if (!containsDelim)
6661                 libNameVariations[varCount++] = PrefixNameSuffixFmt;
6662
6663             libNameVariations[varCount++] = NameFmt;
6664
6665             if (!containsDelim)
6666                 libNameVariations[varCount++] = PrefixNameFmt;
6667         }
6668     }
6669
6670     *numberOfVariations = varCount;
6671 }
6672 #else // FEATURE_PAL
6673 static const int MaxVariationCount = 2;
6674 static void DetermineLibNameVariations(const WCHAR** libNameVariations, int* numberOfVariations, const SString& libName, bool libNameIsRelativePath)
6675 {
6676     // Supported lib name variations
6677     static auto NameFmt = W("%.0s%s%.0s");
6678     static auto NameSuffixFmt = W("%.0s%s%s");
6679
6680     _ASSERTE(*numberOfVariations >= MaxVariationCount);
6681
6682     int varCount = 0;
6683
6684     // The purpose of following code is to workaround LoadLibrary limitation: 
6685     // LoadLibrary won't append extension if filename itself contains '.'. Thus it will break the following scenario:
6686     // [DllImport("A.B")] // The full name for file is "A.B.dll". This is common code pattern for cross-platform PInvoke
6687     // The workaround for above scenario is to call LoadLibrary with "A.B" first, if it fails, then call LoadLibrary with "A.B.dll"
6688     auto it = libName.Begin();
6689     if (!libNameIsRelativePath ||
6690         !libName.Find(it, W('.')) || 
6691         libName.EndsWith(W(".")) || 
6692         libName.EndsWithCaseInsensitive(W(".dll")) || 
6693         libName.EndsWithCaseInsensitive(W(".exe")))
6694     {
6695         // Follow LoadLibrary rules in MSDN doc: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
6696         // If the string specifies a full path, the function searches only that path for the module.
6697         // 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.
6698         // To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string.
6699         libNameVariations[varCount++] = NameFmt;
6700     }
6701     else
6702     {
6703         libNameVariations[varCount++] = NameFmt;
6704         libNameVariations[varCount++] = NameSuffixFmt;
6705     }
6706
6707     *numberOfVariations = varCount;
6708 }
6709 #endif // FEATURE_PAL
6710
6711 // Search for the library and variants of its name in probing directories.
6712 //static 
6713 NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleBySearch(Assembly *callingAssembly, 
6714                                                          BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlags,
6715                                                          LoadLibErrorTracker * pErrorTracker, LPCWSTR wszLibName)
6716 {
6717     STANDARD_VM_CONTRACT;
6718
6719     NATIVE_LIBRARY_HANDLE hmod = NULL;
6720
6721 #if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX)
6722     // Try to go straight to System32 for Windows API sets. This is replicating quick check from
6723     // the OS implementation of api sets.
6724     if (IsWindowsAPISet(wszLibName))
6725     {
6726         hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
6727         if (hmod != NULL)
6728         {
6729             return hmod;
6730         }
6731     }
6732 #endif // FEATURE_CORESYSTEM && !FEATURE_PAL
6733
6734     AppDomain* pDomain = GetAppDomain();
6735     DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
6736     bool libNameIsRelativePath = Path::IsRelative(wszLibName);
6737
6738     // P/Invokes are often declared with variations on the actual library name.
6739     // For example, it's common to leave off the extension/suffix of the library
6740     // even if it has one, or to leave off a prefix like "lib" even if it has one
6741     // (both of these are typically done to smooth over cross-platform differences). 
6742     // We try to dlopen with such variations on the original.
6743     const WCHAR* prefixSuffixCombinations[MaxVariationCount] = {};
6744     int numberOfVariations = COUNTOF(prefixSuffixCombinations);
6745     DetermineLibNameVariations(prefixSuffixCombinations, &numberOfVariations, wszLibName, libNameIsRelativePath);
6746     for (int i = 0; i < numberOfVariations; i++)
6747     {
6748         SString currLibNameVariation;
6749         currLibNameVariation.Printf(prefixSuffixCombinations[i], PLATFORM_SHARED_LIB_PREFIX_W, wszLibName, PLATFORM_SHARED_LIB_SUFFIX_W);
6750
6751         // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path
6752         hmod = LoadFromNativeDllSearchDirectories(currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
6753         if (hmod != NULL)
6754         {
6755             return hmod;
6756         }
6757
6758         if (!libNameIsRelativePath)
6759         {
6760             DWORD flags = loadWithAlteredPathFlags;
6761             if ((dllImportSearchPathFlags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
6762             {
6763                 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
6764                 // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
6765                 flags |= dllImportSearchPathFlags;
6766             }
6767
6768             hmod = LocalLoadLibraryHelper(currLibNameVariation, flags, pErrorTracker);
6769             if (hmod != NULL)
6770             {
6771                 return hmod;
6772             }
6773         }
6774         else if ((callingAssembly != nullptr) && searchAssemblyDirectory)
6775         {
6776             hmod = LoadFromPInvokeAssemblyDirectory(callingAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
6777             if (hmod != NULL)
6778             {
6779                 return hmod;
6780             }
6781         }
6782
6783         hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlags, pErrorTracker);
6784         if (hmod != NULL)
6785         {
6786             return hmod;
6787         }
6788     }
6789
6790     // This may be an assembly name
6791     // Format is "fileName, assemblyDisplayName"
6792     MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
6793     char *szComma = strchr(szLibName, ',');
6794     if (szComma)
6795     {
6796         *szComma = '\0';
6797         // Trim white spaces
6798         while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
6799
6800         AssemblySpec spec;
6801         if (SUCCEEDED(spec.Init(szComma)))
6802         {
6803             // Need to perform case insensitive hashing.
6804             CQuickBytes qbLC;
6805             {
6806                 UTF8_TO_LOWER_CASE(szLibName, qbLC);
6807                 szLibName = (LPUTF8) qbLC.Ptr();
6808             }
6809
6810             Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
6811             Module *pModule = pAssembly->FindModuleByName(szLibName);
6812
6813             hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlags, pErrorTracker);
6814         }
6815     }
6816
6817     return hmod;
6818 }
6819
6820 // This Method returns an instance of the PAL-Registered handle
6821 HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
6822 {
6823     CONTRACTL
6824     {
6825         STANDARD_VM_CHECK;
6826         PRECONDITION( CheckPointer( pMD ) );
6827     }
6828     CONTRACTL_END;
6829     
6830     LPCUTF8 name = pMD->GetLibName();
6831     if ( !name || !*name )
6832         return NULL;
6833     
6834     PREFIX_ASSUME( name != NULL );
6835     MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
6836
6837     ModuleHandleHolder hmod = LoadLibraryModuleViaCallback(pMD, wszLibName);
6838     if (hmod != NULL)
6839     {
6840 #ifdef FEATURE_PAL
6841         hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6842 #endif // FEATURE_PAL
6843         return hmod.Extract();
6844     }
6845
6846     AppDomain* pDomain = GetAppDomain();
6847
6848     // AssemblyLoadContext is not supported in AppX mode and thus,
6849     // we should not perform PInvoke resolution via it when operating in AppX mode.
6850     if (!AppX::IsAppXProcess())
6851     {
6852         hmod = LoadLibraryModuleViaHost(pMD, wszLibName);
6853         if (hmod != NULL)
6854         {
6855 #ifdef FEATURE_PAL
6856             hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6857 #endif // FEATURE_PAL
6858             return hmod.Extract();
6859         }
6860     }
6861     
6862     hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
6863     if (hmod != NULL)
6864     {
6865        return hmod.Extract();
6866     }
6867
6868     hmod = LoadLibraryModuleBySearch(pMD, pErrorTracker, wszLibName);
6869     if (hmod != NULL)
6870     {
6871 #ifdef FEATURE_PAL
6872         hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6873 #endif // FEATURE_PAL
6874
6875         // If we have a handle add it to the cache.
6876         pDomain->AddUnmanagedImageToCache(wszLibName, hmod);
6877         return hmod.Extract();
6878     }
6879
6880     if (!AppX::IsAppXProcess())
6881     {
6882         hmod = LoadLibraryModuleViaEvent(pMD, wszLibName);
6883         if (hmod != NULL)
6884         {
6885 #ifdef FEATURE_PAL
6886             hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6887 #endif // FEATURE_PAL
6888             return hmod.Extract();
6889         }
6890     }
6891
6892     return hmod.Extract();
6893 }
6894
6895 //---------------------------------------------------------
6896 // Loads the DLL and finds the procaddress for an N/Direct call.
6897 //---------------------------------------------------------
6898 /* static */
6899 VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
6900 {
6901     CONTRACTL
6902     {
6903         STANDARD_VM_CHECK;
6904         PRECONDITION(CheckPointer(pMD));
6905     }
6906     CONTRACTL_END;
6907
6908     //
6909     // On the phone, we only allow platform assemblies to define pinvokes
6910     // unless the host has asked us otherwise.
6911     //
6912
6913     if (pMD->IsClassConstructorTriggeredAtLinkTime())
6914     {
6915         pMD->GetMethodTable()->CheckRunClassInitThrowing();
6916     }
6917
6918     if (pMD->IsQCall())
6919     {
6920         LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget;
6921
6922         // Do not repeat the lookup if the QCall was hardbound during ngen
6923         if (pvTarget == NULL)
6924         {
6925             pvTarget = ECall::GetQCallImpl(pMD);
6926         }
6927         else
6928         {
6929             _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD));
6930         }
6931
6932         pMD->SetNDirectTarget(pvTarget);
6933         return;
6934     }
6935
6936     // Loading unmanaged dlls can trigger dllmains which certainly count as code execution!
6937     pMD->EnsureActive();
6938
6939     LoadLibErrorTracker errorTracker;
6940
6941     BOOL fSuccess = FALSE;
6942     HINSTANCE hmod = LoadLibraryModule( pMD, &errorTracker );
6943     if ( hmod )
6944     {
6945         LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
6946         if (pvTarget)
6947         {
6948
6949 #ifdef MDA_SUPPORTED
6950             MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke);
6951             if (pOverlapCheck && pOverlapCheck->ShouldHook(pMD))
6952             {
6953                 LPVOID pNewTarget = pOverlapCheck->Register(hmod,pvTarget);
6954                 if (pNewTarget)
6955                 {
6956                     pvTarget = pNewTarget;
6957                 }
6958             }
6959 #endif
6960             pMD->SetNDirectTarget(pvTarget);
6961             fSuccess = TRUE;
6962         }
6963     }
6964
6965     if (!fSuccess)
6966     {
6967         if (pMD->GetLibName() == NULL)
6968             COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME);
6969
6970         StackSString ssLibName(SString::Utf8, pMD->GetLibName());
6971
6972         if (!hmod)
6973         {
6974             errorTracker.Throw(ssLibName);
6975         }
6976
6977         WCHAR wszEPName[50];
6978         if (WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0)
6979         {
6980             wszEPName[0] = W('?');
6981             wszEPName[1] = W('\0');
6982         }
6983 #ifdef FEATURE_PAL
6984         COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_UNIX, ssLibName.GetUnicode(), wszEPName);
6985 #else
6986         COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_WIN, ssLibName.GetUnicode(), wszEPName);
6987 #endif
6988     }
6989 }
6990
6991
6992 //---------------------------------------------------------
6993 // One-time init
6994 //---------------------------------------------------------
6995 /*static*/ void NDirect::Init()
6996 {
6997     CONTRACTL
6998     {
6999         THROWS;
7000         GC_TRIGGERS;
7001         MODE_ANY;
7002         INJECT_FAULT(COMPlusThrowOM());
7003     }
7004     CONTRACTL_END;
7005
7006 #if !defined(FEATURE_PAL)
7007     // Check if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
7008     HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
7009     _ASSERTE(hMod != NULL);
7010
7011     if (GetProcAddress(hMod, "AddDllDirectory") != NULL)
7012     {
7013         // The AddDllDirectory export was added in KB2533623 together with the new flag support
7014         s_fSecureLoadLibrarySupported = true;
7015     }
7016 #endif // !FEATURE_PAL
7017 }
7018
7019
7020 //==========================================================================
7021 // This function is reached only via NDirectImportThunk. It's purpose
7022 // is to ensure that the target DLL is fully loaded and ready to run.
7023 //
7024 // FUN FACTS: Though this function is actually entered in unmanaged mode,
7025 // it can reenter managed mode and throw a COM+ exception if the DLL linking
7026 // fails.
7027 //==========================================================================
7028
7029
7030 EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD)
7031 {
7032     LPVOID ret = NULL;
7033
7034     BEGIN_PRESERVE_LAST_ERROR;
7035
7036     CONTRACTL
7037     {
7038         THROWS;
7039         GC_TRIGGERS;
7040         MODE_PREEMPTIVE;
7041     }
7042     CONTRACTL_END;
7043
7044     INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7045     // this function is called by CLR to native assembly stubs which are called by 
7046     // managed code as a result, we need an unwind and continue handler to translate 
7047     // any of our internal exceptions into managed exceptions.
7048     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7049
7050     if (pMD->IsEarlyBound())
7051     {
7052         if (!pMD->IsZapped())
7053         {
7054             // we need the MD to be populated in case we decide to build an intercept
7055             // stub to wrap the target in InitEarlyBoundNDirectTarget
7056             PInvokeStaticSigInfo sigInfo;
7057             NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7058         }
7059
7060         pMD->InitEarlyBoundNDirectTarget();
7061     }
7062     else
7063     {
7064         //
7065         // Otherwise we're in an inlined pinvoke late bound MD
7066         //
7067         INDEBUG(Thread *pThread = GetThread());
7068         {
7069             _ASSERTE(pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr());
7070
7071             CONSISTENCY_CHECK(pMD->IsNDirect());
7072             //
7073             // With IL stubs, we don't have to do anything but ensure the DLL is loaded.
7074             //
7075
7076             if (!pMD->IsZapped())
7077             {
7078                 PInvokeStaticSigInfo sigInfo;
7079                 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7080             }
7081             else
7082             {
7083                 // must have been populated at NGEN time
7084                 _ASSERTE(pMD->GetLibName() != NULL);
7085             }
7086
7087             pMD->CheckRestore();
7088
7089             NDirect::NDirectLink(pMD);
7090         }
7091     }
7092
7093     ret = pMD->GetNDirectTarget();
7094
7095     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7096     UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7097
7098     END_PRESERVE_LAST_ERROR;
7099
7100     return ret;
7101 }
7102
7103 //===========================================================================
7104 //  Support for Pinvoke Calli instruction
7105 //
7106 //===========================================================================
7107
7108 EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
7109 {
7110     BEGIN_PRESERVE_LAST_ERROR;
7111
7112     STATIC_CONTRACT_THROWS;
7113     STATIC_CONTRACT_GC_TRIGGERS;
7114     STATIC_CONTRACT_MODE_COOPERATIVE;
7115     STATIC_CONTRACT_ENTRY_POINT;
7116
7117     MAKE_CURRENT_THREAD_AVAILABLE();
7118
7119 #ifdef _DEBUG
7120     Thread::ObjectRefFlush(CURRENT_THREAD);
7121 #endif
7122
7123     FrameWithCookie<PrestubMethodFrame> frame(pTransitionBlock, pMD);
7124     PrestubMethodFrame * pFrame = &frame;
7125
7126     pFrame->Push(CURRENT_THREAD);
7127
7128     _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7129     _ASSERTE(pMD == pFrame->GetFunction());
7130
7131     GetILStubForCalli(pVASigCookie, pMD);
7132
7133     pFrame->Pop(CURRENT_THREAD);
7134
7135     END_PRESERVE_LAST_ERROR;
7136 }
7137
7138 EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
7139 {
7140     BEGIN_PRESERVE_LAST_ERROR;
7141
7142     STATIC_CONTRACT_THROWS;
7143     STATIC_CONTRACT_GC_TRIGGERS;
7144     STATIC_CONTRACT_MODE_COOPERATIVE;
7145     STATIC_CONTRACT_ENTRY_POINT;
7146
7147     MAKE_CURRENT_THREAD_AVAILABLE();
7148
7149 #ifdef _DEBUG
7150     Thread::ObjectRefFlush(CURRENT_THREAD);
7151 #endif
7152
7153     FrameWithCookie<PInvokeCalliFrame> frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget);
7154     PInvokeCalliFrame * pFrame = &frame;
7155
7156     pFrame->Push(CURRENT_THREAD);
7157
7158     _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7159
7160     GetILStubForCalli(pVASigCookie, NULL);
7161
7162     pFrame->Pop(CURRENT_THREAD);
7163
7164     END_PRESERVE_LAST_ERROR;
7165 }
7166
7167 PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
7168 {
7169     CONTRACT(PCODE)
7170     {
7171         THROWS;
7172         GC_TRIGGERS;
7173         ENTRY_POINT;
7174         MODE_ANY;
7175         PRECONDITION(CheckPointer(pVASigCookie));
7176         PRECONDITION(CheckPointer(pMD, NULL_OK));
7177         POSTCONDITION(RETVAL != NULL);
7178     }
7179     CONTRACT_END;
7180
7181     PCODE pTempILStub = NULL;
7182
7183     INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7184     // this function is called by CLR to native assembly stubs which are called by 
7185     // managed code as a result, we need an unwind and continue handler to translate 
7186     // any of our internal exceptions into managed exceptions.
7187     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7188
7189     // Force a GC if the stress level is high enough
7190     GCStress<cfg_any>::MaybeTrigger();
7191
7192     GCX_PREEMP();
7193
7194     Signature signature = pVASigCookie->signature;
7195     CorPinvokeMap unmgdCallConv = pmNoMangle;
7196     
7197     DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
7198     
7199     // The MethodDesc pointer may in fact be the unmanaged target, see PInvokeStubs.asm.
7200     if (pMD == NULL || (UINT_PTR)pMD & 0x1)
7201     {
7202         pMD = NULL;
7203         dwStubFlags |= NDIRECTSTUB_FL_UNMANAGED_CALLI;
7204
7205         // need to convert the CALLI signature to stub signature with managed calling convention
7206         switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->signature))
7207         {
7208             case IMAGE_CEE_CS_CALLCONV_C:
7209                     unmgdCallConv = pmCallConvCdecl;
7210                     break;
7211             case IMAGE_CEE_CS_CALLCONV_STDCALL:
7212                     unmgdCallConv = pmCallConvStdcall;
7213                     break;
7214             case IMAGE_CEE_CS_CALLCONV_THISCALL:
7215                     unmgdCallConv = pmCallConvThiscall;
7216                     break;
7217             case IMAGE_CEE_CS_CALLCONV_FASTCALL:
7218                     unmgdCallConv = pmCallConvFastcall;
7219                     break;
7220             default:
7221                     COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
7222         }
7223
7224         LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
7225         PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
7226         CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
7227         
7228         // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT
7229         *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK;
7230         *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT;
7231
7232         signature = Signature(new_sig, signature.GetRawSigLen());
7233     }
7234     else
7235     {
7236         _ASSERTE(pMD->IsNDirect());
7237         dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
7238
7239         // vararg P/Invoke must be cdecl
7240         unmgdCallConv = pmCallConvCdecl;
7241
7242         if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
7243         {
7244             dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
7245         }
7246     }
7247
7248     mdMethodDef md;
7249     CorNativeLinkFlags nlFlags;
7250     CorNativeLinkType  nlType;
7251
7252     if (pMD != NULL)
7253     {
7254         PInvokeStaticSigInfo sigInfo(pMD);
7255
7256         md = pMD->GetMemberDef();
7257         nlFlags = sigInfo.GetLinkFlags();
7258         nlType  = sigInfo.GetCharSet();
7259     }
7260     else
7261     {
7262         md = mdMethodDefNil;
7263         nlFlags = nlfNone;
7264         nlType  = nltAnsi;
7265     }
7266
7267     StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule);
7268
7269     MethodDesc* pStubMD = NDirect::CreateCLRToNativeILStub(&sigDesc,
7270                                     nlType, 
7271                                     nlFlags, 
7272                                     unmgdCallConv,
7273                                     dwStubFlags);
7274
7275     pTempILStub = JitILStub(pStubMD);
7276
7277     InterlockedCompareExchangeT<PCODE>(&pVASigCookie->pNDirectILStub,
7278                                                     pTempILStub,
7279                                                     NULL);
7280
7281     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7282     UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7283
7284     RETURN pVASigCookie->pNDirectILStub;
7285 }
7286
7287 #endif // CROSSGEN_COMPILE
7288
7289 #endif // #ifndef DACCESS_COMPILE
7290
7291 //
7292 // Truncates a SString by first converting it to unicode and truncate it 
7293 // if it is larger than size. "..." will be appended if it is truncated.
7294 //
7295 void TruncateUnicodeString(SString &string, COUNT_T bufSize)
7296 {
7297     string.Normalize();
7298     if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize)
7299     {
7300         _ASSERTE(bufSize / sizeof(WCHAR) > 4);
7301         string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4);
7302         string.Append(W("..."));
7303     }
7304 }