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