1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
19 #include "dllimport.h"
21 #include "siginfo.hpp"
23 #include "comdelegate.h"
27 #include "comutilnative.h"
29 #include "asmconstants.h"
30 #include "mdaassistants.h"
31 #include "customattribute.h"
32 #include "ilstubcache.h"
33 #include "typeparse.h"
34 #include "sigbuilder.h"
35 #include "sigformat.h"
36 #include "strongnameholders.h"
39 #include <formattype.h>
40 #include "../md/compiler/custattr.h"
42 #ifdef FEATURE_COMINTEROP
43 #include "runtimecallablewrapper.h"
44 #include "clrtocomcall.h"
45 #endif // FEATURE_COMINTEROP
49 #endif // FEATURE_PREJIT
51 #include "eventtrace.h"
53 #ifndef FEATURE_CORECLR
55 #include "fxretarget.h"
58 #include "clr/fs/path.h"
59 using namespace clr::fs;
61 // remove when we get an updated SDK
62 #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
63 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
65 void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx)
67 LIMITED_METHOD_CONTRACT;
68 if (pClause->kind == ILStubEHClause::kNone)
74 CorExceptionFlag flags;
75 switch (pClause->kind)
77 case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break;
78 case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break;
80 UNREACHABLE_MSG("unexpected ILStubEHClause kind");
82 _ASSERTE(idx < nClauses);
83 pEHSect->Fat.Clauses[idx].Flags = flags;
84 pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset;
85 pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength;
86 pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset;
87 pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength;
88 pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken;
91 VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo)
93 LIMITED_METHOD_CONTRACT;
94 pEHSect->Fat.Kind = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
95 pEHSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses);
98 AppendEHClause(nClauses, pEHSect, pOne, &curIdx);
99 AppendEHClause(nClauses, pEHSect, pTwo, &curIdx);
102 StubSigDesc::StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo /*= NULL*/)
113 if (pSigInfo != NULL)
115 m_sig = pSigInfo->GetSignature();
116 m_pModule = pSigInfo->GetModule();
120 _ASSERTE(pMD != NULL);
121 m_sig = pMD->GetSignature();
122 m_pModule = pMD->GetModule(); // Used for token resolution.
127 m_tkMethodDef = pMD->GetMemberDef();
128 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
129 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
133 m_tkMethodDef = mdMethodDefNil;
134 m_pLoaderModule = m_pModule;
137 INDEBUG(InitDebugNames());
140 StubSigDesc::StubSigDesc(MethodDesc *pMD, Signature sig, Module *pModule)
147 PRECONDITION(!sig.IsEmpty());
148 PRECONDITION(pModule != NULL);
158 m_tkMethodDef = pMD->GetMemberDef();
159 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
160 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
164 m_tkMethodDef = mdMethodDefNil;
165 m_pLoaderModule = m_pModule;
168 INDEBUG(InitDebugNames());
171 #ifndef DACCESS_COMPILE
176 virtual void SetLastError(BOOL fSetLastError) = 0;
177 virtual void BeginEmit(DWORD dwStubFlags) = 0;
178 virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) = 0;
179 virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) = 0;
180 virtual void MarshalLCID(int argIdx) = 0;
182 #ifdef FEATURE_COMINTEROP
183 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray) = 0;
184 virtual void MarshalFactoryReturn() = 0;
185 #endif // FEATURE_COMINTEROP
187 virtual void EmitInvokeTarget(MethodDesc *pStubMD) = 0;
189 virtual void FinishEmit(MethodDesc* pMD) = 0;
193 LIMITED_METHOD_CONTRACT;
197 class ILStubState : public StubState
203 const Signature &signature,
204 SigTypeContext* pTypeContext,
209 MethodDesc* pTargetMD)
210 : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx, fTargetHasThis, fStubHasThis)
212 STANDARD_VM_CONTRACT;
218 void SetLastError(BOOL fSetLastError)
220 LIMITED_METHOD_CONTRACT;
222 m_fSetLastError = fSetLastError;
225 // We use three stub linkers to generate IL stubs. The pre linker is the main one. It does all the marshaling and
226 // then calls the target method. The post return linker is only used to unmarshal the return value after we return
227 // from the target method. The post linker handles all the unmarshaling for by ref arguments and clean-up. It
228 // also checks if we should throw an exception etc.
230 // Currently, we have two "emittable" ILCodeLabel's. The first one is at the beginning of the pre linker. This
231 // label is used to emit code to declare and initialize clean-up flags. Each argument which requires clean-up
232 // emits one flag. This flag is set only after the marshaling is done, and it is checked before we do any clean-up
235 // The second "emittable" ILCodeLabel is at the beginning of the post linker. It is used to emit code which is
236 // not safe to run in the case of an exception. The rest of the post linker is wrapped in a finally, and it contains
237 // with the necessary clean-up which should be executed in both normal and exception cases.
238 void BeginEmit(DWORD dwStubFlags)
241 m_slIL.Begin(dwStubFlags);
242 m_dwStubFlags = dwStubFlags;
245 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
251 PRECONDITION(CheckPointer(pInfo));
255 pInfo->GenerateReturnIL(&m_slIL, argOffset,
256 SF_IsForwardStub(m_dwStubFlags),
257 SF_IsFieldGetterStub(m_dwStubFlags),
258 SF_IsHRESULTSwapping(m_dwStubFlags));
261 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
266 PRECONDITION(CheckPointer(pInfo));
270 pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags));
273 #ifdef FEATURE_COMINTEROP
274 // Marshal the hidden length parameter for the managed parameter in pInfo
275 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray)
277 STANDARD_VM_CONTRACT;
279 pInfo->MarshalHiddenLengthArgument(&m_slIL, SF_IsForwardStub(m_dwStubFlags), isForReturnArray);
281 if (SF_IsReverseStub(m_dwStubFlags))
283 // Hidden length arguments appear explicitly in the native signature
284 // however, they are not in the managed signature.
285 m_slIL.AdjustTargetStackDeltaForExtraParam();
289 void MarshalFactoryReturn()
294 PRECONDITION(SF_IsCOMStub(m_dwStubFlags));
295 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
299 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
300 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
301 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
302 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
308 // create a local to hold the returned pUnk and initialize to 0 in case the factory fails
309 // and we try to release it during cleanup
310 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
311 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
312 pcsSetup->EmitLoadNullPtr();
313 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
315 DWORD dwInnerIInspectableLocalNum = -1;
316 DWORD dwOuterIInspectableLocalNum = -1;
317 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
319 // Create locals to store the outer and inner IInspectable values and initialize to null
320 // Note that we do this in the setup stream so that we're guaranteed to have a null-initialized
321 // value in the cleanup stream
322 LocalDesc locDescOuterIInspectable(ELEMENT_TYPE_I);
323 dwOuterIInspectableLocalNum = pcsSetup->NewLocal(locDescOuterIInspectable);
324 pcsSetup->EmitLoadNullPtr();
325 pcsSetup->EmitSTLOC(dwOuterIInspectableLocalNum);
326 LocalDesc locDescInnerIInspectable(ELEMENT_TYPE_I);
327 dwInnerIInspectableLocalNum = pcsSetup->NewLocal(locDescInnerIInspectable);
328 pcsSetup->EmitLoadNullPtr();
329 pcsSetup->EmitSTLOC(dwInnerIInspectableLocalNum);
336 // For composition factories, add the two extra params
337 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
339 // Get outer IInspectable. The helper will return NULL if this is the "top-level" constructor,
340 // and the appropriate outer pointer otherwise.
341 pcsDispatch->EmitLoadThis();
342 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
343 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_OUTER_INSPECTABLE, 2, 1);
344 pcsDispatch->EmitSTLOC(dwOuterIInspectableLocalNum);
346 // load the outer IInspectable (3rd last argument)
347 pcsDispatch->SetStubTargetArgType(ELEMENT_TYPE_I, false);
348 pcsDispatch->EmitLDLOC(dwOuterIInspectableLocalNum);
350 // pass pointer to where inner non-delegating IInspectable should be stored (2nd last argument)
351 LocalDesc locDescInnerPtr(ELEMENT_TYPE_I);
352 locDescInnerPtr.MakeByRef();
353 pcsDispatch->SetStubTargetArgType(&locDescInnerPtr, false);
354 pcsDispatch->EmitLDLOCA(dwInnerIInspectableLocalNum);
357 // pass pointer to the local to the factory method (last argument)
358 locDescFactoryRetVal.MakeByRef();
359 pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
360 pcsDispatch->EmitLDLOCA(dwFactoryRetValLocalNum);
366 // Mark that the factory method has succesfully returned and so cleanup will be necessary after
368 m_slIL.EmitSetArgMarshalIndex(pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
370 // associate the 'this' RCW with one of the returned interface pointers
371 pcsUnmarshal->EmitLoadThis();
373 // now we need to find the right interface pointer to load
374 if (dwInnerIInspectableLocalNum != -1)
376 // We may have a composition scenario
377 ILCodeLabel* pNonCompositionLabel = pcsUnmarshal->NewCodeLabel();
378 ILCodeLabel* pLoadedLabel = pcsUnmarshal->NewCodeLabel();
380 // Did we pass an outer IInspectable?
381 pcsUnmarshal->EmitLDLOC(dwOuterIInspectableLocalNum);
382 pcsUnmarshal->EmitBRFALSE(pNonCompositionLabel);
384 // yes, this is a composition scenario
386 // ignore the delegating interface pointer (will be released in cleanup below) - we can
387 // re-create it by QI'ing the non-delegating one.
388 // Note that using this could be useful in the future (avoids an extra QueryInterface call)
389 // Just load the non-delegating interface pointer
390 pcsUnmarshal->EmitLDLOCA(dwInnerIInspectableLocalNum);
391 pcsUnmarshal->EmitBR(pLoadedLabel);
393 // else, no this is a non-composition scenario
395 pcsUnmarshal->EmitLabel(pNonCompositionLabel);
397 // ignore the non-delegating interface pointer (which should be null, but will regardless get
398 // cleaned up below in the event the factory doesn't follow the pattern properly).
399 // Just load the regular delegating interface pointer
400 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
403 pcsUnmarshal->EmitLabel(pLoadedLabel);
407 // Definitely can't be a composition scenario - use the only pointer we have
408 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
411 pcsUnmarshal->EmitCALL(METHOD__MARSHAL__INITIALIZE_WRAPPER_FOR_WINRT, 2, 0);
417 // release the returned interface pointer in the finally block
418 m_slIL.SetCleanupNeeded();
420 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
422 m_slIL.EmitCheckForArgCleanup(pcsCleanup,
423 NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
424 NDirectStubLinker::BranchIfNotMarshaled,
427 EmitInterfaceClearNative(pcsCleanup, dwFactoryRetValLocalNum);
429 // Note that it's a no-op to pass NULL to Clear_Native, so we call it even though we don't
430 // know if we assigned to the inner/outer IInspectable
431 if (dwInnerIInspectableLocalNum != -1)
433 EmitInterfaceClearNative(pcsCleanup, dwInnerIInspectableLocalNum);
435 if (dwOuterIInspectableLocalNum != -1)
437 EmitInterfaceClearNative(pcsCleanup, dwOuterIInspectableLocalNum);
440 pcsCleanup->EmitLabel(pSkipCleanupLabel);
443 static void EmitInterfaceClearNative(ILCodeStream* pcsEmit, DWORD dwLocalNum)
445 STANDARD_VM_CONTRACT;
447 ILCodeLabel *pSkipClearNativeLabel = pcsEmit->NewCodeLabel();
448 pcsEmit->EmitLDLOC(dwLocalNum);
449 pcsEmit->EmitBRFALSE(pSkipClearNativeLabel);
450 pcsEmit->EmitLDLOC(dwLocalNum);
451 pcsEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
452 pcsEmit->EmitLabel(pSkipClearNativeLabel);
455 #endif // FEATURE_COMINTEROP
457 void MarshalLCID(int argIdx)
459 STANDARD_VM_CONTRACT;
461 ILCodeStream* pcs = m_slIL.GetDispatchCodeStream();
463 #ifdef FEATURE_USE_LCID
464 if (SF_IsReverseStub(m_dwStubFlags))
466 if ((m_slIL.GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_HASTHIS) == IMAGE_CEE_CS_CALLCONV_HASTHIS)
468 // the arg number will be incremented by LDARG if we are in an instance method
469 _ASSERTE(argIdx > 0);
473 LocalDesc locDescThread(MscorlibBinder::GetClass(CLASS__THREAD));
474 DWORD dwThreadLocalNum = pcs->NewLocal(locDescThread);
476 // call Thread.get_CurrentThread()
477 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
479 pcs->EmitSTLOC(dwThreadLocalNum);
481 // call current_thread.get_CurrentCulture()
482 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
484 // save the current culture
485 LocalDesc locDescCulture(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
486 DWORD dwCultureLocalNum = pcs->NewLocal(locDescCulture);
488 pcs->EmitSTLOC(dwCultureLocalNum);
490 // set a new one based on the LCID passed from unmanaged
491 pcs->EmitLDLOC(dwThreadLocalNum);
492 pcs->EmitLDARG(argIdx);
494 // call CultureInfo..ctor(lcid)
495 // call current_thread.set_CurrentCulture(culture)
496 pcs->EmitNEWOBJ(METHOD__CULTURE_INFO__INT_CTOR, 1);
497 pcs->EmitCALL(METHOD__THREAD__SET_CULTURE, 2, 0);
499 // and restore the current one after the call
500 m_slIL.SetCleanupNeeded();
501 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
503 // call current_thread.set_CurrentCulture(original_culture)
504 pcsCleanup->EmitLDLOC(dwThreadLocalNum);
505 pcsCleanup->EmitLDLOC(dwCultureLocalNum);
506 pcsCleanup->EmitCALL(METHOD__THREAD__SET_CULTURE, 1, 1);
511 if (SF_IsCOMStub(m_dwStubFlags))
513 // We used to get LCID from current thread's culture here. The code
514 // was replaced by the hardcoded LCID_ENGLISH_US as requested by VSTO.
515 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
519 // call Thread.get_CurrentThread()
520 // call current_thread.get_CurrentCulture()
521 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
522 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
524 //call CultureInfo.get_LCID(this)
525 pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1);
528 #else // FEATURE_USE_LCID
529 if (SF_IsForwardStub(m_dwStubFlags))
531 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
533 #endif // FEATURE_USE_LCID
535 // add the extra arg to the unmanaged signature
536 LocalDesc locDescNative(ELEMENT_TYPE_I4);
537 pcs->SetStubTargetArgType(&locDescNative, false);
539 if (SF_IsReverseStub(m_dwStubFlags))
541 // reverse the effect of SetStubTargetArgType on the stack delta
542 // (the LCID argument is explicitly passed from unmanaged but does not
543 // show up in the managed signature in any way)
544 m_slIL.AdjustTargetStackDeltaForExtraParam();
549 void SwapStubSignatures(MethodDesc* pStubMD)
551 STANDARD_VM_CONTRACT;
554 // Since the stub handles native-to-managed transitions, we have to swap the
555 // stub-state-calculated stub target sig with the stub sig itself. This is
556 // because the stub target sig represents the native signature and the stub
557 // sig represents the managed signature.
559 // The first step is to convert the managed signature to a module-independent
560 // signature and then pass it off to SetStubTargetMethodSig. Note that the
561 // ILStubResolver will copy the sig, so we only need to make a temporary copy
564 SigBuilder sigBuilder;
567 SigPointer sigPtr(pStubMD->GetSig());
568 sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder);
572 // The second step is to reset the sig on the stub MethodDesc to be the
573 // stub-state-calculated stub target sig.
577 // make a domain-local copy of the sig so that this state can outlive the
578 // compile time state.
581 PCCOR_SIGNATURE pNewSig;
583 cbNewSig = GetStubTargetMethodSigLength();
584 pNewSig = (PCCOR_SIGNATURE)(void *)pStubMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig));
586 memcpyNoGCRefs((void *)pNewSig, GetStubTargetMethodSig(), cbNewSig);
588 pStubMD->AsDynamicMethodDesc()->SetStoredMethodSig(pNewSig, cbNewSig);
590 SigPointer sigPtr(pNewSig, cbNewSig);
592 IfFailThrow(sigPtr.GetCallingConvInfo(&callConvInfo));
594 if (callConvInfo & CORINFO_CALLCONV_HASTHIS)
596 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags &= ~mdStatic;
597 pStubMD->ClearStatic();
601 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags |= mdStatic;
602 pStubMD->SetStatic();
606 // we store the real managed argument stack size in the stub MethodDesc on non-X86
607 UINT stackSize = pStubMD->SizeOfArgStack();
609 if (!FitsInU2(stackSize))
610 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
612 pStubMD->AsDynamicMethodDesc()->SetNativeStackArgSize(static_cast<WORD>(stackSize));
613 #endif // _TARGET_X86_
616 DWORD cbTempModuleIndependentSigLength;
617 BYTE * pTempModuleIndependentSig = (BYTE *)sigBuilder.GetSignature(&cbTempModuleIndependentSigLength);
620 SetStubTargetMethodSig(pTempModuleIndependentSig,
621 cbTempModuleIndependentSigLength);
624 void EmitInvokeTarget(MethodDesc *pStubMD)
626 STANDARD_VM_CONTRACT;
628 m_slIL.DoNDirect(m_slIL.GetDispatchCodeStream(), m_dwStubFlags, pStubMD);
631 #ifdef FEATURE_COMINTEROP
632 void EmitExceptionHandler(LocalDesc* pNativeReturnType, LocalDesc* pManagedReturnType,
633 ILCodeLabel** ppTryEndAndCatchBeginLabel, ILCodeLabel ** ppCatchEndAndReturnLabel)
635 STANDARD_VM_CONTRACT;
637 ILCodeStream* pcsExceptionHandler = m_slIL.NewCodeStream(ILStubLinker::kExceptionHandler);
638 *ppTryEndAndCatchBeginLabel = pcsExceptionHandler->NewCodeLabel();
639 *ppCatchEndAndReturnLabel = pcsExceptionHandler->NewCodeLabel();
641 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
642 pcsExceptionHandler->EmitLabel(*ppTryEndAndCatchBeginLabel);
644 BYTE nativeReturnElemType = pNativeReturnType->ElementType[0]; // return type of the stub
645 BYTE managedReturnElemType = pManagedReturnType->ElementType[0]; // return type of the mananged target
647 bool returnTheHRESULT = SF_IsHRESULTSwapping(m_dwStubFlags) ||
648 (managedReturnElemType == ELEMENT_TYPE_I4) ||
649 (managedReturnElemType == ELEMENT_TYPE_U4);
652 if (!returnTheHRESULT)
654 MdaExceptionSwallowedOnCallFromCom* mda = MDA_GET_ASSISTANT(ExceptionSwallowedOnCallFromCom);
657 // on the stack: exception object, but the stub linker doesn't know it
658 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
659 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__TRIGGER_EXCEPTION_SWALLOWED_MDA,
660 1, // WARNING: This method takes 2 input args, the exception object and the stub context.
661 // But the ILStubLinker has no knowledge that the exception object is on the
662 // stack (because it is unaware that we've just entered a catch block), so we
663 // lie and claim that we only take one input argument.
664 1); // returns the exception object back
667 #endif // MDA_SUPPORTED
669 DWORD retvalLocalNum = m_slIL.GetReturnValueLocalNum();
670 BinderMethodID getHRForException;
671 if (SF_IsWinRTStub(m_dwStubFlags))
673 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION_WINRT;
677 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION;
680 pcsExceptionHandler->EmitCALL(getHRForException,
681 0, // WARNING: This method takes 1 input arg, the exception object. But the ILStubLinker
682 // has no knowledge that the exception object is on the stack (because it is
683 // unaware that we've just entered a catch block), so we lie and claim that we
684 // don't take any input arguments.
687 switch (nativeReturnElemType)
690 UNREACHABLE_MSG("Unexpected element type found on native return type.");
692 case ELEMENT_TYPE_VOID:
693 _ASSERTE(retvalLocalNum == (DWORD)-1);
694 pcsExceptionHandler->EmitPOP();
696 case ELEMENT_TYPE_I4:
697 case ELEMENT_TYPE_U4:
699 if (!returnTheHRESULT)
701 pcsExceptionHandler->EmitPOP();
702 pcsExceptionHandler->EmitLDC(0);
703 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
705 _ASSERTE(retvalLocalNum != (DWORD)-1);
706 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
709 case ELEMENT_TYPE_R4:
710 pcsExceptionHandler->EmitPOP();
711 pcsExceptionHandler->EmitLDC_R4(CLR_NAN_32);
712 _ASSERTE(retvalLocalNum != (DWORD)-1);
713 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
715 case ELEMENT_TYPE_R8:
716 pcsExceptionHandler->EmitPOP();
717 pcsExceptionHandler->EmitLDC_R8(CLR_NAN_64);
718 _ASSERTE(retvalLocalNum != (DWORD)-1);
719 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
721 case ELEMENT_TYPE_INTERNAL:
723 TypeHandle returnTypeHnd = pNativeReturnType->InternalToken;
724 CONSISTENCY_CHECK(returnTypeHnd.IsValueType());
725 _ASSERTE(retvalLocalNum != (DWORD)-1);
726 pcsExceptionHandler->EmitLDLOCA(retvalLocalNum);
727 pcsExceptionHandler->EmitINITOBJ(m_slIL.GetDispatchCodeStream()->GetToken(returnTypeHnd));
730 case ELEMENT_TYPE_BOOLEAN:
731 case ELEMENT_TYPE_CHAR:
732 case ELEMENT_TYPE_I1:
733 case ELEMENT_TYPE_U1:
734 case ELEMENT_TYPE_I2:
735 case ELEMENT_TYPE_U2:
736 case ELEMENT_TYPE_I8:
737 case ELEMENT_TYPE_U8:
740 pcsExceptionHandler->EmitPOP();
741 pcsExceptionHandler->EmitLDC(0);
742 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
743 _ASSERTE(retvalLocalNum != (DWORD)-1);
744 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
748 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
749 pcsExceptionHandler->EmitLabel(*ppCatchEndAndReturnLabel);
750 if (nativeReturnElemType != ELEMENT_TYPE_VOID)
752 _ASSERTE(retvalLocalNum != (DWORD)-1);
753 pcsExceptionHandler->EmitLDLOC(retvalLocalNum);
755 pcsExceptionHandler->EmitRET();
757 #endif // FEATURE_COMINTEROP
759 void FinishEmit(MethodDesc* pStubMD)
761 STANDARD_VM_CONTRACT;
763 ILCodeStream* pcsMarshal = m_slIL.GetMarshalCodeStream();
764 ILCodeStream* pcsUnmarshal = m_slIL.GetUnmarshalCodeStream();
765 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
767 if (SF_IsHRESULTSwapping(m_dwStubFlags) && m_slIL.StubHasVoidReturnType())
769 // if the return type is void, but we're doing HRESULT swapping, we
770 // need to set the return type here. Otherwise, the return value
771 // marshaler will do this.
772 pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4); // HRESULT
774 if (SF_IsReverseStub(m_dwStubFlags))
776 // reverse interop needs to seed the return value if the
777 // managed function returns void but we're doing hresult
779 pcsUnmarshal->EmitLDC(S_OK);
783 LocalDesc nativeReturnType;
784 LocalDesc managedReturnType;
785 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(m_dwStubFlags)
786 && !SF_IsFieldGetterStub(m_dwStubFlags)
787 && !SF_IsFieldSetterStub(m_dwStubFlags);
789 #ifdef FEATURE_COMINTEROP
790 if (hasTryCatchForHRESULT)
792 m_slIL.GetStubTargetReturnType(&nativeReturnType);
793 m_slIL.GetStubReturnType(&managedReturnType);
795 #endif // FEATURE_COMINTEROP
797 if (SF_IsHRESULTSwapping(m_dwStubFlags) && SF_IsReverseStub(m_dwStubFlags))
799 m_slIL.AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
802 if (SF_IsForwardCOMStub(m_dwStubFlags))
804 // Compensate for the 'this' parameter.
805 m_slIL.AdjustTargetStackDeltaForExtraParam();
808 #if defined(_TARGET_X86_)
809 // unmanaged CALLI will get an extra arg with the real target address if host hook is enabled
810 if (SF_IsCALLIStub(m_dwStubFlags) && NDirect::IsHostHookEnabled())
812 pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I, false);
814 #endif // _TARGET_X86_
816 // Don't touch target signatures from this point on otherwise it messes up the
817 // cache in ILStubState::GetStubTargetMethodSig.
821 // The native and local signatures should not have any tokens.
822 // All token references should have been converted to
823 // ELEMENT_TYPE_INTERNAL.
825 // Note that MetaSig::GetReturnType and NextArg will normalize
826 // ELEMENT_TYPE_INTERNAL back to CLASS or VALUETYPE.
828 // <TODO> need to recursively check ELEMENT_TYPE_FNPTR signatures </TODO>
830 SigTypeContext typeContext; // this is an empty type context: COM calls are guaranteed to not be generics.
832 GetStubTargetMethodSig(),
833 GetStubTargetMethodSigLength(),
834 MscorlibBinder::GetModule(),
838 IfFailThrow(nsig.GetReturnProps().PeekElemType(&type));
839 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
841 while (ELEMENT_TYPE_END != (type = nsig.NextArg()))
843 IfFailThrow(nsig.GetArgProps().PeekElemType(&type));
844 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
849 #ifdef FEATURE_COMINTEROP
850 if (SF_IsForwardCOMStub(m_dwStubFlags))
852 #if defined(MDA_SUPPORTED)
853 // We won't use this NGEN'ed stub if RaceOnRCWCleanup is enabled at run-time
854 if (!SF_IsNGENedStub(m_dwStubFlags))
856 // This code may change the type of the frame we use, so it has to be run before the code below where we
857 // retrieve the stack arg size based on the frame type.
858 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
861 // Here we have to register the RCW of the "this" object to the RCWStack and schedule the clean-up for it.
862 // Emit a call to StubHelpers::StubRegisterRCW() and StubHelpers::StubUnregisterRCW() to do this.
863 m_slIL.EmitLoadRCWThis(pcsMarshal, m_dwStubFlags);
864 pcsMarshal->EmitCALL(METHOD__STUBHELPERS__STUB_REGISTER_RCW, 1, 0);
866 // We use an extra local to track whether we need to unregister the RCW on cleanup
867 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
868 DWORD dwRCWRegisteredLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
869 pcsSetup->EmitLDC(0);
870 pcsSetup->EmitSTLOC(dwRCWRegisteredLocalNum);
872 pcsMarshal->EmitLDC(1);
873 pcsMarshal->EmitSTLOC(dwRCWRegisteredLocalNum);
875 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
876 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
878 m_slIL.SetCleanupNeeded();
879 pcsCleanup->EmitLDLOC(dwRCWRegisteredLocalNum);
880 pcsCleanup->EmitBRFALSE(pSkipCleanupLabel);
882 m_slIL.EmitLoadRCWThis(pcsCleanup, m_dwStubFlags);
883 pcsCleanup->EmitCALL(METHOD__STUBHELPERS__STUB_UNREGISTER_RCW, 1, 0);
885 pcsCleanup->EmitLabel(pSkipCleanupLabel);
888 #endif // MDA_SUPPORTED
890 #endif // FEATURE_COMINTEROP
893 // The profiler helpers below must be called immediately before and after the call to the target.
894 // The debugger trace call helpers are invoked from StubRareDisableWorker
897 #if defined(PROFILING_SUPPORTED)
898 DWORD dwMethodDescLocalNum = -1;
900 // Notify the profiler of call out of the runtime
901 if (!SF_IsReverseCOMStub(m_dwStubFlags) && (CORProfilerTrackTransitions() || SF_IsNGENedStubForProfiling(m_dwStubFlags)))
903 dwMethodDescLocalNum = m_slIL.EmitProfilerBeginTransitionCallback(pcsDispatch, m_dwStubFlags);
904 _ASSERTE(dwMethodDescLocalNum != -1);
906 #endif // PROFILING_SUPPORTED
909 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
910 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
912 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
914 #endif // MDA_SUPPORTED
916 #ifdef FEATURE_CORECLR
917 // For CoreClr, clear the last error before calling the target that returns last error.
918 // There isn't always a way to know the function have failed without checking last error,
919 // in particular on Unix.
920 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
922 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CLEAR_LAST_ERROR, 0, 0);
924 #endif // FEATURE_CORECLR
926 // Invoke the target (calli, call method, call delegate, get/set field, etc.)
927 EmitInvokeTarget(pStubMD);
929 // Saving last error must be the first thing we do after returning from the target
930 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
932 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__SET_LAST_ERROR, 0, 0);
935 #if defined(_TARGET_X86_)
936 if (SF_IsForwardDelegateStub(m_dwStubFlags))
938 // the delegate may have an intercept stub attached to its sync block so we should
939 // prevent it from being garbage collected when the call is in progress
940 pcsDispatch->EmitLoadThis();
941 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
943 #endif // defined(_TARGET_X86_)
946 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
947 MDA_GET_ASSISTANT(GcUnmanagedToManaged))
949 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
951 #endif // MDA_SUPPORTED
954 if (SF_IsForwardStub(m_dwStubFlags) && g_pConfig->InteropValidatePinnedObjects())
956 // call StubHelpers.ValidateObject/StubHelpers.ValidateByref on pinned locals
957 m_slIL.EmitObjectValidation(pcsDispatch, m_dwStubFlags);
959 #endif // VERIFY_HEAP
961 #if defined(PROFILING_SUPPORTED)
962 // Notify the profiler of return back into the runtime
963 if (dwMethodDescLocalNum != -1)
965 m_slIL.EmitProfilerEndTransitionCallback(pcsDispatch, m_dwStubFlags, dwMethodDescLocalNum);
967 #endif // PROFILING_SUPPORTED
969 #ifdef FEATURE_COMINTEROP
970 if (SF_IsForwardCOMStub(m_dwStubFlags))
972 // Make sure that the RCW stays alive for the duration of the call. Note that if we do HRESULT
973 // swapping, we'll pass 'this' to GetCOMHRExceptionObject after returning from the target so
974 // GC.KeepAlive is not necessary.
975 if (!SF_IsHRESULTSwapping(m_dwStubFlags))
977 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
978 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
981 #endif // FEATURE_COMINTEROP
983 if (SF_IsHRESULTSwapping(m_dwStubFlags))
985 if (SF_IsForwardStub(m_dwStubFlags))
987 ILCodeLabel* pSkipThrowLabel = pcsDispatch->NewCodeLabel();
989 pcsDispatch->EmitDUP();
990 pcsDispatch->EmitLDC(0);
991 pcsDispatch->EmitBGE(pSkipThrowLabel);
993 #ifdef FEATURE_COMINTEROP
994 if (SF_IsCOMStub(m_dwStubFlags))
996 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
997 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
999 if (SF_IsWinRTStub(m_dwStubFlags))
1001 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT_WINRT, 3, 1);
1005 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT, 3, 1);
1009 #endif // FEATURE_COMINTEROP
1011 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_HR_EXCEPTION_OBJECT, 1, 1);
1014 pcsDispatch->EmitTHROW();
1015 pcsDispatch->EmitLDC(0); // keep the IL stack balanced across the branch and the fall-through
1016 pcsDispatch->EmitLabel(pSkipThrowLabel);
1017 pcsDispatch->EmitPOP();
1021 m_slIL.End(m_dwStubFlags);
1022 if (!hasTryCatchForHRESULT) // we will 'leave' the try scope and then 'ret' from outside
1024 pcsUnmarshal->EmitRET();
1027 CORJIT_FLAGS jitFlags(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB);
1029 if (m_slIL.HasInteropParamExceptionInfo())
1031 // This code will not use the secret parameter, so we do not
1032 // tell the JIT to bother with it.
1034 m_slIL.GenerateInteropParamException(pcsMarshal);
1036 else if (SF_IsFieldGetterStub(m_dwStubFlags) || SF_IsFieldSetterStub(m_dwStubFlags))
1038 // Field access stubs are not shared and do not use the secret parameter.
1041 else if (SF_IsForwardDelegateStub(m_dwStubFlags) ||
1042 (SF_IsForwardCOMStub(m_dwStubFlags) && SF_IsWinRTDelegateStub(m_dwStubFlags)))
1044 // Forward delegate stubs get all the context they need in 'this' so they
1045 // don't use the secret parameter. Except for AMD64 where we use the secret
1046 // argument to pass the real target to the stub-for-host.
1051 // All other IL stubs will need to use the secret parameter.
1052 jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PUBLISH_SECRET_PARAM);
1055 if (SF_IsReverseStub(m_dwStubFlags))
1057 SwapStubSignatures(pStubMD);
1060 ILCodeLabel* pTryEndAndCatchBeginLabel = NULL; // try ends at the same place the catch begins
1061 ILCodeLabel* pCatchEndAndReturnLabel = NULL; // catch ends at the same place we resume afterwards
1062 #ifdef FEATURE_COMINTEROP
1063 if (hasTryCatchForHRESULT)
1065 EmitExceptionHandler(&nativeReturnType, &managedReturnType, &pTryEndAndCatchBeginLabel, &pCatchEndAndReturnLabel);
1067 #endif // FEATURE_COMINTEROP
1075 cbCode = m_slIL.Link(&maxStack);
1076 cbSig = m_slIL.GetLocalSigSize();
1078 ILStubResolver * pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
1079 COR_ILMETHOD_DECODER * pILHeader = pResolver->AllocGeneratedIL(cbCode, cbSig, maxStack);
1080 pbBuffer = (BYTE *)pILHeader->Code;
1081 pbLocalSig = (BYTE *)pILHeader->LocalVarSig;
1082 _ASSERTE(cbSig == pILHeader->cbLocalVarSig);
1084 ILStubEHClause cleanupTryFinally = { 0 };
1085 ILStubEHClause convertToHRTryCatch = { 0 };
1086 m_slIL.GetCleanupFinallyOffsets(&cleanupTryFinally);
1088 #ifdef FEATURE_COMINTEROP
1089 if (hasTryCatchForHRESULT)
1091 convertToHRTryCatch.kind = ILStubEHClause::kTypedCatch;
1092 convertToHRTryCatch.dwTryBeginOffset = 0;
1093 convertToHRTryCatch.dwHandlerBeginOffset = ((DWORD)pTryEndAndCatchBeginLabel->GetCodeOffset());
1094 convertToHRTryCatch.cbTryLength = convertToHRTryCatch.dwHandlerBeginOffset - convertToHRTryCatch.dwTryBeginOffset;
1095 convertToHRTryCatch.cbHandlerLength = ((DWORD)pCatchEndAndReturnLabel->GetCodeOffset()) - convertToHRTryCatch.dwHandlerBeginOffset;
1096 convertToHRTryCatch.dwTypeToken = pcsDispatch->GetToken(g_pObjectClass);
1098 #endif // FEATURE_COMINTEROP
1102 if (convertToHRTryCatch.cbHandlerLength != 0)
1105 if (cleanupTryFinally.cbHandlerLength != 0)
1110 COR_ILMETHOD_SECT_EH* pEHSect = pResolver->AllocEHSect(nEHClauses);
1111 PopulateEHSect(pEHSect, nEHClauses, &cleanupTryFinally, &convertToHRTryCatch);
1114 m_slIL.GenerateCode(pbBuffer, cbCode);
1115 m_slIL.GetLocalSig(pbLocalSig, cbSig);
1117 pResolver->SetJitFlags(jitFlags);
1120 LOG((LF_STUBS, LL_INFO1000, "---------------------------------------------------------------------\n"));
1121 LOG((LF_STUBS, LL_INFO1000, "NDirect IL stub dump: %s::%s\n", pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
1122 if (LoggingEnabled() && LoggingOn(LF_STUBS, LL_INFO1000))
1124 CQuickBytes qbManaged;
1125 CQuickBytes qbLocal;
1127 PCCOR_SIGNATURE pManagedSig;
1130 IMDInternalImport* pIMDI = MscorlibBinder::GetModule()->GetMDImport();
1132 pStubMD->GetSig(&pManagedSig, &cManagedSig);
1134 PrettyPrintSig(pManagedSig, cManagedSig, "*", &qbManaged, pStubMD->GetMDImport(), NULL);
1135 PrettyPrintSig(pbLocalSig, cbSig, NULL, &qbLocal, pIMDI, NULL);
1137 LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, qbManaged.Ptr()));
1138 LOG((LF_STUBS, LL_INFO1000, "locals sig: %p: %s\n", pbLocalSig+1, qbLocal.Ptr()));
1140 if (cleanupTryFinally.cbHandlerLength != 0)
1142 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x finally_begin: 0x%04x finally_end: 0x%04x \n",
1143 cleanupTryFinally.dwTryBeginOffset, cleanupTryFinally.dwTryBeginOffset + cleanupTryFinally.cbTryLength,
1144 cleanupTryFinally.dwHandlerBeginOffset, cleanupTryFinally.dwHandlerBeginOffset + cleanupTryFinally.cbHandlerLength));
1146 if (convertToHRTryCatch.cbHandlerLength != 0)
1148 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x catch_begin: 0x%04x catch_end: 0x%04x type_token: 0x%08x\n",
1149 convertToHRTryCatch.dwTryBeginOffset, convertToHRTryCatch.dwTryBeginOffset + convertToHRTryCatch.cbTryLength,
1150 convertToHRTryCatch.dwHandlerBeginOffset, convertToHRTryCatch.dwHandlerBeginOffset + convertToHRTryCatch.cbHandlerLength,
1151 convertToHRTryCatch.dwTypeToken));
1154 LogILStubFlags(LF_STUBS, LL_INFO1000, m_dwStubFlags);
1156 m_slIL.LogILStub(jitFlags);
1158 LOG((LF_STUBS, LL_INFO1000, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
1161 #ifndef FEATURE_CORECLR
1163 // Publish ETW events for IL stubs
1166 // If the category and the event is enabled...
1167 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ILStubGenerated))
1169 EtwOnILStubGenerated(
1174 &convertToHRTryCatch,
1180 #endif // !FEATURE_CORECLR
1183 #ifndef FEATURE_CORECLR
1184 //---------------------------------------------------------------------------------------
1187 EtwOnILStubGenerated(
1188 MethodDesc * pStubMD,
1189 PCCOR_SIGNATURE pbLocalSig,
1191 CORJIT_FLAGS jitFlags,
1192 ILStubEHClause * pConvertToHRTryCatchBounds,
1193 ILStubEHClause * pCleanupTryFinallyBounds,
1197 STANDARD_VM_CONTRACT;
1200 // Interop Method Information
1202 MethodDesc *pTargetMD = m_slIL.GetTargetMD();
1203 SString strNamespaceOrClassName, strMethodName, strMethodSignature;
1204 UINT64 uModuleId = 0;
1208 pTargetMD->GetMethodInfoWithNewSig(strNamespaceOrClassName, strMethodName, strMethodSignature);
1209 uModuleId = (UINT64)pTargetMD->GetModule()->GetAddrModuleID();
1213 // Stub Method Signature
1215 SString stubNamespaceOrClassName, stubMethodName, stubMethodSignature;
1216 pStubMD->GetMethodInfoWithNewSig(stubNamespaceOrClassName, stubMethodName, stubMethodSignature);
1218 IMDInternalImport *pStubImport = pStubMD->GetModule()->GetMDImport();
1220 CQuickBytes qbLocal;
1221 PrettyPrintSig(pbLocalSig, (DWORD)cbSig, NULL, &qbLocal, pStubImport, NULL);
1223 SString strLocalSig(SString::Utf8, (LPCUTF8)qbLocal.Ptr());
1228 SString strNativeSignature(SString::Utf8);
1229 if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
1231 // Reverse interop. Use StubSignature
1232 strNativeSignature = stubMethodSignature;
1236 // Forward interop. Use StubTarget siganture
1237 PCCOR_SIGNATURE pCallTargetSig = GetStubTargetMethodSig();
1238 DWORD cCallTargetSig = GetStubTargetMethodSigLength();
1240 CQuickBytes qbCallTargetSig;
1242 PrettyPrintSig(pCallTargetSig, cCallTargetSig, "", &qbCallTargetSig, pStubImport, NULL);
1244 strNativeSignature.SetUTF8((LPCUTF8)qbCallTargetSig.Ptr());
1248 // Dump IL stub code
1250 SString strILStubCode;
1251 strILStubCode.Preallocate(4096); // Preallocate 4K bytes to avoid unnecessary growth
1253 SString codeSizeFormat;
1254 codeSizeFormat.LoadResource(CCompRC::Optional, IDS_EE_INTEROP_CODE_SIZE_COMMENT);
1255 strILStubCode.AppendPrintf(W("// %s\t%d (0x%04x)\n"), codeSizeFormat.GetUnicode(), cbCode, cbCode);
1256 strILStubCode.AppendPrintf(W(".maxstack %d \n"), maxStack);
1257 strILStubCode.AppendPrintf(W(".locals %s\n"), strLocalSig.GetUnicode());
1259 m_slIL.LogILStub(jitFlags, &strILStubCode);
1261 if (pConvertToHRTryCatchBounds->cbTryLength != 0 && pConvertToHRTryCatchBounds->cbHandlerLength != 0)
1263 strILStubCode.AppendPrintf(
1264 W(".try IL_%04x to IL_%04x catch handler IL_%04x to IL_%04x\n"),
1265 pConvertToHRTryCatchBounds->dwTryBeginOffset,
1266 pConvertToHRTryCatchBounds->dwTryBeginOffset + pConvertToHRTryCatchBounds->cbTryLength,
1267 pConvertToHRTryCatchBounds->dwHandlerBeginOffset,
1268 pConvertToHRTryCatchBounds->dwHandlerBeginOffset + pConvertToHRTryCatchBounds->cbHandlerLength);
1271 if (pCleanupTryFinallyBounds->cbTryLength != 0 && pCleanupTryFinallyBounds->cbHandlerLength != 0)
1273 strILStubCode.AppendPrintf(
1274 W(".try IL_%04x to IL_%04x finally handler IL_%04x to IL_%04x\n"),
1275 pCleanupTryFinallyBounds->dwTryBeginOffset,
1276 pCleanupTryFinallyBounds->dwTryBeginOffset + pCleanupTryFinallyBounds->cbTryLength,
1277 pCleanupTryFinallyBounds->dwHandlerBeginOffset,
1278 pCleanupTryFinallyBounds->dwHandlerBeginOffset + pCleanupTryFinallyBounds->cbHandlerLength);
1285 if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
1286 dwFlags |= ETW_IL_STUB_FLAGS_REVERSE_INTEROP;
1287 #ifdef FEATURE_COMINTEROP
1288 if (m_dwStubFlags & NDIRECTSTUB_FL_COM)
1289 dwFlags |= ETW_IL_STUB_FLAGS_COM_INTEROP;
1290 #endif // FEATURE_COMINTEROP
1291 if (m_dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)
1292 dwFlags |= ETW_IL_STUB_FLAGS_NGENED_STUB;
1293 if (m_dwStubFlags & NDIRECTSTUB_FL_DELEGATE)
1294 dwFlags |= ETW_IL_STUB_FLAGS_DELEGATE;
1295 if (m_dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)
1296 dwFlags |= ETW_IL_STUB_FLAGS_VARARG;
1297 if (m_dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)
1298 dwFlags |= ETW_IL_STUB_FLAGS_UNMANAGED_CALLI;
1302 dwToken = pTargetMD->GetMemberDef();
1306 // Truncate string fields. Make sure the whole event is less than 64KB
1308 TruncateUnicodeString(strNamespaceOrClassName, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1309 TruncateUnicodeString(strMethodName, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1310 TruncateUnicodeString(strMethodSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1311 TruncateUnicodeString(strNativeSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1312 TruncateUnicodeString(stubMethodSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1313 TruncateUnicodeString(strILStubCode, ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE);
1318 FireEtwILStubGenerated(
1319 GetClrInstanceId(), // ClrInstanceId
1320 uModuleId, // ModuleIdentifier
1321 (UINT64)pStubMD, // StubMethodIdentifier
1322 dwFlags, // StubFlags
1323 dwToken, // ManagedInteropMethodToken
1324 strNamespaceOrClassName.GetUnicode(), // ManagedInteropMethodNamespace
1325 strMethodName.GetUnicode(), // ManagedInteropMethodName
1326 strMethodSignature.GetUnicode(), // ManagedInteropMethodSignature
1327 strNativeSignature.GetUnicode(), // NativeSignature
1328 stubMethodSignature.GetUnicode(), // StubMethodSigature
1329 strILStubCode.GetUnicode() // StubMethodILCode
1331 } // EtwOnILStubGenerated
1332 #endif // !FEATURE_CORECLR
1335 //---------------------------------------------------------------------------------------
1337 static inline void LogOneFlag(DWORD flags, DWORD flag, LPCSTR str, DWORD facility, DWORD level)
1339 LIMITED_METHOD_CONTRACT;
1342 LOG((facility, level, str));
1346 static void LogILStubFlags(DWORD facility, DWORD level, DWORD dwStubFlags)
1348 LIMITED_METHOD_CONTRACT;
1349 LOG((facility, level, "dwStubFlags: 0x%08x\n", dwStubFlags));
1350 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_CONVSIGASVARARG, " NDIRECTSTUB_FL_CONVSIGASVARARG\n", facility, level);
1351 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_BESTFIT, " NDIRECTSTUB_FL_BESTFIT\n", facility, level);
1352 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR, " NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR\n", facility, level);
1353 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUB, " NDIRECTSTUB_FL_NGENEDSTUB\n", facility, level);
1354 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DELEGATE, " NDIRECTSTUB_FL_DELEGATE\n", facility, level);
1355 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DOHRESULTSWAPPING, " NDIRECTSTUB_FL_DOHRESULTSWAPPING\n", facility, level);
1356 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_REVERSE_INTEROP, " NDIRECTSTUB_FL_REVERSE_INTEROP\n", facility, level);
1357 #ifdef FEATURE_COMINTEROP
1358 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_COM, " NDIRECTSTUB_FL_COM\n", facility, level);
1359 #endif // FEATURE_COMINTEROP
1360 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING, " NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING\n", facility, level);
1361 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL, " NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL\n", facility, level);
1362 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_HASDECLARATIVESECURITY, " NDIRECTSTUB_FL_HASDECLARATIVESECURITY\n", facility, level);
1363 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_UNMANAGED_CALLI, " NDIRECTSTUB_FL_UNMANAGED_CALLI\n", facility, level);
1364 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_TRIGGERCCTOR, " NDIRECTSTUB_FL_TRIGGERCCTOR\n", facility, level);
1365 #ifdef FEATURE_COMINTEROP
1366 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDGETTER, " NDIRECTSTUB_FL_FIELDGETTER\n", facility, level);
1367 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDSETTER, " NDIRECTSTUB_FL_FIELDSETTER\n", facility, level);
1368 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRT, " NDIRECTSTUB_FL_WINRT\n", facility, level);
1369 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTDELEGATE, " NDIRECTSTUB_FL_WINRTDELEGATE\n", facility, level);
1370 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSHAREDGENERIC, " NDIRECTSTUB_FL_WINRTSHAREDGENERIC\n", facility, level);
1371 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCTOR, " NDIRECTSTUB_FL_WINRTCTOR\n", facility, level);
1372 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCOMPOSITION, " NDIRECTSTUB_FL_WINRTCOMPOSITION\n", facility, level);
1373 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSTATIC, " NDIRECTSTUB_FL_WINRTSTATIC\n", facility, level);
1374 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTHASREDIRECTION, " NDIRECTSTUB_FL_WINRTHASREDIRECTION\n", facility, level);
1375 #endif // FEATURE_COMINTEROP
1378 // no need to log the internal flags, let's just assert what we expect to see...
1380 CONSISTENCY_CHECK(!SF_IsCOMLateBoundStub(dwStubFlags));
1381 CONSISTENCY_CHECK(!SF_IsCOMEventCallStub(dwStubFlags));
1384 NDIRECTSTUB_FL_CONVSIGASVARARG |
1385 NDIRECTSTUB_FL_BESTFIT |
1386 NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR |
1387 NDIRECTSTUB_FL_NGENEDSTUB |
1388 NDIRECTSTUB_FL_DELEGATE |
1389 NDIRECTSTUB_FL_DOHRESULTSWAPPING |
1390 NDIRECTSTUB_FL_REVERSE_INTEROP |
1391 NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING |
1392 NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL |
1393 NDIRECTSTUB_FL_HASDECLARATIVESECURITY |
1394 NDIRECTSTUB_FL_UNMANAGED_CALLI |
1395 NDIRECTSTUB_FL_TRIGGERCCTOR |
1396 #ifdef FEATURE_COMINTEROP
1397 NDIRECTSTUB_FL_COM |
1398 NDIRECTSTUB_FL_COMLATEBOUND | // internal
1399 NDIRECTSTUB_FL_COMEVENTCALL | // internal
1400 NDIRECTSTUB_FL_FIELDGETTER |
1401 NDIRECTSTUB_FL_FIELDSETTER |
1402 NDIRECTSTUB_FL_WINRT |
1403 NDIRECTSTUB_FL_WINRTDELEGATE |
1404 NDIRECTSTUB_FL_WINRTCTOR |
1405 NDIRECTSTUB_FL_WINRTCOMPOSITION |
1406 NDIRECTSTUB_FL_WINRTSTATIC |
1407 NDIRECTSTUB_FL_WINRTHASREDIRECTION |
1408 #endif // FEATURE_COMINTEROP
1411 DWORD dwUnknownFlags = dwStubFlags & ~dwKnownMask;
1412 if (0 != dwUnknownFlags)
1414 LOG((facility, level, "UNKNOWN FLAGS: 0x%08x\n", dwUnknownFlags));
1419 PCCOR_SIGNATURE GetStubTargetMethodSig()
1421 CONTRACT(PCCOR_SIGNATURE)
1424 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
1430 if (!m_qbNativeFnSigBuffer.Size())
1432 DWORD cb = m_slIL.GetStubTargetMethodSigSize();
1433 pb = (BYTE *)m_qbNativeFnSigBuffer.AllocThrows(cb);
1435 m_slIL.GetStubTargetMethodSig(pb, cb);
1439 pb = (BYTE*)m_qbNativeFnSigBuffer.Ptr();
1446 GetStubTargetMethodSigLength()
1448 WRAPPER_NO_CONTRACT;
1450 return m_slIL.GetStubTargetMethodSigSize();
1453 void SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1455 WRAPPER_NO_CONTRACT;
1457 m_slIL.SetStubTargetMethodSig(pSig, cSig);
1458 m_qbNativeFnSigBuffer.Shrink(0);
1461 TokenLookupMap* GetTokenLookupMap() { WRAPPER_NO_CONTRACT; return m_slIL.GetTokenLookupMap(); }
1464 CQuickBytes m_qbNativeFnSigBuffer;
1465 NDirectStubLinker m_slIL;
1466 BOOL m_fSetLastError;
1467 DWORD m_dwStubFlags;
1471 class PInvoke_ILStubState : public ILStubState
1475 PInvoke_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1476 CorPinvokeMap unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
1481 TargetHasThis(dwStubFlags),
1482 StubHasThis(dwStubFlags),
1487 STANDARD_VM_CONTRACT;
1489 if (SF_IsForwardStub(dwStubFlags))
1491 m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
1496 static BOOL TargetHasThis(DWORD dwStubFlags)
1499 // in reverse pinvoke on delegate, the managed target will
1500 // have a 'this' pointer, but the unmanaged signature does
1503 return SF_IsReverseDelegateStub(dwStubFlags);
1506 static BOOL StubHasThis(DWORD dwStubFlags)
1509 // in forward pinvoke on a delegate, the stub will have a
1510 // 'this' pointer, but the unmanaged target will not.
1512 return SF_IsForwardDelegateStub(dwStubFlags);
1516 #ifdef FEATURE_COMINTEROP
1517 class CLRToCOM_ILStubState : public ILStubState
1521 CLRToCOM_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1522 int iLCIDParamIdx, MethodDesc* pTargetMD)
1528 !SF_IsWinRTStaticStub(dwStubFlags), // fStubHasThis
1533 STANDARD_VM_CONTRACT;
1535 if (SF_IsForwardStub(dwStubFlags))
1537 m_slIL.SetCallingConvention(pmCallConvStdcall, SF_IsVarArgStub(dwStubFlags));
1541 void BeginEmit(DWORD dwStubFlags) // CLR to COM IL
1543 STANDARD_VM_CONTRACT;
1545 ILStubState::BeginEmit(dwStubFlags);
1547 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1549 // add the 'this' COM IP parameter to the target CALLI
1550 m_slIL.GetMarshalCodeStream()->SetStubTargetArgType(ELEMENT_TYPE_I, false);
1552 // convert 'this' to COM IP and the target method entry point
1553 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
1556 if (SF_IsWinRTDelegateStub(m_dwStubFlags))
1558 // write the stub context (EEImplMethodDesc representing the Invoke)
1559 // into the secret arg so it shows up in the InlinedCallFrame and can
1560 // be used by stub for host
1562 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
1563 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1564 pcsDispatch->EmitSTIND_I();
1565 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1570 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1573 pcsDispatch->EmitLDLOCA(m_slIL.GetTargetEntryPointLocalNum());
1575 BinderMethodID getCOMIPMethod;
1576 bool fDoPostCallIPCleanup = true;
1578 if (!SF_IsNGENedStub(dwStubFlags) && NDirect::IsHostHookEnabled())
1580 // always use the non-optimized helper if we are hosted
1581 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1583 else if (SF_IsWinRTStub(dwStubFlags))
1585 // WinRT uses optimized helpers
1586 if (SF_IsWinRTSharedGenericStub(dwStubFlags))
1587 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_SHARED_GENERIC;
1588 else if (SF_IsWinRTDelegateStub(dwStubFlags))
1589 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_DELEGATE;
1591 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT;
1593 // GetCOMIPFromRCW_WinRT, GetCOMIPFromRCW_WinRTSharedGeneric, and GetCOMIPFromRCW_WinRTDelegate
1594 // always cache the COM interface pointer so no post-call cleanup is needed
1595 fDoPostCallIPCleanup = false;
1599 // classic COM interop uses the non-optimized helper
1600 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1603 DWORD dwIPRequiresCleanupLocalNum = (DWORD)-1;
1604 if (fDoPostCallIPCleanup)
1606 dwIPRequiresCleanupLocalNum = pcsDispatch->NewLocal(ELEMENT_TYPE_BOOLEAN);
1607 pcsDispatch->EmitLDLOCA(dwIPRequiresCleanupLocalNum);
1609 // StubHelpers.GetCOMIPFromRCW(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget, out bool pfNeedsRelease)
1610 pcsDispatch->EmitCALL(getCOMIPMethod, 4, 1);
1614 // StubHelpers.GetCOMIPFromRCW_WinRT*(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget)
1615 pcsDispatch->EmitCALL(getCOMIPMethod, 3, 1);
1619 // save it because we'll need it to compute the CALLI target and release it
1620 pcsDispatch->EmitDUP();
1621 pcsDispatch->EmitSTLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1623 if (fDoPostCallIPCleanup)
1625 // make sure it's Release()'ed after the call
1626 m_slIL.SetCleanupNeeded();
1627 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
1629 ILCodeLabel *pSkipThisCleanup = pcsCleanup->NewCodeLabel();
1631 // and if it requires cleanup (i.e. it's not taken from the RCW cache)
1632 pcsCleanup->EmitLDLOC(dwIPRequiresCleanupLocalNum);
1633 pcsCleanup->EmitBRFALSE(pSkipThisCleanup);
1635 pcsCleanup->EmitLDLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1636 pcsCleanup->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
1637 pcsCleanup->EmitLabel(pSkipThisCleanup);
1642 class COMToCLR_ILStubState : public ILStubState
1646 COMToCLR_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1647 int iLCIDParamIdx, MethodDesc* pTargetMD)
1658 STANDARD_VM_CONTRACT;
1661 void BeginEmit(DWORD dwStubFlags) // COM to CLR IL
1663 STANDARD_VM_CONTRACT;
1665 ILStubState::BeginEmit(dwStubFlags);
1667 if (SF_IsWinRTStaticStub(dwStubFlags))
1669 // we are not loading 'this' because the target is static
1670 m_slIL.AdjustTargetStackDeltaForExtraParam();
1675 m_slIL.GetDispatchCodeStream()->EmitLoadThis();
1679 void MarshalFactoryReturn()
1684 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
1688 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
1689 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1690 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
1691 ILCodeStream *pcsExCleanup = m_slIL.GetExceptionCleanupCodeStream();
1693 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
1694 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
1695 pcsSetup->EmitLoadNullPtr();
1696 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
1698 locDescFactoryRetVal.MakeByRef();
1700 // expect one additional argument - pointer to a location that receives the created instance
1701 DWORD dwRetValArgNum = pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
1702 m_slIL.AdjustTargetStackDeltaForExtraParam();
1704 // convert 'this' to an interface pointer corresponding to the default interface of this class
1705 pcsUnmarshal->EmitLoadThis();
1706 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1707 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_RETURN_VALUE, 2, 1);
1708 pcsUnmarshal->EmitSTLOC(dwFactoryRetValLocalNum);
1710 // assign it to the location pointed to by the argument
1711 pcsUnmarshal->EmitLDARG(dwRetValArgNum);
1712 pcsUnmarshal->EmitLDLOC(dwFactoryRetValLocalNum);
1713 pcsUnmarshal->EmitSTIND_I();
1715 // on exception, we want to release the IInspectable's and assign NULL to output locations
1716 m_slIL.SetExceptionCleanupNeeded();
1718 EmitInterfaceClearNative(pcsExCleanup, dwFactoryRetValLocalNum);
1721 pcsExCleanup->EmitLDARG(dwRetValArgNum);
1722 pcsExCleanup->EmitLoadNullPtr();
1723 pcsExCleanup->EmitSTIND_I();
1728 class COMToCLRFieldAccess_ILStubState : public COMToCLR_ILStubState
1732 COMToCLRFieldAccess_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext,
1733 DWORD dwStubFlags, FieldDesc* pFD)
1734 : COMToCLR_ILStubState(
1742 STANDARD_VM_CONTRACT;
1744 _ASSERTE(pFD != NULL);
1748 void EmitInvokeTarget(MethodDesc *pStubMD)
1750 STANDARD_VM_CONTRACT;
1752 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
1754 if (SF_IsFieldGetterStub(m_dwStubFlags))
1756 pcsDispatch->EmitLDFLD(pcsDispatch->GetToken(m_pFD));
1760 CONSISTENCY_CHECK(SF_IsFieldSetterStub(m_dwStubFlags));
1761 pcsDispatch->EmitSTFLD(pcsDispatch->GetToken(m_pFD));
1768 #endif // FEATURE_COMINTEROP
1771 NDirectStubLinker::NDirectStubLinker(
1774 const Signature &signature,
1775 SigTypeContext *pTypeContext,
1776 MethodDesc* pTargetMD,
1778 BOOL fTargetHasThis,
1780 : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, fTargetHasThis, fStubHasThis, !SF_IsCOMStub(dwStubFlags)),
1781 m_pCleanupFinallyBeginLabel(NULL),
1782 m_pCleanupFinallyEndLabel(NULL),
1783 m_pSkipExceptionCleanupLabel(NULL),
1784 #ifdef FEATURE_COMINTEROP
1785 m_dwWinRTFactoryObjectLocalNum(-1),
1786 #endif // FEATURE_COMINTEROP
1787 m_fHasCleanupCode(FALSE),
1788 m_fHasExceptionCleanupCode(FALSE),
1789 m_fCleanupWorkListIsSetup(FALSE),
1790 m_dwThreadLocalNum(-1),
1791 m_dwCleanupWorkListLocalNum(-1),
1792 m_dwRetValLocalNum(-1),
1793 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
1794 m_dwFirstCopyCtorCookieLocalNum(-1),
1795 m_dwLastCopyCtorCookieLocalNum(-1),
1796 #endif // _TARGET_X86_ && !FEATURE_CORECLR
1798 m_ErrorParamIdx(-1),
1799 m_iLCIDParamIdx(iLCIDParamIdx),
1800 m_dwStubFlags(dwStubFlags)
1802 STANDARD_VM_CONTRACT;
1805 m_pcsSetup = NewCodeStream(ILStubLinker::kSetup); // do any one-time setup work
1806 m_pcsMarshal = NewCodeStream(ILStubLinker::kMarshal); // marshals arguments
1807 m_pcsDispatch = NewCodeStream(ILStubLinker::kDispatch); // sets up arguments and makes call
1808 m_pcsRetUnmarshal = NewCodeStream(ILStubLinker::kReturnUnmarshal); // unmarshals return value
1809 m_pcsUnmarshal = NewCodeStream(ILStubLinker::kUnmarshal); // unmarshals arguments
1810 m_pcsExceptionCleanup = NewCodeStream(ILStubLinker::kExceptionCleanup); // MAY NOT THROW: goes in a finally and does exception-only cleanup
1811 m_pcsCleanup = NewCodeStream(ILStubLinker::kCleanup); // MAY NOT THROW: goes in a finally and does unconditional cleanup
1815 m_dwArgMarshalIndexLocalNum = NewLocal(ELEMENT_TYPE_I4);
1816 m_pcsMarshal->EmitLDC(0);
1817 m_pcsMarshal->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1819 #ifdef FEATURE_COMINTEROP
1821 // Forward COM interop needs a local to hold target interface pointer
1823 if (SF_IsForwardCOMStub(m_dwStubFlags))
1825 m_dwTargetEntryPointLocalNum = NewLocal(ELEMENT_TYPE_I);
1826 m_dwTargetInterfacePointerLocalNum = NewLocal(ELEMENT_TYPE_I);
1827 m_pcsSetup->EmitLoadNullPtr();
1828 m_pcsSetup->EmitSTLOC(m_dwTargetInterfacePointerLocalNum);
1830 #endif // FEATURE_COMINTEROP
1833 void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg)
1835 LIMITED_METHOD_CONTRACT;
1836 ULONG uNativeCallingConv = 0;
1838 #if !defined(_TARGET_X86_)
1841 // The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM:
1842 // any float values must be duplicated in the corresponding general-purpose registers.
1843 uNativeCallingConv = CORINFO_CALLCONV_NATIVEVARARG;
1846 #endif // !_TARGET_X86_
1848 switch (unmngCallConv)
1850 case pmCallConvCdecl:
1851 uNativeCallingConv = CORINFO_CALLCONV_C;
1853 case pmCallConvStdcall:
1854 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1856 case pmCallConvThiscall:
1857 uNativeCallingConv = CORINFO_CALLCONV_THISCALL;
1860 _ASSERTE(!"Invalid calling convention.");
1861 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1866 SetStubTargetCallingConv((CorCallingConvention)uNativeCallingConv);
1869 void NDirectStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx)
1871 WRAPPER_NO_CONTRACT;
1874 // This sets our state local variable that tracks the progress of the stub execution.
1875 // In the finally block we test this variable to see what cleanup we need to do. The
1876 // variable starts with the value of 0 and is assigned the following values as the
1879 // CLEANUP_INDEX_ARG0_MARSHAL + 1 - 1st argument marshaled
1880 // CLEANUP_INDEX_ARG0_MARSHAL + 2 - 2nd argument marshaled
1882 // CLEANUP_INDEX_ARG0_MARSHAL + n - nth argument marshaled
1883 // CLEANUP_INDEX_RETVAL_UNMARSHAL + 1 - return value unmarshaled
1884 // CLEANUP_INDEX_ARG0_UNMARSHAL + 1 - 1st argument unmarshaled
1885 // CLEANUP_INDEX_ARG0_UNMARSHAL + 2 - 2nd argument unmarshaled
1887 // CLEANUP_INDEX_ARG0_UNMARSHAL + n - nth argument unmarshaled
1888 // CLEANUP_INDEX_ALL_DONE + 1 - ran to completion, no exception thrown
1890 // Note: There may be gaps, i.e. if say 2nd argument does not need cleanup, the
1891 // state variable will never be assigned the corresponding value. However, the
1892 // value must always monotonically increase so we can use <=, >, etc.
1895 pcsEmit->EmitLDC(uArgIdx + 1);
1896 pcsEmit->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1899 void NDirectStubLinker::EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel)
1901 STANDARD_VM_CONTRACT;
1905 // See EmitSetArgMarshalIndex.
1906 pcsEmit->EmitLDLOC(m_dwArgMarshalIndexLocalNum);
1907 pcsEmit->EmitLDC(uArgIdx);
1911 case BranchIfMarshaled:
1913 // we branch to the label if the argument has been marshaled
1914 pcsEmit->EmitBGT(pSkipCleanupLabel);
1918 case BranchIfNotMarshaled:
1920 // we branch to the label if the argument has not been marshaled
1921 pcsEmit->EmitBLE(pSkipCleanupLabel);
1930 int NDirectStubLinker::GetLCIDParamIdx()
1932 LIMITED_METHOD_CONTRACT;
1933 return m_iLCIDParamIdx;
1936 ILCodeStream* NDirectStubLinker::GetSetupCodeStream()
1938 LIMITED_METHOD_CONTRACT;
1942 ILCodeStream* NDirectStubLinker::GetMarshalCodeStream()
1944 LIMITED_METHOD_CONTRACT;
1945 return m_pcsMarshal;
1948 ILCodeStream* NDirectStubLinker::GetUnmarshalCodeStream()
1950 LIMITED_METHOD_CONTRACT;
1951 return m_pcsUnmarshal;
1954 ILCodeStream* NDirectStubLinker::GetReturnUnmarshalCodeStream()
1956 LIMITED_METHOD_CONTRACT;
1957 return m_pcsRetUnmarshal;
1960 ILCodeStream* NDirectStubLinker::GetDispatchCodeStream()
1962 LIMITED_METHOD_CONTRACT;
1963 return m_pcsDispatch;
1966 ILCodeStream* NDirectStubLinker::GetCleanupCodeStream()
1968 LIMITED_METHOD_CONTRACT;
1969 return m_pcsCleanup;
1972 ILCodeStream* NDirectStubLinker::GetExceptionCleanupCodeStream()
1974 LIMITED_METHOD_CONTRACT;
1975 return m_pcsExceptionCleanup;
1978 void NDirectStubLinker::AdjustTargetStackDeltaForExtraParam()
1980 LIMITED_METHOD_CONTRACT;
1982 // Compensate for the extra parameter.
1984 m_iTargetStackDelta++;
1987 void NDirectStubLinker::AdjustTargetStackDeltaForReverseInteropHRESULTSwapping()
1989 WRAPPER_NO_CONTRACT;
1991 // In the case of reverse pinvoke, we build up the 'target'
1992 // signature as if it were normal forward pinvoke and then
1993 // switch that signature (representing the native sig) with
1994 // the stub's sig (representing the managed sig). However,
1995 // as a side-effect, our calcualted target stack delta is
1998 // The only way that we support a different stack delta is
1999 // through hresult swapping. So this code "undoes" the
2000 // deltas that would have been applied in that case.
2003 if (StubHasVoidReturnType())
2006 // If the managed return type is void, undo the HRESULT
2007 // return type added to our target sig for HRESULT swapping.
2008 // No extra argument will have been added because it makes
2009 // no sense to add an extry byref void argument.
2011 m_iTargetStackDelta--;
2016 // no longer pop the extra byref argument from the stack
2018 m_iTargetStackDelta++;
2022 void NDirectStubLinker::SetInteropParamExceptionInfo(UINT resID, UINT paramIdx)
2024 LIMITED_METHOD_CONTRACT;
2026 // only keep the first one
2027 if (HasInteropParamExceptionInfo())
2032 m_ErrorResID = resID;
2033 m_ErrorParamIdx = paramIdx;
2036 bool NDirectStubLinker::HasInteropParamExceptionInfo()
2038 LIMITED_METHOD_CONTRACT;
2040 return !(((DWORD)-1 == m_ErrorResID) && ((DWORD)-1 == m_ErrorParamIdx));
2043 void NDirectStubLinker::GenerateInteropParamException(ILCodeStream* pcsEmit)
2045 STANDARD_VM_CONTRACT;
2047 pcsEmit->EmitLDC(m_ErrorResID);
2048 pcsEmit->EmitLDC(m_ErrorParamIdx);
2049 pcsEmit->EmitCALL(METHOD__STUBHELPERS__THROW_INTEROP_PARAM_EXCEPTION, 2, 0);
2051 pcsEmit->EmitLDNULL();
2052 pcsEmit->EmitTHROW();
2055 #ifdef FEATURE_COMINTEROP
2056 DWORD NDirectStubLinker::GetTargetInterfacePointerLocalNum()
2058 LIMITED_METHOD_CONTRACT;
2059 CONSISTENCY_CHECK(m_dwTargetInterfacePointerLocalNum != (DWORD)-1);
2060 return m_dwTargetInterfacePointerLocalNum;
2062 DWORD NDirectStubLinker::GetTargetEntryPointLocalNum()
2064 LIMITED_METHOD_CONTRACT;
2065 CONSISTENCY_CHECK(m_dwTargetEntryPointLocalNum != (DWORD)-1);
2066 return m_dwTargetEntryPointLocalNum;
2069 void NDirectStubLinker::EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2071 STANDARD_VM_CONTRACT;
2073 if (SF_IsForwardStub(dwStubFlags) &&
2074 (SF_IsWinRTCtorStub(dwStubFlags) || SF_IsWinRTStaticStub(dwStubFlags)))
2076 // WinRT ctor/static stubs make the call on the factory object instead of 'this'
2077 if (m_dwWinRTFactoryObjectLocalNum == (DWORD)-1)
2079 m_dwWinRTFactoryObjectLocalNum = NewLocal(ELEMENT_TYPE_OBJECT);
2081 // get the factory object
2082 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2083 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_OBJECT, 1, 1);
2084 m_pcsSetup->EmitSTLOC(m_dwWinRTFactoryObjectLocalNum);
2087 pcsEmit->EmitLDLOC(m_dwWinRTFactoryObjectLocalNum);
2091 pcsEmit->EmitLoadThis();
2094 #endif // FEATURE_COMINTEROP
2096 DWORD NDirectStubLinker::GetCleanupWorkListLocalNum()
2098 LIMITED_METHOD_CONTRACT;
2099 CONSISTENCY_CHECK(m_dwCleanupWorkListLocalNum != (DWORD)-1);
2100 return m_dwCleanupWorkListLocalNum;
2103 DWORD NDirectStubLinker::GetThreadLocalNum()
2105 STANDARD_VM_CONTRACT;
2107 if (m_dwThreadLocalNum == (DWORD)-1)
2109 // The local is created and initialized lazily when first asked.
2110 m_dwThreadLocalNum = NewLocal(ELEMENT_TYPE_I);
2111 m_pcsSetup->EmitCALL(METHOD__THREAD__INTERNAL_GET_CURRENT_THREAD, 0, 1);
2112 m_pcsSetup->EmitSTLOC(m_dwThreadLocalNum);
2115 return m_dwThreadLocalNum;
2118 DWORD NDirectStubLinker::GetReturnValueLocalNum()
2120 LIMITED_METHOD_CONTRACT;
2121 return m_dwRetValLocalNum;
2124 BOOL NDirectStubLinker::IsCleanupNeeded()
2126 LIMITED_METHOD_CONTRACT;
2128 return (m_fHasCleanupCode || IsCleanupWorkListSetup());
2131 BOOL NDirectStubLinker::IsExceptionCleanupNeeded()
2133 LIMITED_METHOD_CONTRACT;
2135 return m_fHasExceptionCleanupCode;
2138 void NDirectStubLinker::InitCleanupCode()
2143 PRECONDITION(NULL == m_pCleanupFinallyBeginLabel);
2147 m_pCleanupFinallyBeginLabel = NewCodeLabel();
2148 m_pcsExceptionCleanup->EmitLabel(m_pCleanupFinallyBeginLabel);
2151 void NDirectStubLinker::InitExceptionCleanupCode()
2156 PRECONDITION(NULL == m_pSkipExceptionCleanupLabel);
2162 // we want to skip the entire exception cleanup if no exception has been thrown
2163 m_pSkipExceptionCleanupLabel = NewCodeLabel();
2164 EmitCheckForArgCleanup(m_pcsExceptionCleanup, CLEANUP_INDEX_ALL_DONE, BranchIfMarshaled, m_pSkipExceptionCleanupLabel);
2167 void NDirectStubLinker::SetCleanupNeeded()
2169 WRAPPER_NO_CONTRACT;
2171 if (!m_fHasCleanupCode)
2173 m_fHasCleanupCode = TRUE;
2178 void NDirectStubLinker::SetExceptionCleanupNeeded()
2180 WRAPPER_NO_CONTRACT;
2182 if (!m_fHasExceptionCleanupCode)
2184 m_fHasExceptionCleanupCode = TRUE;
2185 InitExceptionCleanupCode();
2189 void NDirectStubLinker::NeedsCleanupList()
2191 STANDARD_VM_CONTRACT;
2193 if (!IsCleanupWorkListSetup())
2195 m_fCleanupWorkListIsSetup = TRUE;
2198 // we setup a new local that will hold the cleanup work list
2199 LocalDesc desc(MscorlibBinder::GetClass(CLASS__CLEANUP_WORK_LIST));
2200 m_dwCleanupWorkListLocalNum = NewLocal(desc);
2205 BOOL NDirectStubLinker::IsCleanupWorkListSetup ()
2207 LIMITED_METHOD_CONTRACT;
2209 return m_fCleanupWorkListIsSetup;
2213 void NDirectStubLinker::LoadCleanupWorkList(ILCodeStream* pcsEmit)
2215 STANDARD_VM_CONTRACT;
2218 pcsEmit->EmitLDLOCA(GetCleanupWorkListLocalNum());
2221 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
2223 BOOL NDirectStubLinker::IsCopyCtorStubNeeded()
2225 LIMITED_METHOD_CONTRACT;
2226 return (m_dwFirstCopyCtorCookieLocalNum != (DWORD)-1);
2229 DWORD NDirectStubLinker::CreateCopyCtorCookie(ILCodeStream* pcsEmit)
2231 STANDARD_VM_CONTRACT;
2233 MethodTable *pCookieMT = MscorlibBinder::GetClass(CLASS__COPYCTORSTUBCOOKIE);
2235 LocalDesc desc(pCookieMT);
2236 DWORD dwCookieLocalNum = pcsEmit->NewLocal(desc);
2238 // <dwCookieLocalNum> = new CopyCtorStubCookie()
2239 pcsEmit->EmitLDLOCA(dwCookieLocalNum);
2240 pcsEmit->EmitINITOBJ(pcsEmit->GetToken(pCookieMT));
2242 if (m_dwLastCopyCtorCookieLocalNum == (DWORD)-1)
2244 // this is the first cookie in this stub
2245 m_dwFirstCopyCtorCookieLocalNum = dwCookieLocalNum;
2249 // this is not the first cookie - build a linked list
2250 // <m_dwLastCopyCtorCookieLocalNum>.SetNext(&<dwCookieLocalNum>)
2251 pcsEmit->EmitLDLOCA(m_dwLastCopyCtorCookieLocalNum);
2252 pcsEmit->EmitLDLOCA(dwCookieLocalNum);
2253 pcsEmit->EmitCALL(METHOD__COPYCTORSTUBCOOKIE__SET_NEXT, 2, 0);
2256 m_dwLastCopyCtorCookieLocalNum = dwCookieLocalNum;
2257 return dwCookieLocalNum;
2260 #endif // _TARGET_X86_ && !FEATURE_CORECLR
2262 void NDirectStubLinker::Begin(DWORD dwStubFlags)
2264 STANDARD_VM_CONTRACT;
2266 #ifdef FEATURE_COMINTEROP
2267 if (SF_IsWinRTHasRedirection(dwStubFlags))
2269 _ASSERTE(SF_IsForwardCOMStub(dwStubFlags));
2271 // The very first thing we need to do is check whether the call should be routed to
2272 // the marshaling stub for the corresponding projected WinRT interface. If so, we
2274 m_pcsSetup->EmitLoadThis();
2275 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2276 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__SHOULD_CALL_WINRT_INTERFACE, 2, 1);
2278 ILCodeLabel *pNoRedirection = m_pcsSetup->NewCodeLabel();
2279 m_pcsSetup->EmitBRFALSE(pNoRedirection);
2281 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(
2283 TypeHandle::Interop_ManagedToNative);
2285 CONSISTENCY_CHECK(pAdapterMD != NULL && !pAdapterMD->HasMethodInstantiation());
2287 m_pcsSetup->EmitJMP(m_pcsSetup->GetToken(pAdapterMD));
2289 m_pcsSetup->EmitLabel(pNoRedirection);
2291 #endif // FEATURE_COMINTEROP
2293 if (SF_IsForwardStub(dwStubFlags))
2295 #ifndef FEATURE_CORECLR // CAS
2296 // we may need to demand security permission
2297 if (SF_IsStubWithDemand(dwStubFlags))
2299 if (SF_IsCOMStub(dwStubFlags) || SF_IsDelegateStub(dwStubFlags))
2301 // pass NULL NDirectMethodDesc for COM and delegate P/Invoke
2302 m_pcsSetup->EmitLoadNullPtr();
2306 // pass the real MD for direct P/Invoke
2307 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2309 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__DEMAND_PERMISSION, 1, 0);
2311 #endif // !FEATURE_CORECLR
2313 if (SF_IsStubWithCctorTrigger(dwStubFlags))
2315 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2316 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__INIT_DECLARING_TYPE, 1, 0);
2321 #ifdef MDA_SUPPORTED
2322 if (!SF_IsNGENedStub(dwStubFlags) && MDA_GET_ASSISTANT(GcUnmanagedToManaged))
2324 EmitCallGcCollectForMDA(m_pcsSetup, dwStubFlags);
2326 #endif // MDA_SUPPORTED
2328 if (SF_IsDelegateStub(dwStubFlags))
2330 #if defined(MDA_SUPPORTED) || (defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR))
2331 // GC was induced (gcUnmanagedToManagedMDA), arguments have been marshaled, and we are about
2332 // to touch the UMEntryThunk and extract the delegate target from it so this is the right time
2333 // to do the collected delegate MDA check.
2335 // The call to CheckCollectedDelegateMDA is emitted regardless of whether the MDA is on at the
2336 // moment. This is to avoid having to ignore NGENed stubs without the call just as we do for
2337 // the GC MDA (callbackOncollectedDelegateMDA is turned on under managed debugger by default
2338 // so the impact would be substantial). The helper bails out fast if the MDA is not enabled.
2339 EmitLoadStubContext(m_pcsDispatch, dwStubFlags);
2340 m_pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CHECK_COLLECTED_DELEGATE_MDA, 1, 0);
2341 #endif // MDA_SUPPORTED
2344 // recover delegate object from UMEntryThunk
2346 EmitLoadStubContext(m_pcsDispatch, dwStubFlags); // load UMEntryThunk*
2348 m_pcsDispatch->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2349 m_pcsDispatch->EmitADD();
2350 m_pcsDispatch->EmitLDIND_I(); // get OBJECTHANDLE
2351 m_pcsDispatch->EmitLDIND_REF(); // get Delegate object
2352 m_pcsDispatch->EmitLDFLD(GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__TARGET)));
2356 m_pCleanupTryBeginLabel = NewCodeLabel();
2357 m_pcsMarshal->EmitLabel(m_pCleanupTryBeginLabel);
2360 void NDirectStubLinker::End(DWORD dwStubFlags)
2362 STANDARD_VM_CONTRACT;
2364 ILCodeStream* pcs = m_pcsUnmarshal;
2366 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(dwStubFlags)
2367 && !SF_IsFieldGetterStub(dwStubFlags)
2368 && !SF_IsFieldSetterStub(dwStubFlags);
2371 // Create a local for the return value and store the return value in it.
2373 if (IsCleanupNeeded() || hasTryCatchForHRESULT)
2375 // Save the return value if necessary, since the IL stack will be emptied when we leave a try block.
2376 LocalDesc locDescRetVal;
2377 if (SF_IsForwardStub(dwStubFlags))
2379 GetStubReturnType(&locDescRetVal);
2383 GetStubTargetReturnType(&locDescRetVal);
2386 if (!( (locDescRetVal.cbType == 1) && (locDescRetVal.ElementType[0] == ELEMENT_TYPE_VOID) ))
2388 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2389 if (SF_IsReverseStub(dwStubFlags) && StubHasVoidReturnType())
2391 // if the target returns void and we are doing HRESULT swapping, S_OK is loaded
2392 // in the unmarshal stream
2393 m_pcsUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2397 // otherwise the return value is loaded in the return unmarshal stream
2398 m_pcsRetUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2401 else if (hasTryCatchForHRESULT && (locDescRetVal.ElementType[0] != ELEMENT_TYPE_VOID))
2403 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2408 // Emit end-of-try and end-of-finally code for the try/finally
2410 if (IsCleanupNeeded())
2412 m_pCleanupFinallyEndLabel = NewCodeLabel();
2413 m_pCleanupTryEndLabel = NewCodeLabel();
2415 if (IsExceptionCleanupNeeded())
2417 // if we made it here, no exception has been thrown
2418 EmitSetArgMarshalIndex(m_pcsUnmarshal, CLEANUP_INDEX_ALL_DONE);
2421 // Emit a leave at the end of the try block. If we have an outer try/catch, we need
2422 // to leave to the beginning of the ExceptionHandler code stream, which follows the
2423 // Cleanup code stream. If we don't, we can just leave to the tail end of the
2424 // Unmarshal code stream where we'll emit our RET.
2426 ILCodeLabel* pLeaveTarget = m_pCleanupTryEndLabel;
2427 if (hasTryCatchForHRESULT)
2429 pLeaveTarget = m_pCleanupFinallyEndLabel;
2432 m_pcsUnmarshal->EmitLEAVE(pLeaveTarget);
2433 m_pcsUnmarshal->EmitLabel(m_pCleanupTryEndLabel);
2435 // Emit a call to destroy the clean-up list if needed.
2436 if (IsCleanupWorkListSetup())
2438 LoadCleanupWorkList(m_pcsCleanup);
2439 m_pcsCleanup->EmitCALL(METHOD__STUBHELPERS__DESTROY_CLEANUP_LIST, 1, 0);
2442 // Emit the endfinally.
2443 m_pcsCleanup->EmitENDFINALLY();
2444 m_pcsCleanup->EmitLabel(m_pCleanupFinallyEndLabel);
2447 #ifdef MDA_SUPPORTED
2448 if (SF_IsReverseStub(dwStubFlags) && !SF_IsNGENedStub(dwStubFlags) &&
2449 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
2451 EmitCallGcCollectForMDA(pcs, dwStubFlags);
2453 #endif // MDA_SUPPORTED
2455 if (IsExceptionCleanupNeeded())
2457 m_pcsExceptionCleanup->EmitLabel(m_pSkipExceptionCleanupLabel);
2460 // Reload the return value
2461 if ((m_dwRetValLocalNum != (DWORD)-1) && !hasTryCatchForHRESULT)
2463 pcs->EmitLDLOC(m_dwRetValLocalNum);
2467 void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD)
2469 STANDARD_VM_CONTRACT;
2470 if (SF_IsForwardStub(dwStubFlags)) // managed-to-native
2472 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
2473 // set the copy ctor cookie chain if needed
2474 if (IsCopyCtorStubNeeded())
2476 // StubHelpers.SetCopyCtorCookieChain(pStubArg, pUnmngThis, dwStubFlags, &<m_dwFirstCopyCtorCookieLocalNum>)
2477 if (SF_IsDelegateStub(dwStubFlags))
2479 // for forward delegate P/Invoke load the target from 'this'
2480 pcsEmit->EmitLoadThis();
2481 pcsEmit->EmitLDFLD(pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR_AUX)));
2485 // otherwise load the secret argument
2486 EmitLoadStubContext(pcsEmit, dwStubFlags);
2489 if (SF_IsCOMStub(dwStubFlags))
2491 // for forward COM load the unmanaged interface pointer
2492 pcsEmit->EmitLDLOC(m_dwTargetInterfacePointerLocalNum);
2497 pcsEmit->EmitLoadNullPtr();
2499 pcsEmit->EmitLDC(dwStubFlags);
2500 pcsEmit->EmitLDLOCA(m_dwFirstCopyCtorCookieLocalNum);
2501 pcsEmit->EmitCALL(METHOD__STUBHELPERS__SET_COPY_CTOR_COOKIE_CHAIN, 4, 0);
2503 #endif // _TARGET_X86_ && !FEATURE_CORECLR
2505 if (SF_IsDelegateStub(dwStubFlags)) // delegate invocation
2507 // get the delegate unmanaged target - we call a helper instead of just grabbing
2508 // the _methodPtrAux field because we may need to intercept the call for host, MDA, etc.
2509 pcsEmit->EmitLoadThis();
2511 // on AMD64 GetDelegateTarget will return address of the generic stub for host when we are hosted
2512 // and update the secret argument with real target - the secret arg will be embedded in the
2513 // InlinedCallFrame by the JIT and fetched via TLS->Thread->Frame->Datum by the stub for host
2514 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
2516 // we don't need to do this on x86 because stub for host is generated dynamically per target
2517 pcsEmit->EmitLDNULL();
2519 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_TARGET, 2, 1);
2521 else // direct invocation
2523 if (SF_IsCALLIStub(dwStubFlags)) // unmanaged CALLI
2525 // if we ever NGEN CALLI stubs, this would have to be done differently
2526 _ASSERTE(!SF_IsNGENedStub(dwStubFlags));
2528 #ifndef CROSSGEN_COMPILE
2532 #ifndef FEATURE_CORECLR
2533 if (IsCopyCtorStubNeeded())
2535 // if we need to call copy ctor(s), we go to the copy ctor stub
2536 Stub *pCopyCtorStub = NDirect::GetStubForCopyCtor();
2537 pcsEmit->EmitLDC((DWORD_PTR)pCopyCtorStub->GetEntryPoint());
2540 #endif // !FEATURE_CORECLR
2542 // for managed-to-unmanaged CALLI that requires marshaling, the target is passed
2543 // as the secret argument to the stub by GenericPInvokeCalliHelper (asmhelpers.asm)
2544 EmitLoadStubContext(pcsEmit, dwStubFlags);
2547 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2548 if (NDirect::IsHostHookEnabled())
2550 // we need to call to the host hook, real target is passed as the last argument
2551 Stub *pHostStub = NDirect::GenerateStubForHost(
2553 (CorUnmanagedCallingConvention)(GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_MASK),
2554 pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize());
2556 pcsEmit->EmitLDC((DWORD_PTR)pHostStub->GetEntryPoint());
2558 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2560 #else // _TARGET_X86_
2562 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2563 if (NDirect::IsHostHookEnabled())
2565 // the stub for host will get the original target from the secret arg
2566 pcsEmit->EmitLDC((DWORD_PTR)GetEEFuncEntryPoint(PInvokeStubForHost));
2569 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2571 // the secret arg has been shifted to left and ORed with 1 (see code:GenericPInvokeCalliHelper)
2572 EmitLoadStubContext(pcsEmit, dwStubFlags);
2573 #ifndef _TARGET_ARM_
2574 pcsEmit->EmitLDC(1);
2575 pcsEmit->EmitSHR_UN();
2579 #endif // _TARGET_X86_
2581 #endif // CROSSGEN_COMPILE
2584 #ifdef FEATURE_COMINTEROP
2585 if (!SF_IsCOMStub(dwStubFlags)) // forward P/Invoke
2586 #endif // FEATURE_COMINTEROP
2588 EmitLoadStubContext(pcsEmit, dwStubFlags);
2591 // Perf: inline the helper for now
2592 //pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_NDIRECT_TARGET, 1, 1);
2593 pcsEmit->EmitLDC(offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
2595 pcsEmit->EmitLDIND_I();
2596 pcsEmit->EmitLDIND_I();
2599 #ifdef FEATURE_COMINTEROP
2602 // this is a CLR -> COM call
2603 // the target has been computed by StubHelpers::GetCOMIPFromRCW
2604 pcsEmit->EmitLDLOC(m_dwTargetEntryPointLocalNum);
2606 #endif // FEATURE_COMINTEROP
2609 else // native-to-managed
2611 if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate
2613 int tokDelegate_methodPtr = pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR));
2615 EmitLoadStubContext(pcsEmit, dwStubFlags);
2616 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2618 pcsEmit->EmitLDIND_I(); // Get OBJECTHANDLE
2619 pcsEmit->EmitLDIND_REF(); // Get Delegate object
2620 pcsEmit->EmitLDFLD(tokDelegate_methodPtr); // get _methodPtr
2622 #ifdef FEATURE_COMINTEROP
2623 else if (SF_IsCOMStub(dwStubFlags)) // COM -> CLR call
2625 // managed target is passed directly in the secret argument
2626 EmitLoadStubContext(pcsEmit, dwStubFlags);
2628 #endif // FEATURE_COMINTEROP
2629 else // direct reverse P/Invoke (CoreCLR hosting)
2631 EmitLoadStubContext(pcsEmit, dwStubFlags);
2632 CONSISTENCY_CHECK(0 == offsetof(UMEntryThunk, m_pManagedTarget)); // if this changes, just add back the EmitLDC/EmitADD below
2633 // pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pManagedTarget));
2634 // pcsEmit->EmitADD();
2635 pcsEmit->EmitLDIND_I(); // Get UMEntryThunk::m_pManagedTarget
2639 // For managed-to-native calls, the rest of the work is done by the JIT. It will
2640 // erect InlinedCallFrame, flip GC mode, and use the specified calling convention
2641 // to call the target. For native-to-managed calls, this is an ordinary managed
2642 // CALLI and nothing special happens.
2643 pcsEmit->EmitCALLI(TOKEN_ILSTUB_TARGET_SIG, 0, m_iTargetStackDelta);
2646 void NDirectStubLinker::EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal)
2648 STANDARD_VM_CONTRACT;
2650 if (SF_IsForwardPInvokeStub(m_dwStubFlags) && !SF_IsForwardDelegateStub(m_dwStubFlags))
2652 // get the secret argument via intrinsic
2653 pslILEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2657 // no secret argument
2658 pslILEmit->EmitLoadNullPtr();
2661 pslILEmit->EmitLDLOC(dwPinnedLocal);
2663 pslILEmit->EmitCALL(METHOD__STUBHELPERS__LOG_PINNED_ARGUMENT, 2, 0);
2666 void NDirectStubLinker::GetCleanupFinallyOffsets(ILStubEHClause * pClause)
2671 PRECONDITION(CheckPointer(pClause));
2675 if (m_pCleanupFinallyEndLabel)
2677 _ASSERTE(m_pCleanupFinallyBeginLabel);
2678 _ASSERTE(m_pCleanupTryBeginLabel);
2679 _ASSERTE(m_pCleanupTryEndLabel);
2681 pClause->kind = ILStubEHClause::kFinally;
2682 pClause->dwTryBeginOffset = (DWORD)m_pCleanupTryBeginLabel->GetCodeOffset();
2683 pClause->cbTryLength = (DWORD)m_pCleanupTryEndLabel->GetCodeOffset() - pClause->dwTryBeginOffset;
2684 pClause->dwHandlerBeginOffset = (DWORD)m_pCleanupFinallyBeginLabel->GetCodeOffset();
2685 pClause->cbHandlerLength = (DWORD)m_pCleanupFinallyEndLabel->GetCodeOffset() - pClause->dwHandlerBeginOffset;
2689 void NDirectStubLinker::ClearCode()
2691 WRAPPER_NO_CONTRACT;
2692 ILStubLinker::ClearCode();
2694 m_pCleanupTryBeginLabel = 0;
2695 m_pCleanupTryEndLabel = 0;
2696 m_pCleanupFinallyBeginLabel = 0;
2697 m_pCleanupFinallyEndLabel = 0;
2700 #ifdef PROFILING_SUPPORTED
2701 DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2703 STANDARD_VM_CONTRACT;
2705 if (SF_IsForwardDelegateStub(dwStubFlags) || SF_IsCALLIStub(dwStubFlags))
2707 // secret argument does not contain MD nor UMEntryThunk
2708 pcsEmit->EmitLoadNullPtr();
2712 EmitLoadStubContext(pcsEmit, dwStubFlags);
2715 if (SF_IsForwardStub(dwStubFlags))
2717 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2721 // we use a null pThread to indicate reverse interop
2722 pcsEmit->EmitLDC(NULL);
2725 // In the unmanaged delegate case, we need the "this" object to retrieve the MD
2726 // in StubHelpers::ProfilerEnterCallback().
2727 if (SF_IsDelegateStub(dwStubFlags))
2729 if (SF_IsForwardStub(dwStubFlags))
2731 pcsEmit->EmitLoadThis();
2735 EmitLoadStubContext(pcsEmit, dwStubFlags); // load UMEntryThunk*
2736 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2738 pcsEmit->EmitLDIND_I(); // get OBJECTHANDLE
2739 pcsEmit->EmitLDIND_REF(); // get Delegate object
2744 pcsEmit->EmitLDC(NULL);
2746 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_BEGIN_TRANSITION_CALLBACK, 3, 1);
2748 // Store the MD for StubHelpers::ProfilerLeaveCallback().
2749 DWORD dwMethodDescLocalNum = pcsEmit->NewLocal(ELEMENT_TYPE_I);
2750 pcsEmit->EmitSTLOC(dwMethodDescLocalNum);
2751 return dwMethodDescLocalNum;
2754 void NDirectStubLinker::EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum)
2756 STANDARD_VM_CONTRACT;
2758 pcsEmit->EmitLDLOC(dwMethodDescLocalNum);
2759 if (SF_IsReverseStub(dwStubFlags))
2761 // we use a null pThread to indicate reverse interop
2762 pcsEmit->EmitLDC(NULL);
2766 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2768 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_END_TRANSITION_CALLBACK, 2, 0);
2770 #endif // PROFILING_SUPPPORTED
2773 void NDirectStubLinker::EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags)
2775 STANDARD_VM_CONTRACT;
2777 pcsEmit->EmitLDLOC(dwLocalNum);
2779 if (SF_IsDelegateStub(dwStubFlags))
2781 pcsEmit->EmitLoadNullPtr();
2782 pcsEmit->EmitLoadThis();
2784 else if (SF_IsCALLIStub(dwStubFlags))
2786 pcsEmit->EmitLoadNullPtr();
2787 pcsEmit->EmitLDNULL();
2791 // P/Invoke, CLR->COM
2792 EmitLoadStubContext(pcsEmit, dwStubFlags);
2793 pcsEmit->EmitLDNULL();
2798 // StubHelpers.ValidateByref(byref, pMD, pThis)
2799 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_BYREF, 3, 0);
2803 // StubHelpers.ValidateObject(obj, pMD, pThis)
2804 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_OBJECT, 3, 0);
2808 void NDirectStubLinker::EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2810 STANDARD_VM_CONTRACT;
2812 // generate validation callouts for pinned locals
2813 CQuickBytes qbLocalSig;
2814 DWORD cbSig = GetLocalSigSize();
2816 qbLocalSig.AllocThrows(cbSig);
2817 PCOR_SIGNATURE pSig = (PCOR_SIGNATURE)qbLocalSig.Ptr();
2819 GetLocalSig(pSig, cbSig);
2820 SigPointer ptr(pSig, cbSig);
2822 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
2825 IfFailThrow(ptr.GetData(&numLocals));
2827 for (ULONG i = 0; i < numLocals; i++)
2830 IfFailThrow(ptr.PeekByte(&modifier));
2831 if (modifier == ELEMENT_TYPE_PINNED)
2833 IfFailThrow(ptr.GetByte(NULL));
2834 IfFailThrow(ptr.PeekByte(&modifier));
2835 EmitValidateLocal(pcsEmit, i, (modifier == ELEMENT_TYPE_BYREF), dwStubFlags);
2838 IfFailThrow(ptr.SkipExactlyOne());
2841 #endif // VERIFY_HEAP
2843 // Loads the 'secret argument' passed to the stub.
2844 void NDirectStubLinker::EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2846 STANDARD_VM_CONTRACT;
2848 CONSISTENCY_CHECK(!SF_IsForwardDelegateStub(dwStubFlags));
2849 CONSISTENCY_CHECK(!SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags));
2851 #ifdef FEATURE_COMINTEROP
2852 if (SF_IsWinRTDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags))
2854 // we have the delegate 'this' but we need the EEImpl/Instantiated 'Invoke' MD pointer
2855 // (Delegate.GetInvokeMethod does not return exact instantiated MD so we call our own helper)
2856 pcsEmit->EmitLoadThis();
2857 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_INVOKE_METHOD, 1, 1);
2860 #endif // FEATURE_COMINTEROP
2862 // get the secret argument via intrinsic
2863 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2867 #ifdef MDA_SUPPORTED
2868 void NDirectStubLinker::EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2870 STANDARD_VM_CONTRACT;
2872 ILCodeLabel *pSkipGcLabel = NULL;
2874 if (SF_IsForwardPInvokeStub(dwStubFlags) &&
2875 !SF_IsDelegateStub(dwStubFlags) &&
2876 !SF_IsCALLIStub(dwStubFlags))
2878 // don't call GC if this is a QCall
2879 EmitLoadStubContext(pcsEmit, dwStubFlags);
2880 pcsEmit->EmitCALL(METHOD__STUBHELPERS__IS_QCALL, 1, 1);
2882 pSkipGcLabel = pcsEmit->NewCodeLabel();
2883 pcsEmit->EmitBRTRUE(pSkipGcLabel);
2886 pcsEmit->EmitCALL(METHOD__STUBHELPERS__TRIGGER_GC_FOR_MDA, 0, 0);
2888 if (pSkipGcLabel != NULL)
2890 pcsEmit->EmitLabel(pSkipGcLabel);
2893 #endif // MDA_SUPPORTED
2895 #ifdef FEATURE_COMINTEROP
2897 class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing calls
2904 WRAPPER_NO_CONTRACT;
2907 void SetLastError(BOOL fSetLastError)
2909 LIMITED_METHOD_CONTRACT;
2911 CONSISTENCY_CHECK(!fSetLastError);
2914 void BeginEmit(DWORD dwStubFlags)
2916 LIMITED_METHOD_CONTRACT;
2918 CONSISTENCY_CHECK(SF_IsCOMStub(dwStubFlags));
2919 m_dwStubFlags = dwStubFlags;
2922 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
2928 PRECONDITION(CheckPointer(pInfo));
2933 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
2938 PRECONDITION(CheckPointer(pInfo));
2942 if (SF_IsCOMLateBoundStub(m_dwStubFlags) && pInfo->GetDispWrapperType() != 0)
2944 m_lateBoundFlags |= ComPlusCallInfo::kRequiresArgumentWrapping;
2948 void MarshalLCID(int argIdx)
2950 LIMITED_METHOD_CONTRACT;
2953 #ifdef FEATURE_COMINTEROP
2954 void MarshalHiddenLengthArgument(MarshalInfo *, BOOL)
2956 LIMITED_METHOD_CONTRACT;
2958 void MarshalFactoryReturn()
2960 LIMITED_METHOD_CONTRACT;
2963 #endif // FEATURE_COMINTEROP
2965 void EmitInvokeTarget(MethodDesc *pStubMD)
2967 LIMITED_METHOD_CONTRACT;
2968 UNREACHABLE_MSG("Should never come to DispatchStubState::EmitInvokeTarget");
2971 void FinishEmit(MethodDesc *pMD)
2973 STANDARD_VM_CONTRACT;
2975 // set flags directly on the interop MD
2976 _ASSERTE(pMD->IsComPlusCall());
2978 ((ComPlusCallMethodDesc *)pMD)->SetLateBoundFlags(m_lateBoundFlags);
2982 DWORD m_dwStubFlags;
2983 BYTE m_lateBoundFlags; // ComPlusCallMethodDesc::Flags
2986 #endif // FEATURE_COMINTEROP
2989 void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
2999 // initialize data members
3001 m_pModule = pModule;
3002 m_callConv = (CorPinvokeMap)0;
3003 SetBestFitMapping (TRUE);
3004 SetThrowOnUnmappableChar (FALSE);
3005 SetLinkFlags (nlfNone);
3006 SetCharSet (nltAnsi);
3009 // assembly/type level m_bestFit & m_bThrowOnUnmappableChar
3011 BOOL bThrowOnUnmappableChar;
3015 EEClass::GetBestFitMapping(pMT, &bBestFit, &bThrowOnUnmappableChar);
3019 ReadBestFitCustomAttribute(m_pModule->GetMDImport(), mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
3022 SetBestFitMapping (bBestFit);
3023 SetThrowOnUnmappableChar (bThrowOnUnmappableChar);
3026 void PInvokeStaticSigInfo::PreInit(MethodDesc* pMD)
3036 PreInit(pMD->GetModule(), pMD->GetMethodTable());
3037 SetIsStatic (pMD->IsStatic());
3038 m_sig = pMD->GetSignature();
3039 if (pMD->IsEEImpl())
3041 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
3042 SetIsDelegateInterop(TRUE);
3046 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
3047 MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError)
3057 DllImportInit(pMD, pLibName, pEntryPointName);
3063 PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOnError)
3071 PRECONDITION(CheckPointer(pMD));
3077 MethodTable * pMT = pMD->GetMethodTable();
3079 if (!pMT->IsDelegate())
3081 DllImportInit(pMD, NULL, NULL);
3085 // initialize data members to defaults
3088 // System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute
3091 CorPinvokeMap callConv = (CorPinvokeMap)0;
3093 HRESULT hRESULT = pMT->GetMDImport()->GetCustomAttributeByName(
3094 pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, (const VOID **)(&pData), (ULONG *)&cData);
3095 IfFailThrow(hRESULT);
3098 CustomAttributeParser ca(pData, cData);
3101 args[0].InitEnum(SERIALIZATION_TYPE_I4, (ULONG)m_callConv);
3103 IfFailGo(ParseKnownCaArgs(ca, args, lengthof(args)));
3105 enum UnmanagedFunctionPointerNamedArgs
3109 MDA_ThrowOnUnmappableChar,
3115 CaNamedArg namedArgs[MDA_Last];
3116 namedArgs[MDA_CharSet].InitI4FieldEnum("CharSet", "System.Runtime.InteropServices.CharSet", (ULONG)GetCharSet());
3117 namedArgs[MDA_BestFitMapping].InitBoolField("BestFitMapping", (ULONG)GetBestFitMapping());
3118 namedArgs[MDA_ThrowOnUnmappableChar].InitBoolField("ThrowOnUnmappableChar", (ULONG)GetThrowOnUnmappableChar());
3119 namedArgs[MDA_SetLastError].InitBoolField("SetLastError", 0);
3120 namedArgs[MDA_PreserveSig].InitBoolField("PreserveSig", 0);
3122 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
3124 callConv = (CorPinvokeMap)(args[0].val.u4 << 8);
3125 CorNativeLinkType nlt = (CorNativeLinkType)0;
3127 // XXX Tue 07/19/2005
3128 // Keep in sync with the handling of CorPInvokeMap in
3129 // PInvokeStaticSigInfo::DllImportInit.
3130 switch( namedArgs[MDA_CharSet].val.u4 )
3134 nlt = nltAnsi; break;
3136 case nltAuto: // Since Win9x isn't supported anymore, nltAuto always represents unicode strings.
3137 nlt = nltUnicode; break;
3139 hr = E_FAIL; goto ErrExit;
3142 SetBestFitMapping (namedArgs[MDA_BestFitMapping].val.u1);
3143 SetThrowOnUnmappableChar (namedArgs[MDA_ThrowOnUnmappableChar].val.u1);
3144 if (namedArgs[MDA_SetLastError].val.u1)
3145 SetLinkFlags ((CorNativeLinkFlags)(nlfLastError | GetLinkFlags()));
3146 if (namedArgs[MDA_PreserveSig].val.u1)
3147 SetLinkFlags ((CorNativeLinkFlags)(nlfNoMangle | GetLinkFlags()));
3153 SetError(IDS_EE_NDIRECT_BADNATL);
3155 InitCallConv(callConv, pMD->IsVarArg());
3161 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
3162 Signature sig, Module* pModule, ThrowOnError throwOnError)
3170 PRECONDITION(CheckPointer(pModule));
3174 PreInit(pModule, NULL);
3176 SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
3177 InitCallConv((CorPinvokeMap)0, FALSE);
3183 void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LPCUTF8 *ppEntryPointName)
3191 PRECONDITION(CheckPointer(pMD));
3193 // These preconditions to prevent multithreaded regression
3194 // where pMD->ndirect.m_szLibName was passed in directly, cleared
3195 // by this API, then accessed on another thread before being reset here.
3196 PRECONDITION(CheckPointer(ppLibName, NULL_OK) && (!ppLibName || *ppLibName == NULL));
3197 PRECONDITION(CheckPointer(ppEntryPointName, NULL_OK) && (!ppEntryPointName || *ppEntryPointName == NULL));
3201 // initialize data members to defaults
3204 // System.Runtime.InteropServices.DllImportAttribute
3205 IMDInternalImport *pInternalImport = pMD->GetMDImport();
3206 CorPinvokeMap mappingFlags = pmMaxValue;
3207 mdModuleRef modref = mdModuleRefNil;
3208 if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
3210 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3211 // The guessing heuristic has been broken with NGen for a long time since we stopped loading
3212 // images at NGen time using full LoadLibrary. The DLL references are not resolved correctly
3213 // without full LoadLibrary.
3215 // Disable the heuristic consistently during NGen so that it does not kick in by accident.
3216 if (!IsCompilationProcess())
3217 BestGuessNDirectDefaults(pMD);
3219 InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
3223 // out parameter pEntryPointName
3224 if (ppEntryPointName && *ppEntryPointName == NULL)
3225 *ppEntryPointName = pMD->GetName();
3227 // out parameter pLibName
3228 if (ppLibName != NULL)
3230 if (FAILED(pInternalImport->GetModuleRefProps(modref, ppLibName)))
3232 SetError(IDS_CLASSLOAD_BADFORMAT);
3238 InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
3241 CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
3242 if (bestFitMask == pmBestFitEnabled)
3243 SetBestFitMapping (TRUE);
3244 else if (bestFitMask == pmBestFitDisabled)
3245 SetBestFitMapping (FALSE);
3247 // m_bThrowOnUnmappableChar
3248 CorPinvokeMap unmappableMask = (CorPinvokeMap)(mappingFlags & pmThrowOnUnmappableCharMask);
3249 if (unmappableMask == pmThrowOnUnmappableCharEnabled)
3250 SetThrowOnUnmappableChar (TRUE);
3251 else if (unmappableMask == pmThrowOnUnmappableCharDisabled)
3252 SetThrowOnUnmappableChar (FALSE);
3254 // inkFlags : CorPinvoke -> CorNativeLinkFlags
3255 if (mappingFlags & pmSupportsLastError)
3256 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3257 if (mappingFlags & pmNoMangle)
3258 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfNoMangle));
3260 // XXX Tue 07/19/2005
3261 // Keep in sync with the handling of CorNativeLinkType in
3262 // PInvokeStaticSigInfo::PInvokeStaticSigInfo.
3264 // charset : CorPinvoke -> CorNativeLinkType
3265 CorPinvokeMap charSetMask = (CorPinvokeMap)(mappingFlags & (pmCharSetNotSpec | pmCharSetAnsi | pmCharSetUnicode | pmCharSetAuto));
3266 if (charSetMask == pmCharSetNotSpec || charSetMask == pmCharSetAnsi)
3268 SetCharSet (nltAnsi);
3270 else if (charSetMask == pmCharSetUnicode || charSetMask == pmCharSetAuto)
3272 // Since Win9x isn't supported anymore, pmCharSetAuto always represents unicode strings.
3273 SetCharSet (nltUnicode);
3277 SetError(IDS_EE_NDIRECT_BADNATL);
3282 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3284 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3285 static BOOL HeuristicDoesThisLooksLikeAnApiCallHelper(LPBYTE pTarget)
3295 // This code is not that useful anymore since this functionality is already embedded in the VC linker.
3296 // The linker will emit the lasterror flag by default for functions residing in modules that are
3297 // a superset of the list below.
3298 // Look for bug VSWhidbey 241895.
3300 static struct SysDllInfo
3305 } gSysDllInfo[] = {{WINDOWS_KERNEL32_DLLNAME_W, 0, 0},
3307 {W("USER32"), 0, 0},
3308 {W("ADVAPI32"), 0, 0}
3312 for (int i = 0; i < sizeof(gSysDllInfo)/sizeof(*gSysDllInfo); i++)
3314 if (gSysDllInfo[i].pImageBase == 0)
3316 IMAGE_DOS_HEADER *pDos = (IMAGE_DOS_HEADER*)CLRGetModuleHandle(gSysDllInfo[i].pName);
3319 if (pDos->e_magic == VAL16(IMAGE_DOS_SIGNATURE))
3321 IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*) (((LPBYTE)pDos) + VAL32(pDos->e_lfanew));
3322 if (pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) &&
3323 pNT->FileHeader.SizeOfOptionalHeader ==
3325 VAL16(sizeof(IMAGE_OPTIONAL_HEADER64))
3327 VAL16(sizeof(IMAGE_OPTIONAL_HEADER32))
3329 && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
3331 gSysDllInfo[i].dwImageSize = VAL32(pNT->OptionalHeader.SizeOfImage);
3335 gSysDllInfo[i].pImageBase = (LPBYTE)pDos;
3338 if (gSysDllInfo[i].pImageBase != 0 &&
3339 pTarget >= gSysDllInfo[i].pImageBase &&
3340 pTarget < gSysDllInfo[i].pImageBase + gSysDllInfo[i].dwImageSize)
3349 LPBYTE FollowIndirect(LPBYTE pTarget)
3356 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3364 AVInRuntimeImplOkayHolder AVOkay;
3367 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3369 pRet = **(LPBYTE**)(pTarget + 2);
3371 #elif defined(_TARGET_AMD64_)
3372 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3374 INT64 rva = *(INT32*)(pTarget + 2);
3375 pRet = *(LPBYTE*)(pTarget + 6 + rva);
3383 EX_END_CATCH(SwallowAllExceptions);
3388 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3389 BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget)
3399 if (pTarget == NULL)
3402 if (HeuristicDoesThisLooksLikeAnApiCallHelper(pTarget))
3405 LPBYTE pTarget2 = FollowIndirect(pTarget);
3408 // jmp [xxxx] - could be an import thunk
3409 return HeuristicDoesThisLooksLikeAnApiCallHelper( pTarget2 );
3415 BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
3425 static LPBYTE pGetLastError = NULL;
3428 // No need to use a holder here, since no cleanup is necessary.
3429 HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
3432 pGetLastError = (LPBYTE)GetProcAddress(hMod, "GetLastError");
3435 // This should never happen but better to be cautious.
3436 pGetLastError = (LPBYTE)-1;
3441 // We failed to get the module handle for kernel32.dll. This is almost impossible
3442 // however better to err on the side of caution.
3443 pGetLastError = (LPBYTE)-1;
3447 if (pTarget == pGetLastError)
3450 if (pTarget == NULL)
3453 LPBYTE pTarget2 = FollowIndirect(pTarget);
3456 // jmp [xxxx] - could be an import thunk
3457 return pTarget2 == pGetLastError;
3463 DWORD __stdcall FalseGetLastError()
3465 WRAPPER_NO_CONTRACT;
3467 return GetThread()->m_dwLastError;
3470 void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
3480 if (!pMD->IsNDirect())
3483 NDirectMethodDesc* pMDD = (NDirectMethodDesc*)pMD;
3485 if (!pMDD->IsEarlyBound())
3488 LPVOID pTarget = NULL;
3490 // NOTE: If we get inside this block, and this is a call to GetLastError,
3491 // then InitEarlyBoundNDirectTarget has not been run yet.
3492 if (pMDD->NDirectTargetIsImportThunk())
3494 // Get the unmanaged callsite.
3495 pTarget = (LPVOID)pMDD->GetModule()->GetInternalPInvokeTarget(pMDD->GetRVA());
3497 // If this is a call to GetLastError, then we haven't overwritten m_pNativeNDirectTarget yet.
3498 if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)pTarget))
3499 pTarget = (BYTE*) FalseGetLastError;
3503 pTarget = pMDD->GetNativeNDirectTarget();
3506 if (HeuristicDoesThisLooksLikeAnApiCall((LPBYTE) pTarget))
3507 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3510 #endif // FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
3513 void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
3523 // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
3524 if (callConv == pmCallConvWinapi)
3525 callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3527 CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
3528 BOOL fSuccess = MetaSig::GetUnmanagedCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv);
3532 SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format
3535 // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
3536 // to do this before we check to make sure the PInvoke map calling convention and the
3537 // signature calling convention match for compatibility reasons.
3538 if (sigCallConv == pmCallConvWinapi)
3539 sigCallConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3541 if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
3542 SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
3544 if (callConv == 0 && sigCallConv == 0)
3545 m_callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3546 else if (callConv != 0)
3547 m_callConv = callConv;
3549 m_callConv = sigCallConv;
3551 if (bIsVarArg && m_callConv != pmCallConvCdecl)
3552 SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
3555 void PInvokeStaticSigInfo::ReportErrors()
3566 COMPlusThrow(kTypeLoadException, m_error);
3570 //---------------------------------------------------------
3571 // Does a class or method have a NAT_L CustomAttribute?
3575 // FAILED = unknown because something failed.
3576 //---------------------------------------------------------
3578 HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs)
3586 PRECONDITION(CheckPointer(pInternalImport));
3587 PRECONDITION(TypeFromToken(token) == mdtMethodDef);
3591 // Check method flags first before trying to find the custom value
3592 if (!IsReallyMdPinvokeImpl(dwMemberAttrs))
3596 LPCSTR pszImportName;
3599 if (SUCCEEDED(pInternalImport->GetPinvokeMap(token, &mappingFlags, &pszImportName, &modref)))
3606 // Either MD or signature & module must be given.
3608 BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*/, Module *pModule /*= NULL*/)
3613 PRECONDITION(pMD != NULL || (pSig != NULL && pModule != NULL));
3617 // As a by-product, when returning FALSE we will also set the native stack size to the MD if it's
3618 // an NDirectMethodDesc. This number is needed to link the P/Invoke (it determines the @n entry
3619 // point name suffix and affects alignment thunk generation on the Mac). If this method returns
3620 // TRUE, the stack size will be set when building the marshaling IL stub.
3621 DWORD dwStackSize = 0;
3622 CorPinvokeMap callConv = (CorPinvokeMap)0;
3626 if (pMD->IsNDirect() || pMD->IsComPlusCall())
3628 // HRESULT swapping is handled by stub
3629 if ((pMD->GetImplAttrs() & miPreserveSig) == 0)
3633 // SetLastError is handled by stub
3634 PInvokeStaticSigInfo sigInfo(pMD);
3635 if (sigInfo.GetLinkFlags() & nlfLastError)
3638 // LCID argument is handled by stub
3639 if (GetLCIDParameterIndex(pMD) != -1)
3642 // making sure that cctor has run may be handled by stub
3643 if (pMD->IsNDirect() && ((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
3646 callConv = sigInfo.GetCallConv();
3651 PREFIX_ASSUME(pMD != NULL);
3653 pSig = pMD->GetSig();
3654 pModule = pMD->GetModule();
3657 // Check to make certain that the signature only contains types that marshal trivially
3658 SigPointer ptr(pSig);
3659 IfFailThrow(ptr.GetCallingConvInfo(NULL));
3661 IfFailThrow(ptr.GetData(&numArgs));
3662 numArgs++; // +1 for return type
3664 // We'll need to parse parameter native types
3665 mdParamDef *pParamTokenArray = (mdParamDef *)_alloca(numArgs * sizeof(mdParamDef));
3666 IMDInternalImport *pMDImport = pModule->GetMDImport();
3668 SigTypeContext emptyTypeContext;
3670 mdMethodDef methodToken = mdMethodDefNil;
3673 methodToken = pMD->GetMemberDef();
3675 CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
3677 for (ULONG i = 0; i < numArgs; i++)
3679 SigPointer arg = ptr;
3680 CorElementType type;
3681 IfFailThrow(arg.PeekElemType(&type));
3685 case ELEMENT_TYPE_PTR:
3687 IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR
3688 IfFailThrow(arg.PeekElemType(&type));
3690 if (type == ELEMENT_TYPE_VALUETYPE)
3692 if ((arg.HasCustomModifier(pModule,
3693 "Microsoft.VisualC.NeedsCopyConstructorModifier",
3694 ELEMENT_TYPE_CMOD_REQD)) ||
3695 (arg.HasCustomModifier(pModule,
3696 "System.Runtime.CompilerServices.IsCopyConstructed",
3697 ELEMENT_TYPE_CMOD_REQD)))
3702 if (i > 0) dwStackSize += sizeof(SLOT);
3706 case ELEMENT_TYPE_INTERNAL:
3708 // this check is not functional in DAC and provides no security against a malicious dump
3709 // the DAC is prepared to receive an invalid type handle
3710 #ifndef DACCESS_COMPILE
3711 if (pModule->IsSigInIL(arg.GetPtr()))
3712 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
3717 case ELEMENT_TYPE_VALUETYPE:
3719 TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext);
3721 // JIT can handle internal blittable value types
3722 if (!hndArgType.IsBlittable() && !hndArgType.IsEnum())
3727 // return value is fine as long as it can be normalized to an integer
3730 CorElementType normalizedType = hndArgType.GetInternalCorElementType();
3731 if (normalizedType == ELEMENT_TYPE_VALUETYPE)
3733 // it is a structure even after normalization
3739 dwStackSize += StackElemSize(hndArgType.GetSize());
3744 case ELEMENT_TYPE_BOOLEAN:
3745 case ELEMENT_TYPE_CHAR:
3747 // Bool requires marshaling
3748 // Char may require marshaling (MARSHAL_TYPE_ANSICHAR)
3754 if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
3756 if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
3760 // other non-primitive type - requires marshaling
3766 // check for explicit MarshalAs
3767 NativeTypeParamInfo paramInfo;
3769 if (pParamTokenArray[i] != mdParamDefNil)
3771 if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, ¶mInfo) ||
3772 paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT)
3774 // Presence of MarshalAs does not necessitate marshaling (it could as well be the default
3775 // for the type), but it's a good enough heuristic. We definitely don't want to duplicate
3776 // the logic from code:MarshalInfo.MarshalInfo here.
3781 IfFailThrow(ptr.SkipExactlyOne());
3784 if (!FitsInU2(dwStackSize))
3787 // do not set the stack size for varargs - the number is call site specific
3788 if (pMD != NULL && !pMD->IsVarArg())
3790 if (pMD->IsNDirect())
3792 ((NDirectMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize), callConv);
3794 #ifdef FEATURE_COMINTEROP
3795 else if (pMD->IsComPlusCall())
3797 // calling convention is always stdcall
3798 ((ComPlusCallMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize));
3800 #endif // FEATURE_COMINTEROP
3807 // factorization of CreateNDirectStubWorker
3808 static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig,
3810 CorNativeLinkType nlType,
3811 CorNativeLinkFlags nlFlags,
3812 UINT argidx, // this is used for reverse pinvoke hresult swapping
3818 UINT& nativeStackOffset,
3819 bool& fStubNeedsCOM,
3821 DEBUG_ARG(LPCUTF8 pDebugName)
3822 DEBUG_ARG(LPCUTF8 pDebugClassName)
3829 PRECONDITION(CheckPointer(params));
3830 PRECONDITION(CheckPointer(pss));
3831 PRECONDITION(CheckPointer(pMD, NULL_OK));
3835 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3837 MarshalInfo::MarshalScenario ms;
3838 #ifdef FEATURE_COMINTEROP
3839 if (SF_IsCOMStub(dwStubFlags))
3841 if (SF_IsWinRTStub(dwStubFlags))
3842 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3844 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3847 #endif // FEATURE_COMINTEROP
3849 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
3852 #ifdef FEATURE_COMINTEROP
3853 if (SF_IsWinRTCtorStub(dwStubFlags))
3855 _ASSERTE(msig.GetReturnType() == ELEMENT_TYPE_VOID);
3856 _ASSERTE(SF_IsHRESULTSwapping(dwStubFlags));
3858 pss->MarshalFactoryReturn();
3859 nativeStackOffset += sizeof(LPVOID);
3860 if (SF_IsWinRTCompositionStub(dwStubFlags))
3862 nativeStackOffset += 2 * sizeof(LPVOID);
3866 #endif // FEATURE_COMINTEROP
3867 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
3869 MarshalInfo returnInfo(msig.GetModule(),
3870 msig.GetReturnProps(),
3871 msig.GetSigTypeContext(),
3878 msig.NumFixedArgs(),
3879 SF_IsBestFit(dwStubFlags),
3880 SF_IsThrowOnUnmappableChar(dwStubFlags),
3884 DEBUG_ARG(pDebugName)
3885 DEBUG_ARG(pDebugClassName)
3889 marshalType = returnInfo.GetMarshalType();
3891 fStubNeedsCOM |= returnInfo.MarshalerRequiresCOM();
3893 #ifdef FEATURE_COMINTEROP
3894 if (marshalType == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3896 // Hidden length arrays are only valid with HRESULT swapping
3897 if (!SF_IsHRESULTSwapping(dwStubFlags))
3899 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3902 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3903 returnInfo.SetHiddenLengthParamIndex(static_cast<UINT16>(nativeArgIndex));
3905 // Inject the hidden argument so that it winds up at the end of the method signature
3906 pss->MarshalHiddenLengthArgument(&returnInfo, TRUE);
3907 nativeStackOffset += returnInfo.GetHiddenLengthParamStackSize();
3909 if (SF_IsReverseStub(dwStubFlags))
3915 if (SF_IsCOMStub(dwStubFlags))
3917 if (marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS ||
3918 marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3919 marshalType == MarshalInfo::MARSHAL_TYPE_GUID ||
3920 marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL)
3922 #ifndef _TARGET_X86_
3923 // We cannot optimize marshalType to MARSHAL_TYPE_GENERIC_* because the JIT works with exact types
3924 // and would refuse to compile the stub if it implicitly converted between scalars and value types (also see
3925 // code:MarshalInfo.MarhalInfo where we do the optimization on x86). We want to throw only if the structure
3926 // is too big to be returned in registers.
3927 if (marshalType != MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3928 IsUnmanagedValueTypeReturnedByRef(returnInfo.GetNativeArgSize()))
3929 #endif // _TARGET_X86_
3931 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3933 // Note that this limitation is very likely not needed anymore and could be lifted if we care.
3934 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3938 pss->MarshalReturn(&returnInfo, argOffset);
3942 // We don't support native methods that return VARIANTs directly.
3943 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT)
3945 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3947 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3951 pss->MarshalReturn(&returnInfo, argOffset);
3955 #endif // FEATURE_COMINTEROP
3957 if (marshalType > MarshalInfo::MARSHAL_TYPE_DOUBLE && IsUnsupportedValueTypeReturn(msig))
3959 if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
3960 || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
3961 || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
3962 #ifdef FEATURE_COMINTEROP
3963 || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
3964 #endif // FEATURE_COMINTEROP
3967 if (SF_IsHRESULTSwapping(dwStubFlags))
3969 // V1 restriction: we could implement this but it's late in the game to do so.
3970 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3973 else if (marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF)
3975 COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION);
3979 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3983 #ifdef FEATURE_COMINTEROP
3984 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
3986 // No support for returning variants. This is a V1 restriction, due to the late date,
3987 // don't want to add the special-case code to support this in light of low demand.
3988 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NOVARIANTRETURN);
3990 #endif // FEATURE_COMINTEROP
3992 pss->MarshalReturn(&returnInfo, argOffset);
3999 static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
4001 LIMITED_METHOD_CONTRACT;
4005 // -1 means that the argument is not on the stack
4006 return (stackSize >= sizeof(SLOT) ? (stackSize - sizeof(SLOT)) : (UINT)-1);
4008 #endif // _TARGET_X86_
4012 #ifdef FEATURE_COMINTEROP
4014 struct HiddenParameterInfo
4016 MarshalInfo *pManagedParam; // Managed parameter which required the hidden parameter
4017 int nativeIndex; // 0 based index into the native method signature where the hidden parameter should be injected
4020 // Get the indexes of any hidden length parameters to be marshaled for the method
4022 // At return, each value in the ppParamIndexes array is a 0 based index into the native method signature where
4023 // the length parameter for a hidden length array should be passed. The MarshalInfo objects will also be
4024 // updated such that they all have explicit marshaling information.
4026 // The caller is responsible for freeing the memory pointed to by ppParamIndexes
4027 void CheckForHiddenParameters(DWORD cParamMarshalInfo,
4028 __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo,
4029 __out DWORD *pcHiddenNativeParameters,
4030 __out HiddenParameterInfo **ppHiddenNativeParameters)
4035 PRECONDITION(CheckPointer(pParamMarshalInfo));
4036 PRECONDITION(CheckPointer(pcHiddenNativeParameters));
4037 PRECONDITION(CheckPointer(ppHiddenNativeParameters));
4041 NewArrayHolder<HiddenParameterInfo> hiddenParamInfo(new HiddenParameterInfo[cParamMarshalInfo]);
4042 DWORD foundInfoCount = 0;
4044 for (DWORD iParam = 0; iParam < cParamMarshalInfo; ++iParam)
4046 // Look for hidden length arrays, which all require additional parameters to be added
4047 if (pParamMarshalInfo[iParam].GetMarshalType() == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
4049 DWORD currentNativeIndex = iParam + foundInfoCount;
4051 // The location of the length parameter is implicitly just before the array pointer.
4052 // We'll give it our current index, and bumping the found count will push us back a slot.
4054 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
4055 pParamMarshalInfo[iParam].SetHiddenLengthParamIndex(static_cast<UINT16>(currentNativeIndex));
4057 hiddenParamInfo[foundInfoCount].nativeIndex = pParamMarshalInfo[iParam].HiddenLengthParamIndex();
4058 hiddenParamInfo[foundInfoCount].pManagedParam = &(pParamMarshalInfo[iParam]);
4063 *pcHiddenNativeParameters = foundInfoCount;
4064 *ppHiddenNativeParameters = hiddenParamInfo.Extract();
4067 bool IsHiddenParameter(int nativeArgIndex,
4068 DWORD cHiddenParameters,
4069 __in_ecount(cHiddenParameters) HiddenParameterInfo *pHiddenParameters,
4070 __out HiddenParameterInfo **ppHiddenParameterInfo)
4075 PRECONDITION(cHiddenParameters == 0 || CheckPointer(pHiddenParameters));
4076 PRECONDITION(CheckPointer(ppHiddenParameterInfo));
4080 *ppHiddenParameterInfo = NULL;
4082 for (DWORD i = 0; i < cHiddenParameters; ++i)
4084 _ASSERTE(pHiddenParameters[i].nativeIndex != -1);
4085 if (pHiddenParameters[i].nativeIndex == nativeArgIndex)
4087 *ppHiddenParameterInfo = &(pHiddenParameters[i]);
4095 #endif // FEATURE_COMINTEROP
4097 //---------------------------------------------------------
4098 // Creates a new stub for a N/Direct call. Return refcount is 1.
4099 // Note that this function may now throw if it fails to create
4101 //---------------------------------------------------------
4102 static void CreateNDirectStubWorker(StubState* pss,
4103 StubSigDesc* pSigDesc,
4104 CorNativeLinkType nlType,
4105 CorNativeLinkFlags nlFlags,
4106 CorPinvokeMap unmgdCallConv,
4109 mdParamDef* pParamTokenArray,
4117 PRECONDITION(CheckPointer(pss));
4118 PRECONDITION(CheckPointer(pSigDesc));
4119 PRECONDITION(CheckPointer(pMD, NULL_OK));
4120 PRECONDITION(!pMD || pMD->IsILStub() || (0 != pMD->GetMethodTable()->IsDelegate()) == SF_IsDelegateStub(dwStubFlags));
4124 SF_ConsistencyCheck(dwStubFlags);
4127 if (g_pConfig->ShouldBreakOnInteropStubSetup(pSigDesc->m_pDebugName))
4128 CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName));
4133 if (SF_IsCOMStub(dwStubFlags))
4135 _ASSERTE(0 == nlType);
4136 _ASSERTE(0 == nlFlags);
4137 _ASSERTE(0 == unmgdCallConv);
4141 _ASSERTE(nlType == nltAnsi || nlType == nltUnicode);
4143 Module *pModule = pSigDesc->m_pModule;
4146 // Set up signature walking objects.
4149 MetaSig msig(pSigDesc->m_sig,
4151 &pSigDesc->m_typeContext);
4153 if (SF_IsVarArgStub(dwStubFlags))
4154 msig.SetTreatAsVarArg();
4156 bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
4158 pss->SetLastError(nlFlags & nlfLastError);
4160 // This has been in the product since forward P/Invoke via delegates was
4161 // introduced. It's wrong, but please keep it for backward compatibility.
4162 if (SF_IsDelegateStub(dwStubFlags))
4163 pss->SetLastError(TRUE);
4165 pss->BeginEmit(dwStubFlags);
4169 // LCID is not supported on WinRT
4170 _ASSERTE(!SF_IsWinRTStub(dwStubFlags));
4172 // The code to handle the LCID will call MarshalLCID before calling MarshalArgument
4173 // on the argument the LCID should go after. So we just bump up the index here.
4177 int numArgs = msig.NumFixedArgs();
4179 // thiscall must have at least one parameter (the "this")
4180 if (fThisCall && numArgs == 0)
4181 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4184 // Now, emit the IL.
4189 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
4192 // Marshal the return value.
4195 UINT nativeStackSize = (SF_IsCOMStub(dwStubFlags) ? sizeof(SLOT) : 0);
4196 bool fHasCopyCtorArgs = false;
4197 bool fStubNeedsCOM = SF_IsCOMStub(dwStubFlags);
4199 // Normally we would like this to be false so that we use the correct signature
4200 // in the IL_STUB, (i.e if it returns a value class then the signature will use that)
4201 // When this bool is true we change the return type to void and explicitly add a
4202 // return buffer argument as the first argument.
4203 BOOL fMarshalReturnValueFirst = false;
4205 // We can only change fMarshalReturnValueFirst to true when we are NOT doing HRESULT-swapping!
4207 if (!SF_IsHRESULTSwapping(dwStubFlags))
4210 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
4211 // JIT32 has problems in generating code for pinvoke ILStubs which do a return in return buffer.
4212 // Therefore instead we change the signature of calli to return void and make the return buffer as first
4213 // argument. This matches the ABI i.e. return buffer is passed as first arg. So native target will get the
4214 // return buffer in correct register.
4215 // The return structure secret arg comes first, however byvalue return is processed at
4216 // the end because it could be the HRESULT-swapped argument which always comes last.
4217 fMarshalReturnValueFirst = HasRetBuffArg(&msig);
4220 #if defined(_TARGET_AMD64_) && defined(_WIN64) && !defined(FEATURE_CORECLR)
4221 // JIT64 (which is only used on the Windows Desktop CLR) has a problem generating code
4222 // for the pinvoke ILStubs which do a return using a struct type. Therefore, we
4223 // change the signature of calli to return void and make the return buffer as first argument.
4224 // This matches the ABI i.e. return buffer is passed as first arg. So native target will get
4225 // the return buffer in correct register.
4226 // Ideally we only want to set it for JIT64 and not ryujit but currently there isn't a fast way
4227 // to determine that at runtime.
4228 fMarshalReturnValueFirst = HasRetBuffArg(&msig);
4232 if (fMarshalReturnValueFirst)
4234 marshalType = DoMarshalReturnValue(msig,
4247 DEBUG_ARG(pSigDesc->m_pDebugName)
4248 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4251 if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE ||
4252 marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY ||
4253 marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET ||
4254 marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF ||
4255 marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
4256 #ifdef FEATURE_COMINTEROP
4257 || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
4258 #endif // FEATURE_COMINTEROP
4261 // These are special non-blittable types returned by-ref in managed,
4262 // but marshaled as primitive values returned by-value in unmanaged.
4266 // This is an ordinary value type - see if it is returned by-ref.
4267 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4268 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4270 nativeStackSize += sizeof(LPVOID);
4276 // Marshal the arguments
4278 MarshalInfo::MarshalScenario ms;
4279 #ifdef FEATURE_COMINTEROP
4280 if (SF_IsCOMStub(dwStubFlags))
4282 if (SF_IsWinRTStub(dwStubFlags))
4283 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
4285 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
4288 #endif // FEATURE_COMINTEROP
4290 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
4293 // Build up marshaling information for each of the method's parameters
4294 SIZE_T cbParamMarshalInfo;
4295 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(MarshalInfo), numArgs, cbParamMarshalInfo))
4297 COMPlusThrowHR(COR_E_OVERFLOW);
4300 NewArrayHolder<BYTE> pbParamMarshalInfo(new BYTE[cbParamMarshalInfo]);
4301 MarshalInfo *pParamMarshalInfo = reinterpret_cast<MarshalInfo *>(pbParamMarshalInfo.GetValue());
4303 MetaSig paramInfoMSig(msig);
4304 for (int i = 0; i < numArgs; ++i)
4306 paramInfoMSig.NextArg();
4307 new(&(pParamMarshalInfo[i])) MarshalInfo(paramInfoMSig.GetModule(),
4308 paramInfoMSig.GetArgProps(),
4309 paramInfoMSig.GetSigTypeContext(),
4310 pParamTokenArray[i + 1],
4317 SF_IsBestFit(dwStubFlags),
4318 SF_IsThrowOnUnmappableChar(dwStubFlags),
4322 DEBUG_ARG(pSigDesc->m_pDebugName)
4323 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4327 #ifdef FEATURE_COMINTEROP
4328 // Check to see if we need to inject any additional hidden parameters
4329 DWORD cHiddenNativeParameters;
4330 NewArrayHolder<HiddenParameterInfo> pHiddenNativeParameters;
4331 CheckForHiddenParameters(numArgs, pParamMarshalInfo, &cHiddenNativeParameters, &pHiddenNativeParameters);
4333 // Hidden parameters and LCID do not mix
4334 _ASSERTE(!(cHiddenNativeParameters > 0 && iLCIDArg != -1));
4335 #endif // FEATURE_COMINTEROP
4337 // Marshal the parameters
4339 int nativeArgIndex = 0;
4340 while (argidx <= numArgs)
4342 #ifdef FEATURE_COMINTEROP
4343 HiddenParameterInfo *pHiddenParameter;
4344 // Check to see if we need to inject a hidden parameter
4345 if (IsHiddenParameter(nativeArgIndex, cHiddenNativeParameters, pHiddenNativeParameters, &pHiddenParameter))
4347 pss->MarshalHiddenLengthArgument(pHiddenParameter->pManagedParam, FALSE);
4348 nativeStackSize += pHiddenParameter->pManagedParam->GetHiddenLengthParamStackSize();
4350 if (SF_IsReverseStub(dwStubFlags))
4356 #endif // FEATURE_COMINTEROP
4359 // Check to see if this is the parameter after which we need to insert the LCID.
4361 if (argidx == iLCIDArg)
4363 pss->MarshalLCID(argidx);
4364 nativeStackSize += sizeof(LPVOID);
4366 if (SF_IsReverseStub(dwStubFlags))
4372 MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4374 #ifdef FEATURE_COMINTEROP
4375 // For the hidden-length array, length parameters must occur before the parameter containing the array pointer
4376 _ASSERTE(info.GetMarshalType() != MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY || nativeArgIndex > info.HiddenLengthParamIndex());
4377 #endif // FEATURE_COMINTEROP
4379 pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4380 nativeStackSize += info.GetNativeArgSize();
4382 fStubNeedsCOM |= info.MarshalerRequiresCOM();
4384 if (fThisCall && argidx == 1)
4386 // make sure that the first parameter is enregisterable
4387 if (info.GetNativeArgSize() > sizeof(SLOT))
4388 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4391 #ifndef FEATURE_CORECLR
4392 if (info.GetMarshalType() == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR)
4394 fHasCopyCtorArgs = true;
4396 #endif // !FEATURE_CORECLR
4404 // Check to see if this is the parameter after which we need to insert the LCID.
4405 if (argidx == iLCIDArg)
4407 pss->MarshalLCID(argidx);
4408 nativeStackSize += sizeof(LPVOID);
4410 if (SF_IsReverseStub(dwStubFlags))
4414 if (!fMarshalReturnValueFirst)
4416 // This could be a HRESULT-swapped argument so it must come last.
4417 marshalType = DoMarshalReturnValue(msig,
4430 DEBUG_ARG(pSigDesc->m_pDebugName)
4431 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4434 // If the return value is a SafeHandle or CriticalHandle, mark the stub method.
4435 // Interop methods that use this stub will have an implicit reliability contract
4436 // (see code:TAStackCrawlCallBack).
4437 if (!SF_IsHRESULTSwapping(dwStubFlags))
4439 if (marshalType == MarshalInfo::MARSHAL_TYPE_SAFEHANDLE ||
4440 marshalType == MarshalInfo::MARSHAL_TYPE_CRITICALHANDLE)
4442 if (pMD->IsDynamicMethod())
4443 pMD->AsDynamicMethodDesc()->SetUnbreakable(true);
4448 if (SF_IsHRESULTSwapping(dwStubFlags))
4450 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
4451 nativeStackSize += sizeof(LPVOID);
4454 if (pMD->IsDynamicMethod())
4456 // Set the native stack size to the IL stub MD. It is needed for alignment
4457 // thunk generation on the Mac and stdcall name decoration on Windows.
4458 // We do not store it directly in the interop MethodDesc here because due
4459 // to sharing we come here only for the first call with given signature and
4460 // the target MD may even be NULL.
4465 _ASSERTE(nativeStackSize >= sizeof(SLOT));
4466 nativeStackSize -= sizeof(SLOT);
4468 #else // _TARGET_X86_
4470 // The algorithm to compute nativeStackSize on the fly is x86-specific.
4471 // Recompute the correct size for other platforms from the stub signature.
4473 if (SF_IsForwardStub(dwStubFlags))
4475 // It would be nice to compute the correct value for forward stubs too.
4476 // The value is only used in MarshalNative::NumParamBytes right now,
4477 // and changing what MarshalNative::NumParamBytes returns is
4478 // a potential breaking change.
4482 // native stack size is updated in code:ILStubState.SwapStubSignatures
4484 #endif // _TARGET_X86_
4486 if (!FitsInU2(nativeStackSize))
4487 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
4489 DynamicMethodDesc *pDMD = pMD->AsDynamicMethodDesc();
4491 pDMD->SetNativeStackArgSize(static_cast<WORD>(nativeStackSize));
4492 pDMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
4493 pDMD->SetStubNeedsCOMStarted(fStubNeedsCOM);
4496 // FinishEmit needs to know the native stack arg size so we call it after the number
4497 // has been set in the stub MD (code:DynamicMethodDesc.SetNativeStackArgSize)
4498 pss->FinishEmit(pMD);
4501 class NDirectStubHashBlob : public ILStubHashBlobBase
4506 WORD m_unmgdCallConv;
4507 BYTE m_nlType; // C_ASSERTS are in NDirect::CreateHashBlob
4514 BYTE m_rgbSigAndParamData[1];
4515 // (dwParamAttr, cbNativeType) // length: number of parameters
4516 // NativeTypeBlob // length: number of parameters
4517 // BYTE m_rgbSigData[]; // length: determined by sig walk
4520 // For better performance and less memory fragmentation,
4521 // I'm using structure here to avoid allocating 3 different arrays.
4526 PCCOR_SIGNATURE pvNativeType;
4529 ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams)
4531 STANDARD_VM_CONTRACT;
4533 NDirectStubHashBlob* pBlob;
4535 IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport();
4537 CQuickBytes paramInfoBytes;
4538 paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens);
4539 ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr();
4540 ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens);
4542 size_t cbNativeTypeTotal = 0;
4545 // Collect information for function parameters
4547 for (int idx = 0; idx < pParams->m_nParamTokens; idx++)
4549 mdParamDef token = pParams->m_pParamTokenArray[idx];
4550 if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token)
4552 USHORT usSequence_Ignore; // We don't need usSequence in the hash as the param array is already sorted
4553 LPCSTR szParamName_Ignore;
4554 IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, ¶mInfos[idx].dwParamAttr, &szParamName_Ignore));
4556 if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal)
4558 IfFailThrow(pInternalImport->GetFieldMarshal(token, ¶mInfos[idx].pvNativeType, ¶mInfos[idx].cbNativeType));
4559 cbNativeTypeTotal += paramInfos[idx].cbNativeType;
4564 SigPointer sigPtr = pParams->m_sig.CreateSigPointer();
4566 // note that ConvertToInternalSignature also resolves generics so different instantiations will get different
4567 // hash blobs for methods that have generic parameters in their signature
4568 SigBuilder sigBuilder;
4569 sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE);
4572 PVOID pSig = sigBuilder.GetSignature(&cbSig);
4575 // Build hash blob for IL stub sharing
4577 S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) +
4578 S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) + // Parameter attributes
4579 S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) + // Native type blob size
4580 S_SIZE_T(cbNativeTypeTotal) + // Native type blob data
4581 S_SIZE_T(cbSig); // Signature
4583 if (cbSizeOfBlob.IsOverflow())
4584 COMPlusThrowHR(COR_E_OVERFLOW);
4586 static_assert_no_msg(nltMaxValue <= 0xFF);
4587 static_assert_no_msg(nlfMaxValue <= 0xFF);
4588 static_assert_no_msg(pmMaxValue <= 0xFFFF);
4590 NewArrayHolder<BYTE> pBytes = new BYTE[cbSizeOfBlob.Value()];
4591 // zero out the hash bytes to ensure all bit fields are deterministically set
4592 ZeroMemory(pBytes, cbSizeOfBlob.Value());
4593 pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes;
4595 pBlob->m_pModule = NULL;
4597 if (SF_IsNGENedStub(pParams->m_dwStubFlags))
4599 // don't share across modules if we are ngening the stub
4600 pBlob->m_pModule = pParams->m_pModule;
4603 pBlob->m_cbSizeOfBlob = cbSizeOfBlob.Value();
4604 pBlob->m_unmgdCallConv = static_cast<WORD>(pParams->m_unmgdCallConv);
4605 pBlob->m_nlType = static_cast<BYTE>(pParams->m_nlType);
4606 pBlob->m_nlFlags = static_cast<BYTE>(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub
4607 pBlob->m_iLCIDArg = pParams->m_iLCIDArg;
4609 pBlob->m_StubFlags = pParams->m_dwStubFlags;
4610 pBlob->m_nParams = pParams->m_nParamTokens;
4612 BYTE* pBlobParams = &pBlob->m_rgbSigAndParamData[0];
4615 // Write (dwParamAttr, cbNativeType) for parameters
4617 // Note that these need to be aligned and it is why they are written before the byte blobs
4618 // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs
4620 _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0);
4621 _ASSERTE(sizeof(DWORD) == sizeof(ULONG));
4623 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4625 // We only care about In/Out/HasFieldMarshal
4626 // Other attr are about optional/default values which are not used in marshalling,
4627 // but only used in compilers
4628 *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal);
4629 pBlobParams += sizeof(DWORD);
4631 *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType;
4632 pBlobParams += sizeof(ULONG);
4636 // Write native type blob for parameters
4638 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4640 memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType);
4641 pBlobParams += paramInfos[i].cbNativeType;
4647 memcpy(pBlobParams, pSig, cbSig);
4649 // Verify that we indeed have reached the end
4650 _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value());
4652 pBytes.SuppressRelease();
4653 return (ILStubHashBlob*)pBlob;
4657 ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams)
4667 // Use the m_pLoaderModule instead of m_pModule
4668 // They could be different for methods on generic types.
4669 return pParams->m_pLoaderModule->GetILStubCache();
4673 MethodDesc* NDirect::GetStubMethodDesc(
4674 MethodDesc *pTargetMD,
4675 NDirectStubParameters* pParams,
4676 ILStubHashBlob* pHashParams,
4677 AllocMemTracker* pamTracker,
4678 bool& bILStubCreator,
4679 MethodDesc* pLastMD)
4681 CONTRACT(MethodDesc*)
4685 PRECONDITION(CheckPointer(pParams));
4686 PRECONDITION(!pParams->m_sig.IsEmpty());
4687 PRECONDITION(CheckPointer(pParams->m_pModule));
4688 PRECONDITION(CheckPointer(pTargetMD, NULL_OK));
4689 POSTCONDITION(CheckPointer(RETVAL));
4695 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4697 pMD = pCache->GetStubMethodDesc(pTargetMD,
4699 pParams->m_dwStubFlags,
4701 pParams->m_sig.GetRawSig(),
4702 pParams->m_sig.GetRawSigLen(),
4712 void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams)
4718 PRECONDITION(CheckPointer(pParams));
4719 PRECONDITION(CheckPointer(pHashParams));
4720 PRECONDITION(!pParams->m_sig.IsEmpty());
4721 PRECONDITION(CheckPointer(pParams->m_pModule));
4725 LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams));
4727 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4729 pCache->DeleteEntry(pHashParams);
4733 void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD)
4739 PRECONDITION(CheckPointer(pParams));
4740 PRECONDITION(!pParams->m_sig.IsEmpty());
4741 PRECONDITION(CheckPointer(pParams->m_pModule));
4745 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4747 pCache->AddMethodDescChunkWithLockTaken(pMD);
4751 // Additional factorization of CreateNDirectStub. This hoists all the metadata accesses
4752 // into one location so that we can leave CreateNDirectStubWorker to just generate the
4753 // IL. This allows us to cache a stub based on the inputs to CreateNDirectStubWorker
4754 // instead of having to generate the IL first before doing the caching.
4756 void CreateNDirectStubAccessMetadata(StubSigDesc* pSigDesc, // IN
4757 CorPinvokeMap unmgdCallConv, // IN
4758 DWORD* pdwStubFlags, // IN/OUT
4759 int* piLCIDArg, // OUT
4760 int* pNumArgs // OUT
4763 STANDARD_VM_CONTRACT;
4765 if (SF_IsCOMStub(*pdwStubFlags))
4767 _ASSERTE(0 == unmgdCallConv);
4771 if (unmgdCallConv != pmCallConvStdcall &&
4772 unmgdCallConv != pmCallConvCdecl &&
4773 unmgdCallConv != pmCallConvThiscall)
4775 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
4779 #ifdef FEATURE_COMINTEROP
4780 if (SF_IsDelegateStub(*pdwStubFlags))
4782 _ASSERTE(!SF_IsWinRTStub(*pdwStubFlags));
4783 if (pSigDesc->m_pMD->GetMethodTable()->IsProjectedFromWinRT())
4785 // We do not allow P/Invoking via WinRT delegates to better segregate WinRT
4786 // from classic interop scenarios.
4787 COMPlusThrow(kMarshalDirectiveException, IDS_EE_DELEGATEPINVOKE_WINRT);
4790 #endif // FEATURE_COMINTEROP
4792 MetaSig msig(pSigDesc->m_sig,
4793 pSigDesc->m_pModule,
4794 &pSigDesc->m_typeContext);
4796 if (SF_IsVarArgStub(*pdwStubFlags))
4797 msig.SetTreatAsVarArg();
4799 (*pNumArgs) = msig.NumFixedArgs();
4801 IMDInternalImport* pInternalImport = pSigDesc->m_pModule->GetMDImport();
4803 _ASSERTE(!SF_IsHRESULTSwapping(*pdwStubFlags));
4805 mdMethodDef md = pSigDesc->m_tkMethodDef;
4806 if (md != mdMethodDefNil)
4808 DWORD dwDescrOffset;
4810 IfFailThrow(pInternalImport->GetMethodImplProps(
4815 #ifdef FEATURE_COMINTEROP
4816 if (SF_IsWinRTStub(*pdwStubFlags))
4818 // All WinRT methods do HRESULT swapping
4819 if (IsMiPreserveSig(dwImplFlags))
4821 COMPlusThrow(kMarshalDirectiveException, IDS_EE_PRESERVESIG_WINRT);
4824 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4827 #endif // FEATURE_COMINTEROP
4828 if (SF_IsReverseStub(*pdwStubFlags))
4830 // only COM-to-CLR call supports hresult swapping in the reverse direction
4831 if (SF_IsCOMStub(*pdwStubFlags) && !IsMiPreserveSig(dwImplFlags))
4833 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4838 // fwd pinvoke, fwd com interop support hresult swapping.
4839 // delegate to an unmanaged method does not.
4840 if (!IsMiPreserveSig(dwImplFlags) && !SF_IsDelegateStub(*pdwStubFlags))
4842 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4847 if (pSigDesc->m_pMD != NULL)
4849 (*piLCIDArg) = GetLCIDParameterIndex(pSigDesc->m_pMD);
4856 // Check to see if we need to do LCID conversion.
4857 if ((*piLCIDArg) != -1 && (*piLCIDArg) > (*pNumArgs))
4859 COMPlusThrow(kIndexOutOfRangeException, IDS_EE_INVALIDLCIDPARAM);
4862 if (SF_IsCOMStub(*pdwStubFlags) && !SF_IsWinRTStaticStub(*pdwStubFlags))
4864 CONSISTENCY_CHECK(msig.HasThis());
4868 if (msig.HasThis() && !SF_IsDelegateStub(*pdwStubFlags))
4870 COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC);
4875 void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError /*= TRUE*/)
4877 if (pNMD->IsSynchronized() && throwOnError)
4878 COMPlusThrow(kTypeLoadException, IDS_EE_NOSYNCHRONIZED);
4880 WORD ndirectflags = 0;
4881 if (pNMD->MethodDesc::IsVarArg())
4882 ndirectflags |= NDirectMethodDesc::kVarArgs;
4884 LPCUTF8 szLibName = NULL, szEntryPointName = NULL;
4885 new (pSigInfo) PInvokeStaticSigInfo(pNMD, &szLibName, &szEntryPointName,
4886 (throwOnError ? PInvokeStaticSigInfo::THROW_ON_ERROR : PInvokeStaticSigInfo::NO_THROW_ON_ERROR));
4888 if (pSigInfo->GetCharSet() == nltAnsi)
4889 ndirectflags |= NDirectMethodDesc::kNativeAnsi;
4891 CorNativeLinkFlags linkflags = pSigInfo->GetLinkFlags();
4892 if (linkflags & nlfLastError)
4893 ndirectflags |= NDirectMethodDesc::kLastError;
4894 if (linkflags & nlfNoMangle)
4895 ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
4897 CorPinvokeMap callConv = pSigInfo->GetCallConv();
4898 if (callConv == pmCallConvStdcall)
4899 ndirectflags |= NDirectMethodDesc::kStdCall;
4900 if (callConv == pmCallConvThiscall)
4901 ndirectflags |= NDirectMethodDesc::kThisCall;
4903 if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
4905 ndirectflags |= NDirectMethodDesc::kIsQCall;
4909 EnsureWritablePages(&pNMD->ndirect);
4910 pNMD->ndirect.m_pszLibName = szLibName;
4911 pNMD->ndirect.m_pszEntrypointName = szEntryPointName;
4915 if (ndirectflags & NDirectMethodDesc::kStdCall)
4917 // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling.
4919 ArgIterator argit(&msig);
4920 if (argit.HasRetBuffArg())
4922 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4923 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4925 ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf;
4929 #endif // _TARGET_X86_
4931 // Call this exactly ONCE per thread. Do not publish incomplete prestub flags
4932 // or you will introduce a race condition.
4933 pNMD->InterlockedSetNDirectFlags(ndirectflags);
4936 #ifdef FEATURE_COMINTEROP
4937 // Find the MethodDesc of the predefined IL stub method by either
4938 // 1) looking at redirected adapter interfaces, OR
4939 // 2) looking at special attributes for the specific interop scenario (specified by dwStubFlags).
4940 // Currently only ManagedToNativeComInteropStubAttribute is supported.
4941 // It returns NULL if no such attribute(s) can be found.
4942 // But if the attribute is found and is invalid, or something went wrong in the looking up
4943 // process, an exception will be thrown. If everything goes well, you'll get the MethodDesc
4944 // of the stub method
4945 HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD)
4952 PRECONDITION(CheckPointer(pTargetMD));
4953 PRECONDITION(CheckPointer(ppRetStubMD));
4954 PRECONDITION(*ppRetStubMD == NULL);
4960 MethodTable *pTargetMT = pTargetMD->GetMethodTable();
4962 // Check if this is a redirected interface - we have static stubs in mscorlib for those.
4963 if (SF_IsForwardCOMStub(dwStubFlags) && pTargetMT->IsInterface())
4966 // Redirect generic redirected interfaces to the corresponding adapter methods in mscorlib
4967 if (pTargetMT->HasInstantiation())
4969 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(pTargetMD, TypeHandle::Interop_ManagedToNative);
4970 if (pAdapterMD != NULL)
4972 *ppRetStubMD = pAdapterMD;
4979 // Find out if we have the attribute
4984 // Support v-table forward classic COM interop calls only
4985 if (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags) && !SF_IsWinRTStub(dwStubFlags))
4987 if (pTargetMT->HasInstantiation())
4989 // ManagedToNativeComInteropStubAttribute is not supported with generics
4993 if (pTargetMD->IsFCall())
4995 // ManagedToNativeComInteropStubAttribute is not supported on FCalls (i.e. methods on legacy
4996 // interfaces forwarded to CustomMarshalers.dll such as IEnumerable::GetEnumerator)
4999 _ASSERTE(pTargetMD->IsComPlusCall());
5001 if (pTargetMD->IsInterface())
5003 _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
5004 hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
5005 pTargetMD->GetMemberDef(),
5006 FORWARD_INTEROP_STUB_METHOD_TYPE,
5012 // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
5013 // Translate that to E_FAIL
5014 else if (hr == S_FALSE)
5019 // We are dealing with the class, use the interface MD instead
5020 // After second thought I believe we don't need to check the class MD.
5021 // We can think stubs as part of public interface, and if the interface is public,
5022 // the stubs should also be accessible
5023 MethodDesc *pInterfaceMD = pTargetMD->GetInterfaceMD();
5026 hr = FindPredefinedILStubMethod(pInterfaceMD, dwStubFlags, ppRetStubMD);
5037 // Parse the attribute
5039 CustomAttributeParser parser(pBytes, cbBytes);
5040 IfFailRet(parser.SkipProlog());
5044 IfFailRet(parser.GetNonEmptyString(&pTypeName, &cbTypeName));
5046 LPCUTF8 pMethodName;
5048 IfFailRet(parser.GetNonEmptyString(&pMethodName, &cbMethodName));
5050 StackSString typeName(SString::Utf8, pTypeName, cbTypeName);
5051 StackSString methodName(SString::Utf8, pMethodName, cbMethodName);
5054 // Retrieve the type
5056 TypeHandle stubClassType;
5057 stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
5059 MethodTable *pStubClassMT = stubClassType.AsMethodTable();
5061 StackSString stubClassName;
5062 pStubClassMT->_GetFullyQualifiedNameForClassNestedAware(stubClassName);
5064 StackSString targetInterfaceName;
5065 pTargetMT->_GetFullyQualifiedNameForClassNestedAware(targetInterfaceName);
5067 // Restrict to same assembly only to reduce test cost
5068 if (stubClassType.GetAssembly() != pTargetMT->GetAssembly())
5072 IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY,
5073 stubClassName.GetUnicode(),
5074 targetInterfaceName.GetUnicode()
5078 if (stubClassType.HasInstantiation())
5082 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC,
5083 stubClassName.GetUnicode()
5087 if (stubClassType.IsInterface())
5091 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE,
5092 stubClassName.GetUnicode()
5097 // Locate the MethodDesc for the stub method
5099 MethodDesc *pStubMD = NULL;
5102 PCCOR_SIGNATURE pTargetSig = NULL;
5103 DWORD pcTargetSig = 0;
5105 SigTypeContext typeContext; // NO generics supported
5107 pTargetMD->GetSig(&pTargetSig, &pcTargetSig);
5109 MetaSig msig(pTargetSig,
5111 pTargetMD->GetModule(),
5113 _ASSERTE(msig.HasThis());
5115 SigBuilder stubSigBuilder;
5118 // Append calling Convention, NumOfArgs + 1,
5120 stubSigBuilder.AppendByte(msig.GetCallingConvention() & ~IMAGE_CEE_CS_CALLCONV_HASTHIS);
5121 stubSigBuilder.AppendData(msig.NumFixedArgs() + 1);
5124 // Append return type
5126 SigPointer pReturn = msig.GetReturnProps();
5127 LPBYTE pReturnTypeBegin = (LPBYTE)pReturn.GetPtr();
5128 IfFailThrow(pReturn.SkipExactlyOne());
5129 LPBYTE pReturnTypeEnd = (LPBYTE)pReturn.GetPtr();
5131 stubSigBuilder.AppendBlob(pReturnTypeBegin, pReturnTypeEnd - pReturnTypeBegin);
5136 stubSigBuilder.AppendElementType(ELEMENT_TYPE_CLASS);
5137 stubSigBuilder.AppendToken(pTargetMT->GetCl());
5140 // Copy rest of the arguments
5142 if (msig.NextArg() != ELEMENT_TYPE_END)
5144 SigPointer pFirstArg = msig.GetArgProps();
5145 LPBYTE pArgBegin = (LPBYTE) pFirstArg.GetPtr();
5146 LPBYTE pArgEnd = (LPBYTE) pTargetSig + pcTargetSig;
5148 stubSigBuilder.AppendBlob(pArgBegin, pArgEnd - pArgBegin);
5152 // Allocate new memory and copy over
5154 DWORD pcStubSig = 0;
5155 PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE) stubSigBuilder.GetSignature(&pcStubSig);
5158 // Find method using name + signature
5160 StackScratchBuffer buffer;
5161 LPCUTF8 szMethodNameUTF8 = methodName.GetUTF8(buffer);
5162 pStubMD = MemberLoader::FindMethod(stubClassType.GetMethodTable(),
5166 pTargetMT->GetModule());
5168 if (pStubMD == NULL)
5177 pTargetMD->GetMDImport(),
5180 // Unfortunately the PrettyPrintSig doesn't print 'static' when the function is static
5181 // so we need to append 'static' here. No need to localize
5182 SString signature(SString::Utf8, (LPCUTF8)"static ");
5183 signature.AppendUTF8((LPCUTF8) qbSig.Ptr());
5186 kMissingMethodException,
5187 IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING,
5188 signature.GetUnicode(),
5189 stubClassName.GetUnicode()
5196 // Check the Stub MD
5199 // Verify that the target interop method can call the stub method
5201 _ASSERTE(pTargetMD != NULL);
5203 StaticAccessCheckContext accessContext(pTargetMD, pTargetMT);
5205 if (!ClassLoader::CanAccess(
5208 stubClassType.GetAssembly(),
5209 pStubMD->GetAttrs(),
5213 StackSString interopMethodName(SString::Utf8, pTargetMD->GetName());
5216 kMethodAccessException,
5217 IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD,
5218 interopMethodName.GetUnicode(),
5219 methodName.GetUnicode()
5223 // The FindMethod call will make sure that it is static by matching signature.
5224 // So there is no need to check and throw
5225 _ASSERTE(pStubMD->IsStatic());
5227 *ppRetStubMD = pStubMD;
5231 #endif // FEATURE_COMINTEROP
5233 MethodDesc* CreateInteropILStub(
5235 StubSigDesc* pSigDesc,
5236 CorNativeLinkType nlType,
5237 CorNativeLinkFlags nlFlags,
5238 CorPinvokeMap unmgdCallConv,
5239 DWORD dwStubFlags, // NDirectStubFlags
5241 mdParamDef* pParamTokenArray,
5245 CONTRACT(MethodDesc*)
5249 PRECONDITION(CheckPointer(pSigDesc));
5250 POSTCONDITION(CheckPointer(RETVAL));
5255 ///////////////////////////////
5257 // MethodDesc creation
5259 ///////////////////////////////
5261 MethodDesc* pStubMD = NULL;
5263 Module* pModule = pSigDesc->m_pModule;
5264 Module* pLoaderModule = pSigDesc->m_pLoaderModule;
5265 MethodDesc* pTargetMD = pSigDesc->m_pMD;
5267 // pTargetMD may be null in the case of calli pinvoke
5268 // and vararg pinvoke.
5271 #ifdef FEATURE_COMINTEROP
5273 // Try to locate predefined IL stub either defined in user code or hardcoded in CLR
5274 // If there is one, use the pointed method as the stub.
5275 // Skip pTargetMD == NULL case for reverse interop calls
5277 if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD)))
5279 #ifndef CROSSGEN_COMPILE
5280 // We are about to execute method in pStubMD which could be in another module.
5281 // Call EnsureActive before make the call
5282 // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here
5283 pStubMD->EnsureActive();
5285 if (pStubMD->IsPreImplemented())
5286 RestoreNGENedStub(pStubMD);
5291 #endif // FEATURE_COMINTEROP
5293 // Otherwise, fall back to generating IL stub on-the-fly
5294 NDirectStubParameters params(pSigDesc->m_sig,
5295 &pSigDesc->m_typeContext,
5307 // The following two ILStubCreatorHelperHolder are to recover the status when an
5308 // exception happen during the generation of the IL stubs. We need to free the
5309 // memory allocated and restore the ILStubCache.
5311 // The following block is logically divided into two phases. The first phase is
5312 // CreateOrGet IL Stub phase which we take a domain level lock. The second phase
5313 // is IL generation phase which we take a MethodDesc level lock. Taking two locks
5314 // is mainly designed for performance.
5316 // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
5317 // allocated memory during the creation of MethodDesc so that we are able to remove
5318 // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
5320 // When removing IL Stub from Cache, we have a constraint that only the thread which
5321 // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
5322 // remove it from cache if OOM occurs
5325 ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, ¶ms);
5327 // take the domain level lock
5328 ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock());
5331 // The holder will free the allocated MethodDesc and restore the ILStubCache
5332 // if exception happen.
5333 ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper);
5334 pStubMD = pCreateOrGetStubHolder->GetStubMD();
5336 ///////////////////////////////
5340 ///////////////////////////////
5343 // take the MethodDesc level locker
5344 ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5346 ListLockEntryLockHolder pEntryLock(pEntry, FALSE);
5348 // We can release the holder for the first phase now
5349 pCreateOrGetStubHolder.SuppressRelease();
5352 // The holder will free the allocated MethodDesc and restore the ILStubCache
5353 // if exception happen. The reason to get the holder again is to
5354 ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper);
5356 if (!pEntryLock.DeadlockAwareAcquire())
5358 // the IL generation is not recursive!
5359 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5362 if (SF_IsSharedStub(params.m_dwStubFlags))
5364 // Assure that pStubMD we have now has not been destroyed by other threads
5365 pGenILHolder->GetStubMethodDesc();
5367 while (pStubMD != pGenILHolder->GetStubMD())
5369 pStubMD = pGenILHolder->GetStubMD();
5371 pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5372 pEntryLock.Assign(pEntry, FALSE);
5374 if (!pEntryLock.DeadlockAwareAcquire())
5376 // the IL generation is not recursive!
5377 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5380 pGenILHolder->GetStubMethodDesc();
5386 // We have the entry lock now, we can release the global lock
5387 pILStubLock.Release();
5389 if (pEntry->m_hrResultCode != S_FALSE)
5391 // We came in to generate the IL but someone
5392 // beat us so there's nothing to do
5396 ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
5398 CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc()));
5400 if (pResolver->IsILGenerated())
5402 // this stub already has its IL generated
5407 // Check that the stub signature and MethodDesc are compatible. The JIT
5408 // interface functions depend on this.
5412 SigPointer ptr = pSigDesc->m_sig.CreateSigPointer();
5415 IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo));
5417 BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS);
5419 // CreateNDirectStubWorker will throw an exception for these cases.
5420 BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags);
5422 if (fSigIsStatic || fCanHaveThis)
5424 CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic);
5429 ILStubGenHolder sgh(pResolver);
5431 pResolver->SetStubMethodDesc(pStubMD);
5432 pResolver->SetStubTargetMethodDesc(pTargetMD);
5434 CreateNDirectStubWorker(pss,
5444 pResolver->SetTokenLookupMap(pss->GetTokenLookupMap());
5446 pResolver->SetStubTargetMethodSig(
5447 pss->GetStubTargetMethodSig(),
5448 pss->GetStubTargetMethodSigLength());
5450 // we successfully generated the IL stub
5451 sgh.SuppressRelease();
5454 pEntry->m_hrResultCode = S_OK;
5458 // Link the MethodDesc onto the method table with the lock taken
5459 NDirect::AddMethodDescChunkWithLockTaken(¶ms, pStubMD);
5461 pGenILHolder.SuppressRelease();
5465 ilStubCreatorHelper.SuppressRelease();
5468 #if defined(_TARGET_X86_)
5469 if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg())
5471 // copy the stack arg byte count from the stub MD to the target MD - this number is computed
5472 // during stub generation and is copied to all target MDs that share the stub
5473 // (we don't set it for varargs - the number is call site specific)
5474 // also copy the "takes parameters with copy constructors" flag which is needed to generate
5475 // appropriate intercept stub
5477 WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
5478 BOOL fHasCopyCtorArgs = pStubMD->AsDynamicMethodDesc()->HasCopyCtorArgs();
5480 if (pTargetMD->IsNDirect())
5482 NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
5484 pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
5485 pTargetNMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5487 #ifdef FEATURE_COMINTEROP
5490 if (SF_IsCOMStub(dwStubFlags))
5492 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD);
5494 if (pComInfo != NULL)
5496 pComInfo->SetStackArgumentSize(cbStackArgSize);
5497 pComInfo->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5501 #endif // FEATURE_COMINTEROP
5503 #endif // defined(_TARGET_X86_)
5508 MethodDesc* NDirect::CreateCLRToNativeILStub(
5509 StubSigDesc* pSigDesc,
5510 CorNativeLinkType nlType,
5511 CorNativeLinkFlags nlFlags,
5512 CorPinvokeMap unmgdCallConv,
5513 DWORD dwStubFlags) // NDirectStubFlags
5515 CONTRACT(MethodDesc*)
5519 PRECONDITION(CheckPointer(pSigDesc));
5520 POSTCONDITION(CheckPointer(RETVAL));
5526 int numParamTokens = 0;
5527 mdParamDef* pParamTokenArray = NULL;
5529 CreateNDirectStubAccessMetadata(pSigDesc,
5535 Module *pModule = pSigDesc->m_pModule;
5536 numParamTokens = numArgs + 1;
5537 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5538 CollateParamTokens(pModule->GetMDImport(), pSigDesc->m_tkMethodDef, numArgs, pParamTokenArray);
5540 // for interop vectors that have declarative security, we need
5541 // to update the stub flags to ensure a unique stub hash
5542 // is generated based on the marshalling signature AND
5543 // any declarative security.
5544 // IMPORTANT: This will only inject the security callouts for
5545 // interop functionality which has a non-null target MethodDesc.
5546 // Currently, this is known to exclude things like native
5547 // function ptrs. It is assumed that if the target is not
5548 // attribute'able for metadata, then it cannot have declarative
5549 // security - and that the target is not attributable if it was
5550 // not passed to this function.
5551 MethodDesc *pMD = pSigDesc->m_pMD;
5552 if (pMD != NULL && SF_IsForwardStub(dwStubFlags))
5554 // In an AppX process there is only one fully trusted AppDomain, so there is never any need to insert
5555 // a security callout on the stubs.
5556 if (!AppX::IsAppXProcess())
5558 #ifdef FEATURE_COMINTEROP
5559 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5561 // To preserve Whidbey behavior, we only enforce the implicit demand for
5562 // unmanaged code permission.
5563 MethodTable* pMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
5564 if (pMT->ClassRequiresUnmanagedCodeCheck() &&
5565 !pMD->HasSuppressUnmanagedCodeAccessAttr())
5567 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5571 #endif // FEATURE_COMPINTEROP
5572 if (pMD->IsInterceptedForDeclSecurity())
5574 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5579 NewHolder<ILStubState> pStubState;
5581 #ifdef FEATURE_COMINTEROP
5582 if (SF_IsCOMStub(dwStubFlags))
5584 if (SF_IsReverseStub(dwStubFlags))
5586 pStubState = new COMToCLR_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5590 pStubState = new CLRToCOM_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5596 pStubState = new PInvoke_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, pMD);
5599 MethodDesc* pStubMD;
5600 pStubMD = CreateInteropILStub(
5616 #ifdef FEATURE_COMINTEROP
5617 MethodDesc* NDirect::CreateFieldAccessILStub(
5618 PCCOR_SIGNATURE szMetaSig,
5619 DWORD cbMetaSigSize,
5622 DWORD dwStubFlags, // NDirectStubFlags
5625 CONTRACT(MethodDesc*)
5629 PRECONDITION(CheckPointer(szMetaSig));
5630 PRECONDITION(CheckPointer(pModule));
5631 PRECONDITION(CheckPointer(pFD, NULL_OK));
5632 PRECONDITION(SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags));
5633 POSTCONDITION(CheckPointer(RETVAL));
5637 int numArgs = (SF_IsFieldSetterStub(dwStubFlags) ? 1 : 0);
5638 int numParamTokens = numArgs + 1;
5640 // make sure we capture marshaling metadata
5641 mdParamDef* pParamTokenArray = (mdParamDef *)_alloca(numParamTokens * sizeof(mdParamDef));
5642 pParamTokenArray[0] = mdParamDefNil;
5643 pParamTokenArray[numArgs] = (mdParamDef)fd;
5645 // fields are never preserve-sig
5646 dwStubFlags |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
5648 // convert field signature to getter/setter signature
5649 SigBuilder sigBuilder;
5651 sigBuilder.AppendData(IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS);
5652 sigBuilder.AppendData(numArgs);
5654 if (SF_IsFieldSetterStub(dwStubFlags))
5656 // managed setter returns void
5657 sigBuilder.AppendElementType(ELEMENT_TYPE_VOID);
5660 CONSISTENCY_CHECK(*szMetaSig == IMAGE_CEE_CS_CALLCONV_FIELD);
5662 sigBuilder.AppendBlob((const PVOID)(szMetaSig + 1), cbMetaSigSize - 1);
5663 szMetaSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbMetaSigSize);
5665 StubSigDesc sigDesc(NULL, Signature(szMetaSig, cbMetaSigSize), pModule);
5668 sigDesc.m_pDebugName = pFD->GetDebugName();
5669 sigDesc.m_pDebugClassName = pFD->GetEnclosingMethodTable()->GetDebugClassName();
5672 Signature signature(szMetaSig, cbMetaSigSize);
5673 NewHolder<ILStubState> pStubState = new COMToCLRFieldAccess_ILStubState(pModule, signature, &sigDesc.m_typeContext, dwStubFlags, pFD);
5675 MethodDesc* pStubMD;
5676 pStubMD = CreateInteropILStub(
5679 (CorNativeLinkType)0,
5680 (CorNativeLinkFlags)0,
5689 #endif // FEATURE_COMINTEROP
5691 MethodDesc* NDirect::CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
5695 STANDARD_VM_CONTRACT;
5697 StubSigDesc sigDesc(pMD, pSigInfo);
5699 if (SF_IsWinRTDelegateStub(dwStubFlags))
5701 _ASSERTE(pMD->IsEEImpl());
5703 return CreateCLRToNativeILStub(&sigDesc,
5704 (CorNativeLinkType)0,
5705 (CorNativeLinkFlags)0,
5707 (pSigInfo->GetStubFlags() | dwStubFlags) & ~NDIRECTSTUB_FL_DELEGATE);
5711 return CreateCLRToNativeILStub(&sigDesc,
5712 pSigInfo->GetCharSet(),
5713 pSigInfo->GetLinkFlags(),
5714 pSigInfo->GetCallConv(),
5715 pSigInfo->GetStubFlags() | dwStubFlags);
5719 MethodDesc* NDirect::GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags)
5721 STANDARD_VM_CONTRACT;
5723 MethodDesc* pStubMD = NULL;
5725 if (!pNMD->IsVarArgs() || SF_IsForNumParamBytes(dwStubFlags))
5727 if (pNMD->IsClassConstructorTriggeredByILStub())
5729 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
5732 pStubMD = CreateCLRToNativeILStub(
5734 dwStubFlags & ~NDIRECTSTUB_FL_FOR_NUMPARAMBYTES,
5741 MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
5743 STANDARD_VM_CONTRACT;
5745 BOOL fGcMdaEnabled = FALSE;
5746 #ifdef MDA_SUPPORTED
5747 if (MDA_GET_ASSISTANT(GcManagedToUnmanaged) || MDA_GET_ASSISTANT(GcUnmanagedToManaged))
5749 // We never generate checks for these MDAs to NGEN'ed stubs so if they are
5750 // enabled, a new stub must be generated (the perf impact is huge anyway).
5751 fGcMdaEnabled = TRUE;
5753 #endif // MDA_SUPPORTED
5755 #ifdef FEATURE_COMINTEROP
5756 if (SF_IsReverseCOMStub(dwStubFlags))
5761 // reverse COM stubs live in a hash table
5762 StubMethodHashTable *pHash = pMD->GetLoaderModule()->GetStubMethodHashTable();
5763 return (pHash == NULL ? NULL : pHash->FindMethodDesc(pMD));
5766 #endif // FEATURE_COMINTEROP
5767 if (pMD->IsNDirect())
5769 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5770 return ((fGcMdaEnabled && !pNMD->IsQCall()) ? NULL : pNMD->ndirect.m_pStubMD.GetValueMaybeNull());
5772 #ifdef FEATURE_COMINTEROP
5773 else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5775 #ifdef MDA_SUPPORTED
5776 if (MDA_GET_ASSISTANT(RaceOnRCWCleanup))
5778 // we never generate this callout to NGEN'ed stubs
5781 #endif // MDA_SUPPORTED
5783 if (NDirect::IsHostHookEnabled())
5785 MethodTable *pMT = pMD->GetMethodTable();
5786 if (pMT->IsProjectedFromWinRT() || pMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative))
5788 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5789 // must be rejected if we are hosted.
5797 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
5798 return (pComInfo == NULL ? NULL : pComInfo->m_pStubMD.GetValueMaybeNull());
5800 #endif // FEATURE_COMINTEROP
5801 else if (pMD->IsEEImpl())
5806 DelegateEEClass *pClass = (DelegateEEClass *)pMD->GetClass();
5807 if (SF_IsReverseStub(dwStubFlags))
5809 return pClass->m_pReverseStubMD;
5813 #ifdef FEATURE_COMINTEROP
5814 if (SF_IsWinRTDelegateStub(dwStubFlags))
5816 if (NDirect::IsHostHookEnabled() && pMD->GetMethodTable()->IsProjectedFromWinRT())
5818 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5819 // must be rejected if we are hosted.
5823 return pClass->m_pComPlusCallInfo->m_pStubMD.GetValueMaybeNull();
5826 #endif // FEATURE_COMINTEROP
5828 return pClass->m_pForwardStubMD;
5832 else if (pMD->IsIL())
5834 // these are currently only created at runtime, not at NGEN time
5839 UNREACHABLE_MSG("unexpected type of MethodDesc");
5843 #ifndef CROSSGEN_COMPILE
5845 PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5851 PRECONDITION(CheckPointer(pManagedMD));
5852 POSTCONDITION(RETVAL != NULL);
5856 // pStubMD, if provided, must be preimplemented.
5857 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5859 if (NULL == *ppStubMD)
5861 PInvokeStaticSigInfo sigInfo(pManagedMD);
5862 *ppStubMD = NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pManagedMD);
5865 RETURN JitILStub(*ppStubMD);
5868 PCODE NDirect::GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5870 STANDARD_VM_CONTRACT;
5874 // pStubMD, if provided, must be preimplemented.
5875 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5877 if (NULL == *ppStubMD)
5879 PInvokeStaticSigInfo sigInfo;
5880 NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo, /* throwOnError = */ !SF_IsForNumParamBytes(dwStubFlags));
5882 *ppStubMD = NDirect::GetILStubMethodDesc(pNMD, &sigInfo, dwStubFlags);
5885 if (SF_IsForNumParamBytes(dwStubFlags))
5890 pStub = JitILStub(*ppStubMD);
5894 CONSISTENCY_CHECK(pNMD->IsVarArgs());
5897 // varargs goes through vararg NDirect stub
5899 pStub = TheVarargNDirectStub(pNMD->HasRetBuffArg());
5902 #ifdef FEATURE_MIXEDMODE // IJW
5903 if (pNMD->IsEarlyBound())
5905 pNMD->InitEarlyBoundNDirectTarget();
5914 // NOTE: there is a race in updating this MethodDesc. We depend on all
5915 // threads getting back the same DynamicMethodDesc for a particular
5916 // NDirectMethodDesc, in that case, the locking around the actual JIT
5917 // operation will prevent the code from being jitted more than once.
5918 // By the time we get here, all threads get the same address of code
5919 // back from the JIT operation and they all just fill in the same value
5922 // In the NGEN case, all threads will get the same preimplemented code
5923 // address much like the JIT case.
5929 PCODE JitILStub(MethodDesc* pStubMD)
5931 STANDARD_VM_CONTRACT;
5933 PCODE pCode = pStubMD->GetNativeCode();
5937 ///////////////////////////////
5941 ///////////////////////////////
5944 if (pStubMD->IsDynamicMethod())
5947 // A dynamically generated IL stub
5950 CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
5951 pCode = pStubMD->MakeJitWorker(NULL, jitFlags);
5953 _ASSERTE(pCode == pStubMD->GetNativeCode());
5958 // A static IL stub that is pointing to a static method in user assembly
5959 // Compile it and return the native code
5962 // This returns the stable entry point
5963 pCode = pStubMD->DoPrestub(NULL);
5965 _ASSERTE(pCode == pStubMD->GetStableEntryPoint());
5969 if (!pStubMD->IsDynamicMethod())
5971 // We need an entry point that can be called multiple times
5972 pCode = pStubMD->GetMultiCallableAddrOfCode();
5978 MethodDesc* RestoreNGENedStub(MethodDesc* pStubMD)
5983 PRECONDITION(CheckPointer(pStubMD));
5987 #ifdef FEATURE_PREJIT
5988 pStubMD->CheckRestore();
5990 PCODE pCode = pStubMD->GetPreImplementedCode();
5993 TADDR pFixupList = pStubMD->GetFixupList();
5994 if (pFixupList != NULL)
5996 Module* pZapModule = pStubMD->GetZapModule();
5997 _ASSERTE(pZapModule != NULL);
5998 if (!pZapModule->FixupDelayList(pFixupList))
6000 _ASSERTE(!"FixupDelayList failed");
6001 ThrowHR(COR_E_BADIMAGEFORMAT);
6005 #if defined(HAVE_GCCOVER)
6006 if (GCStress<cfg_instr_ngen>::IsEnabled())
6007 SetupGcCoverage(pStubMD, (BYTE*) pCode);
6008 #endif // HAVE_GCCOVER
6013 // We only pass a non-NULL pStubMD to GetStubForILStub() below if pStubMD is preimplemeneted.
6016 #endif // FEATURE_PREJIT
6021 PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags, MethodDesc **ppStubMD)
6027 PRECONDITION(CheckPointer(pMD));
6028 PRECONDITION(pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl() || pMD->IsIL());
6033 MethodDesc* pStubMD = NULL;
6035 pStubMD = GetStubMethodDescFromInteropMethodDesc(pMD, dwStubFlags);
6036 if (pStubMD != NULL)
6038 pStubMD = RestoreNGENedStub(pStubMD);
6041 if ((NULL == pStubMD) && (SF_IsNGENedStub(dwStubFlags)))
6043 // Return NULL -- the caller asked only for an ngened stub and
6044 // one does not exist, so don't do any more work.
6045 CONSISTENCY_CHECK(pStub == NULL);
6048 if (pMD->IsNDirect())
6050 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
6051 pStub = NDirect::GetStubForILStub(pNMD, &pStubMD, dwStubFlags);
6053 #ifdef FEATURE_COMINTEROP
6055 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
6057 pStub = ComPlusCall::GetStubForILStub(pMD, &pStubMD);
6059 #endif // FEATURE_COMINTEROP
6061 if (pMD->IsEEImpl())
6063 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
6064 EEImplMethodDesc* pDelegateMD = (EEImplMethodDesc*)pMD;
6065 pStub = COMDelegate::GetStubForILStub(pDelegateMD, &pStubMD, dwStubFlags);
6070 CONSISTENCY_CHECK(SF_IsReverseStub(dwStubFlags));
6071 pStub = NDirect::GetStubForILStub(pMD, &pStubMD, dwStubFlags);
6075 UNREACHABLE_MSG("unexpected MethodDesc type");
6078 if (pStubMD != NULL && pStubMD->IsILStub() && pStubMD->AsDynamicMethodDesc()->IsStubNeedsCOMStarted())
6080 // the stub uses COM so make sure that it is started
6084 if (ppStubMD != NULL)
6085 *EnsureWritablePages(ppStubMD) = pStubMD;
6090 #ifdef FEATURE_COMINTEROP
6091 void CreateCLRToDispatchCOMStub(
6093 DWORD dwStubFlags) // NDirectStubFlags
6099 PRECONDITION(CheckPointer(pMD));
6103 _ASSERTE(SF_IsCOMLateBoundStub(dwStubFlags) || SF_IsCOMEventCallStub(dwStubFlags));
6105 // If we are dealing with a COM event call, then we need to initialize the
6106 // COM event call information.
6107 if (SF_IsCOMEventCallStub(dwStubFlags))
6109 _ASSERTE(pMD->IsComPlusCall()); // no generic COM eventing
6110 ((ComPlusCallMethodDesc *)pMD)->InitComEventCallInfo();
6113 // Get the call signature information
6114 StubSigDesc sigDesc(pMD);
6118 int numParamTokens = 0;
6119 mdParamDef* pParamTokenArray = NULL;
6121 CreateNDirectStubAccessMetadata(&sigDesc,
6127 numParamTokens = numArgs + 1;
6128 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
6129 CollateParamTokens(sigDesc.m_pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray);
6131 DispatchStubState MyStubState;
6133 CreateNDirectStubWorker(&MyStubState,
6135 (CorNativeLinkType)0,
6136 (CorNativeLinkFlags)0,
6138 dwStubFlags | NDIRECTSTUB_FL_COM,
6143 _ASSERTE(pMD->IsComPlusCall()); // no generic disp-calls
6144 ((ComPlusCallMethodDesc *)pMD)->InitRetThunk();
6148 #endif // FEATURE_COMINTEROP
6151 LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod)
6153 // GetProcAddress cannot be called while preemptive GC is disabled.
6154 // It requires the OS to take the loader lock.
6158 PRECONDITION(CheckPointer(pMD));
6159 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6163 g_IBCLogger.LogNDirectCodeAccess(pMD);
6165 #ifdef MDA_SUPPORTED
6166 MDA_TRIGGER_ASSISTANT(PInvokeLog, LogPInvoke(pMD, hMod));
6169 RETURN pMD->FindEntryPoint(hMod);
6172 VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget)
6180 PRECONDITION(IsNDirect());
6181 PRECONDITION(pTarget != NULL);
6185 Stub *pInterceptStub = NULL;
6189 // Host hooks are not supported for Mac CoreCLR.
6190 if (NDirect::IsHostHookEnabled())
6193 // we will call CallNeedsHostHook on every invocation for back compat
6196 fHook = CallNeedsHostHook((size_t)pTarget);
6200 if (g_pConfig->ShouldGenerateStubForHost())
6209 #ifndef FEATURE_CORECLR
6210 if (HasCopyCtorArgs())
6212 _ASSERTE(pInterceptStub == NULL);
6214 // static stub that gets its arguments in a thread-static field
6215 pInterceptStub = NDirect::GetStubForCopyCtor();
6217 #endif // !FEATURE_CORECLR
6219 #ifdef MDA_SUPPORTED
6220 if (!IsQCall() && MDA_GET_ASSISTANT(PInvokeStackImbalance))
6222 pInterceptStub = GenerateStubForMDA(pTarget, pInterceptStub, fHook);
6224 #endif // MDA_SUPPORTED
6226 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
6229 pInterceptStub = GenerateStubForHost(pTarget, pInterceptStub);
6231 #endif // FEATURE_INCLUDE_ALL_INTERFACES
6233 #endif // _TARGET_X86_
6236 NDirectWriteableData* pWriteableData = GetWriteableData();
6237 EnsureWritablePages(pWriteableData);
6238 g_IBCLogger.LogNDirectCodeAccess(this);
6240 if (pInterceptStub != NULL WIN64_ONLY(|| fHook))
6242 ndirect.m_pNativeNDirectTarget = pTarget;
6244 #if defined(_TARGET_X86_)
6245 pTarget = (PVOID)pInterceptStub->GetEntryPoint();
6247 LPVOID oldTarget = GetNDirectImportThunkGlue()->GetEntrypoint();
6248 if (FastInterlockCompareExchangePointer(&pWriteableData->m_pNDirectTarget, pTarget,
6249 oldTarget) != oldTarget)
6251 pInterceptStub->DecRef();
6254 _ASSERTE(pInterceptStub == NULL); // we don't intercept for anything else than host on !_TARGET_X86_
6255 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
6256 pWriteableData->m_pNDirectTarget = (LPVOID)GetEEFuncEntryPoint(PInvokeStubForHost);
6257 #endif // FEATURE_INCLUDE_ALL_INTERFACES
6262 pWriteableData->m_pNDirectTarget = pTarget;
6266 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
6268 // Returns a small stub whose purpose is to record current ESP and call code:CopyCtorCallStubWorker
6269 // to invoke copy constructors and destructors as appropriate. This stub operates on arguments
6270 // already pushed to the stack by JITted IL stub and must not create a new frame, i.e. it must
6271 // tail call to the target for it to see the arguments that copy ctors have been called on.
6273 // As a consequence, the stub doesn't take any extra secret arguments and the description of the
6274 // ctors/dtors to call is passed "out-of-band" in a thread static field. The worker returns
6275 // address of the real target (also passed out of band) which enables us to have only one static
6276 // stub in i386\asmhelpers.asm.
6279 Stub *NDirect::GetStubForCopyCtor()
6281 STANDARD_VM_CONTRACT;
6283 static Stub *s_pStub = NULL;
6285 if (s_pStub == NULL)
6287 Stub *pStub = Stub::NewStub(GetEEFuncEntryPoint(CopyCtorCallStub));
6288 if (InterlockedCompareExchangeT(&s_pStub, pStub, NULL) != NULL)
6298 #endif // _TARGET_X86_ && !FEATURE_CORECLR
6300 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
6301 BOOL NDirect::IsHostHookEnabled()
6303 WRAPPER_NO_CONTRACT;
6305 // WARNING: The non-debug portion of this logic is inlined into UMThunkStubAMD64!
6307 return CLRTaskHosted() INDEBUG(|| g_pConfig->ShouldGenerateStubForHost());
6310 EXTERN_C BOOL CallNeedsHostHook(size_t target)
6313 IHostTaskManager *pManager = CorHost2::GetHostTaskManager();
6317 BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
6318 hr = pManager->CallNeedsHostHook(target,&fHook);
6319 END_SO_TOLERANT_CODE_CALLING_HOST;
6320 _ASSERTE (hr == S_OK);
6325 if (g_pConfig->ShouldGenerateStubForHost())
6333 #endif // FEATURE_INCLUDE_ALL_INTERFACES
6335 #if defined(_TARGET_X86_) && defined(MDA_SUPPORTED)
6336 EXTERN_C VOID __stdcall PInvokeStackImbalanceWorker(StackImbalanceCookie *pSICookie, DWORD dwPostESP)
6338 STATIC_CONTRACT_THROWS;
6339 STATIC_CONTRACT_GC_TRIGGERS;
6340 STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6342 // make sure we restore the original Win32 last error before leaving this function - we are
6343 // called right after returning from the P/Invoke target and the error has not been saved yet
6344 BEGIN_PRESERVE_LAST_ERROR;
6346 MdaPInvokeStackImbalance* pProbe = MDA_GET_ASSISTANT(PInvokeStackImbalance);
6348 // This MDA must be active if we generated a call to PInvokeStackImbalanceHelper
6351 pProbe->CheckStack(pSICookie, dwPostESP);
6353 END_PRESERVE_LAST_ERROR;
6355 #endif // _TARGET_X86_ && MDA_SUPPORTED
6357 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
6358 struct CopyCtorStubCookie // same layout as StubHelpers.CopyCtorStubCookie
6360 LPVOID m_srcInstancePtr;
6361 DWORD m_dstStackOffset;
6362 LPVOID m_ctorPtr; // managed method ptr
6363 LPVOID m_dtorPtr; // managed method ptr
6365 CopyCtorStubCookie *m_pNext;
6368 struct CopyCtorStubDesc // same layout as StubHelpers.CopyCtorStubDesc
6370 CopyCtorStubCookie *m_pCookie;
6374 // Called by CopyCtorCallStub after we have already transitioned to unmanaged. Invokes copy ctor(s)
6375 // and dtor(s) using reverse P/Invoke which has some perf impact but provides all the debugging and
6376 // profiling support. An alternative solution would be CallDescr or some optimized variant of it
6377 // which would probably result in confusing call stacks.
6378 EXTERN_C LPVOID __stdcall CopyCtorCallStubWorker(BYTE *pESP)
6380 STATIC_CONTRACT_THROWS;
6381 STATIC_CONTRACT_GC_TRIGGERS;
6382 STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6384 CopyCtorStubCookie *pCookie;
6388 // get address of the thread-static field
6389 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__STUBHELPERS__COPY_CTOR_STUB_DESC);
6391 CopyCtorStubDesc *pStubDesc = (CopyCtorStubDesc *)Thread::GetStaticFieldAddress(pFD);
6393 // read the fields in cooperative mode
6394 pCookie = pStubDesc->m_pCookie;
6395 pTarget = pStubDesc->m_pTarget;
6397 _ASSERTE(pCookie != NULL && pTarget != NULL);
6399 // make sure we ASSERT/AV reliably if we are called by mistake
6400 pStubDesc->m_pCookie = NULL;
6401 pStubDesc->m_pTarget = NULL;
6404 while (pCookie != NULL)
6406 if (pCookie->m_ctorPtr != NULL)
6408 // get reverse P/Invoke to the copy ctor (cache on AD)
6409 MethodDesc *pMD = Entry2MethodDesc((PCODE)pCookie->m_ctorPtr, NULL);
6410 UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
6412 // GetUMEntryThunk always returns stdcall-able function pointers for ordinary managed methods
6413 // but the ctor can be a P/Invoke (pre-Whidbey MC++ only)
6414 typedef void (__stdcall *CtorFnPtr_StdCall) (LPVOID dst, LPVOID src);
6415 typedef void (__thiscall *CtorFnPtr_ThisCall)(LPVOID dst, LPVOID src);
6416 typedef void (__cdecl *CtorFnPtr_Cdecl) (LPVOID dst, LPVOID src);
6418 // call the copy ctor using the right calling convention
6419 UMThunkMarshInfo *pMarshInfo = pUMEntryThunk->GetUMThunkMarshInfo();
6420 pMarshInfo->RunTimeInit();
6422 switch (pMarshInfo->GetCallingConvention() & pmCallConvMask)
6424 case pmCallConvStdcall:
6425 case pmCallConvWinapi:
6427 CtorFnPtr_StdCall fnPtr = (CtorFnPtr_StdCall)pUMEntryThunk->GetCode();
6428 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6432 case pmCallConvThiscall:
6434 CtorFnPtr_ThisCall fnPtr = (CtorFnPtr_ThisCall)pUMEntryThunk->GetCode();
6435 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6441 _ASSERTE((pMarshInfo->GetCallingConvention() & pmCallConvMask) == pmCallConvCdecl);
6443 CtorFnPtr_Cdecl fnPtr = (CtorFnPtr_Cdecl)pUMEntryThunk->GetCode();
6444 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6449 if (pCookie->m_dtorPtr != NULL)
6451 // get reverse P/Invoke to the dtor (cache on AD)
6452 MethodDesc *pMD = Entry2MethodDesc((PCODE)pCookie->m_dtorPtr, NULL);
6453 UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
6455 // GetUMEntryThunk always returns stdcall-able function pointers for ordinary managed methods
6456 // but the dtor can be a P/Invoke (pre-Whidbey MC++ only)
6457 typedef void (__stdcall *DtorFnPtr_StdCall) (LPVOID src);
6458 typedef void (__thiscall *DtorFnPtr_ThisCall)(LPVOID src);
6459 typedef void (__cdecl *DtorFnPtr_Cdecl) (LPVOID src);
6461 // call the dtor using the right calling convention
6462 UMThunkMarshInfo *pMarshInfo = pUMEntryThunk->GetUMThunkMarshInfo();
6463 pMarshInfo->RunTimeInit();
6465 switch (pMarshInfo->GetCallingConvention() & pmCallConvMask)
6467 case pmCallConvStdcall:
6468 case pmCallConvWinapi:
6470 DtorFnPtr_StdCall fnPtr = (DtorFnPtr_StdCall)pUMEntryThunk->GetCode();
6471 fnPtr(pCookie->m_srcInstancePtr);
6475 case pmCallConvThiscall:
6477 DtorFnPtr_ThisCall fnPtr = (DtorFnPtr_ThisCall)pUMEntryThunk->GetCode();
6478 fnPtr(pCookie->m_srcInstancePtr);
6484 _ASSERTE((pMarshInfo->GetCallingConvention() & pmCallConvMask) == pmCallConvCdecl);
6486 DtorFnPtr_Cdecl fnPtr = (DtorFnPtr_Cdecl)pUMEntryThunk->GetCode();
6487 fnPtr(pCookie->m_srcInstancePtr);
6492 pCookie = pCookie->m_pNext;
6497 #endif // _TARGET_X86_ && !FEATURE_CORECLR
6499 // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places
6500 // if earlier loads fail and those later loads obliterate error codes.
6502 // This tracker object will keep track of the error code in accordance to priority:
6504 // low-priority: unknown error code (should never happen)
6505 // medium-priority: dll not found
6506 // high-priority: dll found but error during loading
6508 // We will overwrite the previous load's error code only if the new error code is higher priority.
6511 class LoadLibErrorTracker
6514 static const DWORD const_priorityNotFound = 10;
6515 static const DWORD const_priorityAccessDenied = 20;
6516 static const DWORD const_priorityCouldNotLoad = 99999;
6518 LoadLibErrorTracker()
6520 LIMITED_METHOD_CONTRACT;
6522 m_priorityOfLastError = 0;
6525 VOID TrackErrorCode(DWORD dwLastError)
6527 LIMITED_METHOD_CONTRACT;
6531 switch (dwLastError)
6533 case ERROR_FILE_NOT_FOUND:
6534 case ERROR_PATH_NOT_FOUND:
6535 case ERROR_MOD_NOT_FOUND:
6536 case ERROR_DLL_NOT_FOUND:
6537 priority = const_priorityNotFound;
6540 // If we can't access a location, we can't know if the dll's there or if it's good.
6541 // Still, this is probably more unusual (and thus of more interest) than a dll-not-found
6542 // so give it an intermediate priority.
6543 case ERROR_ACCESS_DENIED:
6544 priority = const_priorityAccessDenied;
6546 // Assume all others are "dll found but couldn't load."
6548 priority = const_priorityCouldNotLoad;
6552 UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError));
6555 // Sets the error code to HRESULT as could not load DLL
6556 void TrackHR_CouldNotLoad(HRESULT hr)
6558 UpdateHR(const_priorityCouldNotLoad, hr);
6566 void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath)
6568 STANDARD_VM_CONTRACT;
6570 HRESULT theHRESULT = GetHR();
6571 if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT))
6573 COMPlusThrow(kBadImageFormatException);
6578 GetHRMsg(theHRESULT, hrString);
6579 COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, libraryNameOrPath.GetUnicode(), hrString);
6586 void UpdateHR(DWORD priority, HRESULT hr)
6588 if (priority > m_priorityOfLastError)
6591 m_priorityOfLastError = priority;
6596 DWORD m_priorityOfLastError;
6597 }; // class LoadLibErrorTracker
6599 // Local helper function for the LoadLibraryModule function below
6600 static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
6602 STANDARD_VM_CONTRACT;
6604 HMODULE hmod = NULL;
6608 if ((flags & 0xFFFFFF00) != 0
6609 #ifndef FEATURE_CORESYSTEM
6610 && NDirect::SecureLoadLibrarySupported()
6611 #endif // !FEATURE_CORESYSTEM
6614 hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00);
6620 DWORD dwLastError = GetLastError();
6621 if (dwLastError != ERROR_INVALID_PARAMETER)
6623 pErrorTracker->TrackErrorCode(dwLastError);
6628 hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF);
6630 #else // !FEATURE_PAL
6631 hmod = CLRLoadLibrary(name);
6632 #endif // !FEATURE_PAL
6636 pErrorTracker->TrackErrorCode(GetLastError());
6642 // Local helper function for the LoadLibraryFromPath function below
6643 static HMODULE LocalLoadLibraryDirectHelper(LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6645 STANDARD_VM_CONTRACT;
6648 return LocalLoadLibraryHelper(name, flags, pErrorTracker);
6649 #else // !FEATURE_PAL
6650 // Load the library directly, and don't register it yet with PAL. The system library handle is required here, not the PAL
6651 // handle. The system library handle is registered with PAL to get a PAL handle in LoadLibraryModuleViaHost().
6652 HMODULE hmod = PAL_LoadLibraryDirect(name);
6656 pErrorTracker->TrackErrorCode(GetLastError());
6660 #endif // !FEATURE_PAL
6664 #if !defined(FEATURE_CORESYSTEM)
6666 #define NATIVE_DLL(d) L#d, L#d W(".dll")
6668 const LPCWSTR wellKnownModules[] =
6670 NATIVE_DLL(advapi32),
6672 NATIVE_DLL(gdiplus),
6673 NATIVE_DLL(kernel32),
6674 NATIVE_DLL(mscoree),
6676 NATIVE_DLL(shfolder),
6681 BOOL CompareLibNames (UPTR val1, UPTR val2)
6690 LPCWSTR wszStr1 = (LPCWSTR)(val1 << 1);
6691 LPCWSTR wszStr2 = (LPCWSTR)val2;
6693 if (SString::_wcsicmp(wszStr1, wszStr2) == 0)
6699 PtrHashMap * NDirect::s_pWellKnownNativeModules = NULL;
6700 bool NDirect::s_fSecureLoadLibrarySupported = false;
6702 HINSTANCE NDirect::CheckForWellKnownModules(LPCWSTR wszLibName, LoadLibErrorTracker *pErrorTracker)
6704 STANDARD_VM_CONTRACT;
6706 ModuleHandleHolder hMod;
6707 ULONG hash = HashiString(wszLibName);
6708 LPCWSTR wszName = NULL;
6709 wszName = (LPCWSTR) s_pWellKnownNativeModules->LookupValue((UPTR) hash, (LPVOID)wszLibName);
6711 if (wszName != (LPCWSTR)INVALIDENTRY)
6713 hMod = LocalLoadLibraryHelper(wszLibName, 0, pErrorTracker);
6716 return hMod.Extract();
6719 #endif // !FEATURE_CORESYSTEM
6721 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
6722 #define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
6724 #ifndef FEATURE_CORECLR
6726 VOID NDirect::CheckUnificationList(NDirectMethodDesc * pMD, DWORD * pDllImportSearchPathFlag, BOOL * pSearchAssemblyDirectory)
6736 // If neither assembly and method have the attribute, check the unification list.
6737 Assembly *pAssembly = pMD->GetAssembly();
6739 if (!pAssembly->IsStrongNamed())
6742 const char * simpleName = pAssembly->GetSimpleName();
6744 StringHashIterator(it, g_arFxPolicy, simpleName);
6748 while ((pos = it.GetNext()) >= 0)
6750 const FrameworkConfig & config = g_arFxPolicy[pos];
6752 FixedSizeString<char> asmName;
6754 config.GetFxAssemblyName(asmName);
6756 if (_stricmp(asmName, simpleName) == 0)
6758 DWORD cbPublicKey = 0;
6759 const void *pbPublicKey = NULL;
6760 pbPublicKey = pAssembly->GetPublicKey(&cbPublicKey);
6763 // StrongNameTokenFromPublicKey is potentially expensive operation. Do it only once we got a match on the simple name.
6765 StrongNameBufferHolder<BYTE> pbStrongNameToken;
6766 DWORD cbStrongNameToken;
6768 if (StrongNameTokenFromPublicKey((BYTE*) pbPublicKey,cbPublicKey,&pbStrongNameToken,&cbStrongNameToken))
6770 BOOL pktIsEqual = TRUE;
6772 LPCWSTR pwzPKT = config.GetPKT();
6774 for (UINT j = 0; j < cbStrongNameToken; j++)
6776 WCHAR firstChar = TOHEX(pbStrongNameToken[j] / 16);
6777 WCHAR secondChar = TOHEX(pbStrongNameToken[j] % 16);
6779 if (firstChar != TOLOWER(pwzPKT[j*2]) || secondChar != TOLOWER(pwzPKT[j*2+1]))
6788 *pDllImportSearchPathFlag = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
6789 *pSearchAssemblyDirectory = TRUE;
6796 #endif // !FEATURE_CORECLR
6799 HMODULE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
6801 STANDARD_VM_CONTRACT;
6803 LoadLibErrorTracker errorTracker;
6804 const HMODULE systemModuleHandle =
6805 LocalLoadLibraryDirectHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
6806 if (systemModuleHandle == nullptr)
6808 SString libraryPathSString(libraryPath);
6809 errorTracker.Throw(libraryPathSString);
6811 return systemModuleHandle;
6814 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6816 HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName)
6818 STANDARD_VM_CONTRACT;
6819 //Dynamic Pinvoke Support:
6820 //Check if we need to provide the host a chance to provide the unmanaged dll
6822 #ifndef PLATFORM_UNIX
6823 // Prevent Overriding of Windows API sets.
6824 // This is replicating quick check from the OS implementation of api sets.
6825 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6832 CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
6833 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6835 PEFile *pManifestFile = pAssembly->GetManifestFile();
6836 PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
6838 //Step 0: Check if the assembly was bound using TPA.
6839 // The Binding Context can be null or an overridden TPA context
6840 if (pBindingContext == NULL)
6842 pBindingContext = nullptr;
6844 // If the assembly does not have a binder associated with it explicitly, then check if it is
6845 // a dynamic assembly, or not, since they can have a fallback load context associated with them.
6846 if (pManifestFile->IsDynamic())
6848 pBindingContext = pManifestFile->GetFallbackLoadContextBinder();
6852 // If we do not have any binder associated, then return to the default resolution mechanism.
6853 if (pBindingContext == nullptr)
6858 UINT_PTR assemblyBinderID = 0;
6859 IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6861 ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6863 // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
6864 if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
6869 #ifdef FEATURE_COMINTEROP
6870 CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
6871 if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
6873 // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
6874 // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
6876 // For this, we should use the standard mechanism to make pinvoke call as well.
6879 #endif // FEATURE_COMINTEROP
6881 //Step 1: If the assembly was not bound using TPA,
6882 // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
6883 // The custom assembly context a chance to load the unmanaged dll.
6887 STRINGREF pUnmanagedDllName;
6888 pUnmanagedDllName = StringObject::NewString(wszLibName);
6890 GCPROTECT_BEGIN(pUnmanagedDllName);
6892 // Get the pointer to the managed assembly load context
6893 INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6895 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
6896 PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
6897 DECLARE_ARGHOLDER_ARRAY(args, 2);
6898 args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
6899 args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6902 CALL_MANAGED_METHOD(hmod,LPVOID,args);
6907 if (hmod != nullptr)
6909 // Register the system library handle with PAL and get a PAL library handle
6910 hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6912 #endif // FEATURE_PAL
6914 return (HMODULE)hmod;
6916 #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6918 // Try to load the module alongside the assembly where the PInvoke was declared.
6919 HMODULE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6921 STANDARD_VM_CONTRACT;
6923 HMODULE hmod = NULL;
6925 SString path = pAssembly->GetManifestFile()->GetPath();
6927 SString::Iterator lastPathSeparatorIter = path.End();
6928 if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
6930 lastPathSeparatorIter++;
6931 path.Truncate(lastPathSeparatorIter);
6933 path.Append(libName);
6934 hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
6940 #ifdef FEATURE_CORECLR
6941 // Try to load the module from the native DLL search directories
6942 HMODULE NDirect::LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6944 STANDARD_VM_CONTRACT;
6946 HMODULE hmod = NULL;
6948 if (pDomain->HasNativeDllSearchDirectories())
6950 AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
6951 while (hmod == NULL && pathIter.Next())
6953 SString qualifiedPath(*(pathIter.GetPath()));
6954 qualifiedPath.Append(libName);
6955 if (!Path::IsRelative(qualifiedPath))
6957 hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
6964 #endif // FEATURE_CORECLR
6966 HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
6971 PRECONDITION( CheckPointer( pMD ) );
6975 LPCUTF8 name = pMD->GetLibName();
6976 if ( !name || !*name )
6979 ModuleHandleHolder hmod;
6981 DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
6983 PREFIX_ASSUME( name != NULL );
6984 MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
6986 AppDomain* pDomain = GetAppDomain();
6988 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6989 // AssemblyLoadContext is not supported in AppX mode and thus,
6990 // we should not perform PInvoke resolution via it when operating in
6992 if (!AppX::IsAppXProcess())
6994 hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName);
6996 #endif //FEATURE_HOST_ASSEMBLY_RESOLVER
7001 hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
7006 return hmod.Extract();
7009 #if !defined(FEATURE_CORESYSTEM)
7010 hmod = CheckForWellKnownModules(wszLibName, pErrorTracker);
7014 // In the PAL version of CoreCLR, the CLR module itself exports the functionality
7015 // that the Windows version obtains from kernel32 and friends. In order to avoid
7016 // picking up the wrong instance, we perform this redirection first.
7017 // This is also true for CoreSystem builds, where mscorlib p/invokes are forwarded through coreclr
7018 // itself so we can control CoreSystem library/API name re-mapping from one central location.
7019 if (SString::_wcsicmp(wszLibName, MAIN_CLR_MODULE_NAME_W) == 0)
7020 hmod = GetCLRModule();
7021 #endif // FEATURE_PAL
7023 #if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX)
7026 // Try to go straight to System32 for Windows API sets. This is replicating quick check from
7027 // the OS implementation of api sets.
7028 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
7030 hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
7033 #endif // FEATURE_CORESYSTEM && !FEATURE_PAL
7035 #ifdef FEATURE_CORECLR
7038 // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path
7039 hmod = LoadFromNativeDllSearchDirectories(pDomain, wszLibName, loadWithAlteredPathFlags, pErrorTracker);
7041 #endif // FEATURE_CORECLR
7043 DWORD dllImportSearchPathFlag = 0;
7044 BOOL searchAssemblyDirectory = TRUE;
7045 bool libNameIsRelativePath = Path::IsRelative(wszLibName);
7048 // First checks if the method has DefaultDllImportSearchPathsAttribute. If method has the attribute
7049 // then dllImportSearchPathFlag is set to its value.
7050 // Otherwise checks if the assembly has the attribute.
7051 // If assembly has the attribute then flag ise set to its value.
7052 BOOL attributeIsFound = FALSE;
7054 if (pMD->HasDefaultDllImportSearchPathsAttribute())
7056 dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
7057 searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
7058 attributeIsFound = TRUE;
7062 Module * pModule = pMD->GetModule();
7064 if(pModule->HasDefaultDllImportSearchPathsAttribute())
7066 dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
7067 searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
7068 attributeIsFound = TRUE;
7072 #ifndef FEATURE_CORECLR
7073 if (!attributeIsFound)
7075 CheckUnificationList(pMD, &dllImportSearchPathFlag, &searchAssemblyDirectory);
7079 if (!libNameIsRelativePath)
7081 DWORD flags = loadWithAlteredPathFlags;
7082 if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
7084 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
7085 // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
7086 flags |= dllImportSearchPathFlag;
7089 hmod = LocalLoadLibraryHelper(wszLibName, flags, pErrorTracker);
7091 else if (searchAssemblyDirectory)
7093 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
7094 hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, wszLibName, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7096 #ifndef FEATURE_CORECLR
7099 // Try to load the DLL alongside the assembly where the PInvoke was
7100 // declared using the codebase of the assembly. This is required for download
7101 // and shadow copy scenarios.
7104 pAssembly->GetCodeBase(codebase);
7105 DWORD dwCodebaseLength = codebase.GetCount();
7107 // Strip off the protocol
7108 for (ptr = codebase.GetUnicode(); *ptr && *ptr != W(':'); ptr++);
7110 // If we have a code base then prepend it to the library name
7113 SString pathFromCodebase;
7115 // After finding the colon move forward until no more forward slashes
7116 for (ptr++; *ptr && *ptr == W('/'); ptr++);
7119 // Calculate the number of characters we are interested in
7120 if (dwCodebaseLength > (DWORD)(ptr - codebase.GetUnicode()) )
7122 // Back up to the last slash (forward or backwards)
7125 for (tail = codebase.GetUnicode() + (dwCodebaseLength - 1); tail > ptr && *tail != W('/') && *tail != W('\\'); tail--);
7129 for (;ptr <= tail; ptr++)
7132 pathFromCodebase.Append(W('\\'));
7134 pathFromCodebase.Append(*ptr);
7140 pathFromCodebase.Append(wszLibName);
7142 SString path = pAssembly->GetManifestFile()->GetPath();
7143 SString::Iterator i = path.End();
7144 if (PEAssembly::FindLastPathSeparator(path, i))
7148 path.Append(wszLibName);
7151 if (!pathFromCodebase.EqualsCaseInsensitive(path, PEImage::GetFileSystemLocale()))
7153 hmod = LocalLoadLibraryHelper(pathFromCodebase, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7157 #endif // !FEATURE_CORECLR
7161 // This call searches the application directory instead of the location for the library.
7164 hmod = LocalLoadLibraryHelper(wszLibName, dllImportSearchPathFlag, pErrorTracker);
7167 // This may be an assembly name
7170 // Format is "fileName, assemblyDisplayName"
7171 MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
7172 char *szComma = strchr(szLibName, ',');
7176 while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
7179 if (SUCCEEDED(spec.Init(szComma)))
7181 // Need to perform case insensitive hashing.
7184 UTF8_TO_LOWER_CASE(szLibName, qbLC);
7185 szLibName = (LPUTF8) qbLC.Ptr();
7188 Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
7189 Module *pModule = pAssembly->FindModuleByName(szLibName);
7191 hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7199 // P/Invokes are often declared with variations on the actual library name.
7200 // For example, it's common to leave off the extension/suffix of the library
7201 // even if it has one, or to leave off a prefix like "lib" even if it has one
7202 // (both of these are typically done to smooth over cross-platform differences).
7203 // We try to dlopen with such variations on the original.
7204 const char* const prefixSuffixCombinations[] =
7206 "%s%s%s", // prefix+name+suffix
7207 "%.0s%s%s", // name+suffix
7208 "%s%s%.0s", // prefix+name
7211 const int NUMBER_OF_LIB_NAME_VARIATIONS = COUNTOF(prefixSuffixCombinations);
7213 // Try to load from places we tried above, but this time with variations on the
7214 // name including the prefix, suffix, and both.
7215 for (int i = 0; i < NUMBER_OF_LIB_NAME_VARIATIONS; i++)
7217 SString currLibNameVariation;
7218 currLibNameVariation.Printf(prefixSuffixCombinations[i], PAL_SHLIB_PREFIX, name, PAL_SHLIB_SUFFIX);
7220 if (libNameIsRelativePath && searchAssemblyDirectory)
7222 Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly();
7223 hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7228 hmod = LoadFromNativeDllSearchDirectories(pDomain, currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
7232 hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlag, pErrorTracker);
7237 #endif // FEATURE_PAL
7239 // After all this, if we have a handle add it to the cache.
7242 pDomain->AddUnmanagedImageToCache(wszLibName, hmod);
7245 return hmod.Extract();
7248 //---------------------------------------------------------
7249 // Loads the DLL and finds the procaddress for an N/Direct call.
7250 //---------------------------------------------------------
7252 VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
7257 PRECONDITION(CheckPointer(pMD));
7262 // On the phone, we only allow platform assemblies to define pinvokes
7263 // unless the host has asked us otherwise.
7266 if (pMD->IsClassConstructorTriggeredAtLinkTime())
7268 pMD->GetMethodTable()->CheckRunClassInitThrowing();
7273 LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget;
7275 // Do not repeat the lookup if the QCall was hardbound during ngen
7276 if (pvTarget == NULL)
7278 pvTarget = ECall::GetQCallImpl(pMD);
7282 _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD));
7285 pMD->SetNDirectTarget(pvTarget);
7289 // Loading unmanaged dlls can trigger dllmains which certainly count as code execution!
7290 pMD->EnsureActive();
7292 LoadLibErrorTracker errorTracker;
7294 BOOL fSuccess = FALSE;
7295 HINSTANCE hmod = LoadLibraryModule( pMD, &errorTracker );
7298 LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
7302 #ifdef MDA_SUPPORTED
7303 MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke);
7304 if (pOverlapCheck && pOverlapCheck->ShouldHook(pMD))
7306 LPVOID pNewTarget = pOverlapCheck->Register(hmod,pvTarget);
7309 pvTarget = pNewTarget;
7313 pMD->SetNDirectTarget(pvTarget);
7320 if (pMD->GetLibName() == NULL)
7321 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME);
7323 StackSString ssLibName(SString::Utf8, pMD->GetLibName());
7327 errorTracker.Throw(ssLibName);
7330 WCHAR wszEPName[50];
7331 if(WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0)
7333 wszEPName[0] = W('?');
7334 wszEPName[1] = W('\0');
7337 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS, ssLibName.GetUnicode(), wszEPName);
7342 //---------------------------------------------------------
7344 //---------------------------------------------------------
7345 /*static*/ void NDirect::Init()
7352 INJECT_FAULT(COMPlusThrowOM());
7356 #if !defined(FEATURE_CORECLR)
7357 // Generate a table of some well known native dlls
7358 s_pWellKnownNativeModules = ::new PtrHashMap();
7359 s_pWellKnownNativeModules->Init(sizeof(wellKnownModules)/sizeof(LPCWSTR), CompareLibNames, TRUE, NULL);
7360 for (int index = 0; index < sizeof(wellKnownModules)/sizeof(LPCWSTR); index++)
7362 s_pWellKnownNativeModules->InsertValue((UPTR) HashiString(wellKnownModules[index]), (LPVOID)wellKnownModules[index]);
7365 // Check if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
7366 HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
7367 _ASSERTE(hMod != NULL);
7369 if (GetProcAddress(hMod, "AddDllDirectory") != NULL)
7371 // The AddDllDirectory export was added in KB2533623 together with the new flag support
7372 s_fSecureLoadLibrarySupported = true;
7374 #endif // !FEATURE_CORECLR
7378 //==========================================================================
7379 // This function is reached only via NDirectImportThunk. It's purpose
7380 // is to ensure that the target DLL is fully loaded and ready to run.
7382 // FUN FACTS: Though this function is actually entered in unmanaged mode,
7383 // it can reenter managed mode and throw a COM+ exception if the DLL linking
7385 //==========================================================================
7388 EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD)
7392 BEGIN_PRESERVE_LAST_ERROR;
7403 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7404 // this function is called by CLR to native assembly stubs which are called by
7405 // managed code as a result, we need an unwind and continue handler to translate
7406 // any of our internal exceptions into managed exceptions.
7407 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7409 #ifdef FEATURE_MIXEDMODE // IJW
7410 if (pMD->IsEarlyBound())
7412 if (!pMD->IsZapped())
7414 // we need the MD to be populated in case we decide to build an intercept
7415 // stub to wrap the target in InitEarlyBoundNDirectTarget
7416 PInvokeStaticSigInfo sigInfo;
7417 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7420 pMD->InitEarlyBoundNDirectTarget();
7423 #endif // FEATURE_MIXEDMODE
7426 // Otherwise we're in an inlined pinvoke late bound MD
7428 INDEBUG(Thread *pThread = GetThread());
7430 _ASSERTE(pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr());
7432 CONSISTENCY_CHECK(pMD->IsNDirect());
7434 // With IL stubs, we don't have to do anything but ensure the DLL is loaded.
7437 if (!pMD->GetModule()->GetSecurityDescriptor()->CanCallUnmanagedCode())
7438 Security::ThrowSecurityException(g_SecurityPermissionClassName, SPFLAGSUNMANAGEDCODE);
7440 if (!pMD->IsZapped())
7442 PInvokeStaticSigInfo sigInfo;
7443 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7447 // must have been populated at NGEN time
7448 _ASSERTE(pMD->GetLibName() != NULL);
7451 pMD->CheckRestore();
7453 NDirect::NDirectLink(pMD);
7457 ret = pMD->GetNDirectTarget();
7459 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7460 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7462 END_PRESERVE_LAST_ERROR;
7467 //===========================================================================
7468 // Support for Pinvoke Calli instruction
7470 //===========================================================================
7472 EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
7474 BEGIN_PRESERVE_LAST_ERROR;
7476 STATIC_CONTRACT_THROWS;
7477 STATIC_CONTRACT_GC_TRIGGERS;
7478 STATIC_CONTRACT_MODE_COOPERATIVE;
7479 STATIC_CONTRACT_ENTRY_POINT;
7481 MAKE_CURRENT_THREAD_AVAILABLE();
7484 Thread::ObjectRefFlush(CURRENT_THREAD);
7487 FrameWithCookie<PrestubMethodFrame> frame(pTransitionBlock, pMD);
7488 PrestubMethodFrame * pFrame = &frame;
7490 pFrame->Push(CURRENT_THREAD);
7492 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7493 _ASSERTE(pMD == pFrame->GetFunction());
7495 GetILStubForCalli(pVASigCookie, pMD);
7497 pFrame->Pop(CURRENT_THREAD);
7499 END_PRESERVE_LAST_ERROR;
7502 EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
7504 BEGIN_PRESERVE_LAST_ERROR;
7506 STATIC_CONTRACT_THROWS;
7507 STATIC_CONTRACT_GC_TRIGGERS;
7508 STATIC_CONTRACT_MODE_COOPERATIVE;
7509 STATIC_CONTRACT_ENTRY_POINT;
7511 MAKE_CURRENT_THREAD_AVAILABLE();
7514 Thread::ObjectRefFlush(CURRENT_THREAD);
7517 FrameWithCookie<PInvokeCalliFrame> frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget);
7518 PInvokeCalliFrame * pFrame = &frame;
7520 pFrame->Push(CURRENT_THREAD);
7522 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7524 GetILStubForCalli(pVASigCookie, NULL);
7526 pFrame->Pop(CURRENT_THREAD);
7528 END_PRESERVE_LAST_ERROR;
7531 PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
7539 PRECONDITION(CheckPointer(pVASigCookie));
7540 PRECONDITION(CheckPointer(pMD, NULL_OK));
7541 POSTCONDITION(RETVAL != NULL);
7545 PCODE pTempILStub = NULL;
7547 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7548 // this function is called by CLR to native assembly stubs which are called by
7549 // managed code as a result, we need an unwind and continue handler to translate
7550 // any of our internal exceptions into managed exceptions.
7551 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7553 // Force a GC if the stress level is high enough
7554 GCStress<cfg_any>::MaybeTrigger();
7558 Signature signature = pVASigCookie->signature;
7559 CorPinvokeMap unmgdCallConv = pmNoMangle;
7561 DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
7563 // The MethodDesc pointer may in fact be the unmanaged target, see PInvokeStubs.asm.
7564 if (pMD == NULL || (UINT_PTR)pMD & 0x1)
7567 dwStubFlags |= NDIRECTSTUB_FL_UNMANAGED_CALLI;
7569 // need to convert the CALLI signature to stub signature with managed calling convention
7570 switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->signature))
7572 case IMAGE_CEE_CS_CALLCONV_C:
7573 unmgdCallConv = pmCallConvCdecl;
7575 case IMAGE_CEE_CS_CALLCONV_STDCALL:
7576 unmgdCallConv = pmCallConvStdcall;
7578 case IMAGE_CEE_CS_CALLCONV_THISCALL:
7579 unmgdCallConv = pmCallConvThiscall;
7581 case IMAGE_CEE_CS_CALLCONV_FASTCALL:
7582 unmgdCallConv = pmCallConvFastcall;
7585 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
7588 LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
7589 PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
7590 CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
7592 // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT
7593 *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK;
7594 *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT;
7596 signature = Signature(new_sig, signature.GetRawSigLen());
7600 _ASSERTE(pMD->IsNDirect());
7601 dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
7603 // vararg P/Invoke must be cdecl
7604 unmgdCallConv = pmCallConvCdecl;
7606 if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
7608 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
7613 CorNativeLinkFlags nlFlags;
7614 CorNativeLinkType nlType;
7618 PInvokeStaticSigInfo sigInfo(pMD);
7620 md = pMD->GetMemberDef();
7621 nlFlags = sigInfo.GetLinkFlags();
7622 nlType = sigInfo.GetCharSet();
7626 md = mdMethodDefNil;
7631 StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule);
7633 MethodDesc* pStubMD = NDirect::CreateCLRToNativeILStub(&sigDesc,
7639 pTempILStub = JitILStub(pStubMD);
7641 InterlockedCompareExchangeT<PCODE>(&pVASigCookie->pNDirectILStub,
7645 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7646 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7648 RETURN pVASigCookie->pNDirectILStub;
7651 #endif // CROSSGEN_COMPILE
7653 #endif // #ifndef DACCESS_COMPILE
7656 // Truncates a SString by first converting it to unicode and truncate it
7657 // if it is larger than size. "..." will be appened if it is truncated.
7659 void TruncateUnicodeString(SString &string, COUNT_T bufSize)
7662 if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize)
7664 _ASSERTE(bufSize / sizeof(WCHAR) > 4);
7665 string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4);
7666 string.Append(W("..."));