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