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