2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include "dllimport.h"
22 #include "siginfo.hpp"
24 #include "comdelegate.h"
28 #include "comutilnative.h"
30 #include "asmconstants.h"
31 #include "mdaassistants.h"
32 #include "customattribute.h"
33 #include "ilstubcache.h"
34 #include "typeparse.h"
35 #include "sigbuilder.h"
36 #include "sigformat.h"
37 #include "strongnameholders.h"
40 #include <formattype.h>
41 #include "../md/compiler/custattr.h"
43 #ifdef FEATURE_COMINTEROP
44 #include "runtimecallablewrapper.h"
45 #include "clrtocomcall.h"
46 #endif // FEATURE_COMINTEROP
50 #endif // FEATURE_PREJIT
52 #include "eventtrace.h"
54 #ifndef FEATURE_CORECLR
56 #include "fxretarget.h"
59 // remove when we get an updated SDK
60 #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
61 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
63 void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx)
65 LIMITED_METHOD_CONTRACT;
66 if (pClause->kind == ILStubEHClause::kNone)
72 CorExceptionFlag flags;
73 switch (pClause->kind)
75 case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break;
76 case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break;
78 UNREACHABLE_MSG("unexpected ILStubEHClause kind");
80 _ASSERTE(idx < nClauses);
81 pEHSect->Fat.Clauses[idx].Flags = flags;
82 pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset;
83 pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength;
84 pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset;
85 pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength;
86 pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken;
89 VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo)
91 LIMITED_METHOD_CONTRACT;
92 pEHSect->Fat.Kind = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
93 pEHSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses);
96 AppendEHClause(nClauses, pEHSect, pOne, &curIdx);
97 AppendEHClause(nClauses, pEHSect, pTwo, &curIdx);
100 StubSigDesc::StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo /*= NULL*/)
111 if (pSigInfo != NULL)
113 m_sig = pSigInfo->GetSignature();
114 m_pModule = pSigInfo->GetModule();
118 _ASSERTE(pMD != NULL);
119 m_sig = pMD->GetSignature();
120 m_pModule = pMD->GetModule(); // Used for token resolution.
125 m_tkMethodDef = pMD->GetMemberDef();
126 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
127 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
131 m_tkMethodDef = mdMethodDefNil;
132 m_pLoaderModule = m_pModule;
135 INDEBUG(InitDebugNames());
138 StubSigDesc::StubSigDesc(MethodDesc *pMD, Signature sig, Module *pModule)
145 PRECONDITION(!sig.IsEmpty());
146 PRECONDITION(pModule != NULL);
156 m_tkMethodDef = pMD->GetMemberDef();
157 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
158 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
162 m_tkMethodDef = mdMethodDefNil;
163 m_pLoaderModule = m_pModule;
166 INDEBUG(InitDebugNames());
169 #ifndef DACCESS_COMPILE
174 virtual void SetLastError(BOOL fSetLastError) = 0;
175 virtual void BeginEmit(DWORD dwStubFlags) = 0;
176 virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) = 0;
177 virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) = 0;
178 virtual void MarshalLCID(int argIdx) = 0;
180 #ifdef FEATURE_COMINTEROP
181 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray) = 0;
182 virtual void MarshalFactoryReturn() = 0;
183 #endif // FEATURE_COMINTEROP
185 virtual void EmitInvokeTarget(MethodDesc *pStubMD) = 0;
187 virtual void FinishEmit(MethodDesc* pMD) = 0;
191 LIMITED_METHOD_CONTRACT;
195 class ILStubState : public StubState
201 const Signature &signature,
202 SigTypeContext* pTypeContext,
207 MethodDesc* pTargetMD)
208 : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx, fTargetHasThis, fStubHasThis)
210 STANDARD_VM_CONTRACT;
216 void SetLastError(BOOL fSetLastError)
218 LIMITED_METHOD_CONTRACT;
220 m_fSetLastError = fSetLastError;
223 // We use three stub linkers to generate IL stubs. The pre linker is the main one. It does all the marshaling and
224 // then calls the target method. The post return linker is only used to unmarshal the return value after we return
225 // from the target method. The post linker handles all the unmarshaling for by ref arguments and clean-up. It
226 // also checks if we should throw an exception etc.
228 // Currently, we have two "emittable" ILCodeLabel's. The first one is at the beginning of the pre linker. This
229 // label is used to emit code to declare and initialize clean-up flags. Each argument which requires clean-up
230 // emits one flag. This flag is set only after the marshaling is done, and it is checked before we do any clean-up
233 // The second "emittable" ILCodeLabel is at the beginning of the post linker. It is used to emit code which is
234 // not safe to run in the case of an exception. The rest of the post linker is wrapped in a finally, and it contains
235 // with the necessary clean-up which should be executed in both normal and exception cases.
236 void BeginEmit(DWORD dwStubFlags)
239 m_slIL.Begin(dwStubFlags);
240 m_dwStubFlags = dwStubFlags;
243 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
249 PRECONDITION(CheckPointer(pInfo));
253 pInfo->GenerateReturnIL(&m_slIL, argOffset,
254 SF_IsForwardStub(m_dwStubFlags),
255 SF_IsFieldGetterStub(m_dwStubFlags),
256 SF_IsHRESULTSwapping(m_dwStubFlags));
259 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
264 PRECONDITION(CheckPointer(pInfo));
268 pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags));
271 #ifdef FEATURE_COMINTEROP
272 // Marshal the hidden length parameter for the managed parameter in pInfo
273 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray)
275 STANDARD_VM_CONTRACT;
277 pInfo->MarshalHiddenLengthArgument(&m_slIL, SF_IsForwardStub(m_dwStubFlags), isForReturnArray);
279 if (SF_IsReverseStub(m_dwStubFlags))
281 // Hidden length arguments appear explicitly in the native signature
282 // however, they are not in the managed signature.
283 m_slIL.AdjustTargetStackDeltaForExtraParam();
287 void MarshalFactoryReturn()
292 PRECONDITION(SF_IsCOMStub(m_dwStubFlags));
293 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
297 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
298 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
299 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
300 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
306 // create a local to hold the returned pUnk and initialize to 0 in case the factory fails
307 // and we try to release it during cleanup
308 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
309 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
310 pcsSetup->EmitLoadNullPtr();
311 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
313 DWORD dwInnerIInspectableLocalNum = -1;
314 DWORD dwOuterIInspectableLocalNum = -1;
315 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
317 // Create locals to store the outer and inner IInspectable values and initialize to null
318 // Note that we do this in the setup stream so that we're guaranteed to have a null-initialized
319 // value in the cleanup stream
320 LocalDesc locDescOuterIInspectable(ELEMENT_TYPE_I);
321 dwOuterIInspectableLocalNum = pcsSetup->NewLocal(locDescOuterIInspectable);
322 pcsSetup->EmitLoadNullPtr();
323 pcsSetup->EmitSTLOC(dwOuterIInspectableLocalNum);
324 LocalDesc locDescInnerIInspectable(ELEMENT_TYPE_I);
325 dwInnerIInspectableLocalNum = pcsSetup->NewLocal(locDescInnerIInspectable);
326 pcsSetup->EmitLoadNullPtr();
327 pcsSetup->EmitSTLOC(dwInnerIInspectableLocalNum);
334 // For composition factories, add the two extra params
335 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
337 // Get outer IInspectable. The helper will return NULL if this is the "top-level" constructor,
338 // and the appropriate outer pointer otherwise.
339 pcsDispatch->EmitLoadThis();
340 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
341 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_OUTER_INSPECTABLE, 2, 1);
342 pcsDispatch->EmitSTLOC(dwOuterIInspectableLocalNum);
344 // load the outer IInspectable (3rd last argument)
345 pcsDispatch->SetStubTargetArgType(ELEMENT_TYPE_I, false);
346 pcsDispatch->EmitLDLOC(dwOuterIInspectableLocalNum);
348 // pass pointer to where inner non-delegating IInspectable should be stored (2nd last argument)
349 LocalDesc locDescInnerPtr(ELEMENT_TYPE_I);
350 locDescInnerPtr.MakeByRef();
351 pcsDispatch->SetStubTargetArgType(&locDescInnerPtr, false);
352 pcsDispatch->EmitLDLOCA(dwInnerIInspectableLocalNum);
355 // pass pointer to the local to the factory method (last argument)
356 locDescFactoryRetVal.MakeByRef();
357 pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
358 pcsDispatch->EmitLDLOCA(dwFactoryRetValLocalNum);
364 // Mark that the factory method has succesfully returned and so cleanup will be necessary after
366 m_slIL.EmitSetArgMarshalIndex(pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
368 // associate the 'this' RCW with one of the returned interface pointers
369 pcsUnmarshal->EmitLoadThis();
371 // now we need to find the right interface pointer to load
372 if (dwInnerIInspectableLocalNum != -1)
374 // We may have a composition scenario
375 ILCodeLabel* pNonCompositionLabel = pcsUnmarshal->NewCodeLabel();
376 ILCodeLabel* pLoadedLabel = pcsUnmarshal->NewCodeLabel();
378 // Did we pass an outer IInspectable?
379 pcsUnmarshal->EmitLDLOC(dwOuterIInspectableLocalNum);
380 pcsUnmarshal->EmitBRFALSE(pNonCompositionLabel);
382 // yes, this is a composition scenario
384 // ignore the delegating interface pointer (will be released in cleanup below) - we can
385 // re-create it by QI'ing the non-delegating one.
386 // Note that using this could be useful in the future (avoids an extra QueryInterface call)
387 // Just load the non-delegating interface pointer
388 pcsUnmarshal->EmitLDLOCA(dwInnerIInspectableLocalNum);
389 pcsUnmarshal->EmitBR(pLoadedLabel);
391 // else, no this is a non-composition scenario
393 pcsUnmarshal->EmitLabel(pNonCompositionLabel);
395 // ignore the non-delegating interface pointer (which should be null, but will regardless get
396 // cleaned up below in the event the factory doesn't follow the pattern properly).
397 // Just load the regular delegating interface pointer
398 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
401 pcsUnmarshal->EmitLabel(pLoadedLabel);
405 // Definitely can't be a composition scenario - use the only pointer we have
406 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
409 pcsUnmarshal->EmitCALL(METHOD__MARSHAL__INITIALIZE_WRAPPER_FOR_WINRT, 2, 0);
415 // release the returned interface pointer in the finally block
416 m_slIL.SetCleanupNeeded();
418 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
420 m_slIL.EmitCheckForArgCleanup(pcsCleanup,
421 NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
422 NDirectStubLinker::BranchIfNotMarshaled,
425 EmitInterfaceClearNative(pcsCleanup, dwFactoryRetValLocalNum);
427 // Note that it's a no-op to pass NULL to Clear_Native, so we call it even though we don't
428 // know if we assigned to the inner/outer IInspectable
429 if (dwInnerIInspectableLocalNum != -1)
431 EmitInterfaceClearNative(pcsCleanup, dwInnerIInspectableLocalNum);
433 if (dwOuterIInspectableLocalNum != -1)
435 EmitInterfaceClearNative(pcsCleanup, dwOuterIInspectableLocalNum);
438 pcsCleanup->EmitLabel(pSkipCleanupLabel);
441 static void EmitInterfaceClearNative(ILCodeStream* pcsEmit, DWORD dwLocalNum)
443 STANDARD_VM_CONTRACT;
445 ILCodeLabel *pSkipClearNativeLabel = pcsEmit->NewCodeLabel();
446 pcsEmit->EmitLDLOC(dwLocalNum);
447 pcsEmit->EmitBRFALSE(pSkipClearNativeLabel);
448 pcsEmit->EmitLDLOC(dwLocalNum);
449 pcsEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
450 pcsEmit->EmitLabel(pSkipClearNativeLabel);
453 #endif // FEATURE_COMINTEROP
455 void MarshalLCID(int argIdx)
457 STANDARD_VM_CONTRACT;
459 ILCodeStream* pcs = m_slIL.GetDispatchCodeStream();
461 #ifdef FEATURE_USE_LCID
462 if (SF_IsReverseStub(m_dwStubFlags))
464 if ((m_slIL.GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_HASTHIS) == IMAGE_CEE_CS_CALLCONV_HASTHIS)
466 // the arg number will be incremented by LDARG if we are in an instance method
467 _ASSERTE(argIdx > 0);
471 LocalDesc locDescThread(MscorlibBinder::GetClass(CLASS__THREAD));
472 DWORD dwThreadLocalNum = pcs->NewLocal(locDescThread);
474 // call Thread.get_CurrentThread()
475 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
477 pcs->EmitSTLOC(dwThreadLocalNum);
479 // call current_thread.get_CurrentCulture()
480 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
482 // save the current culture
483 LocalDesc locDescCulture(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
484 DWORD dwCultureLocalNum = pcs->NewLocal(locDescCulture);
486 pcs->EmitSTLOC(dwCultureLocalNum);
488 // set a new one based on the LCID passed from unmanaged
489 pcs->EmitLDLOC(dwThreadLocalNum);
490 pcs->EmitLDARG(argIdx);
492 // call CultureInfo..ctor(lcid)
493 // call current_thread.set_CurrentCulture(culture)
494 pcs->EmitNEWOBJ(METHOD__CULTURE_INFO__INT_CTOR, 1);
495 pcs->EmitCALL(METHOD__THREAD__SET_CULTURE, 2, 0);
497 // and restore the current one after the call
498 m_slIL.SetCleanupNeeded();
499 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
501 // call current_thread.set_CurrentCulture(original_culture)
502 pcsCleanup->EmitLDLOC(dwThreadLocalNum);
503 pcsCleanup->EmitLDLOC(dwCultureLocalNum);
504 pcsCleanup->EmitCALL(METHOD__THREAD__SET_CULTURE, 1, 1);
509 if (SF_IsCOMStub(m_dwStubFlags))
511 // We used to get LCID from current thread's culture here. The code
512 // was replaced by the hardcoded LCID_ENGLISH_US as requested by VSTO.
513 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
517 // call Thread.get_CurrentThread()
518 // call current_thread.get_CurrentCulture()
519 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
520 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
522 //call CultureInfo.get_LCID(this)
523 pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1);
526 #else // FEATURE_USE_LCID
527 if (SF_IsForwardStub(m_dwStubFlags))
529 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
531 #endif // FEATURE_USE_LCID
533 // add the extra arg to the unmanaged signature
534 LocalDesc locDescNative(ELEMENT_TYPE_I4);
535 pcs->SetStubTargetArgType(&locDescNative, false);
537 if (SF_IsReverseStub(m_dwStubFlags))
539 // reverse the effect of SetStubTargetArgType on the stack delta
540 // (the LCID argument is explicitly passed from unmanaged but does not
541 // show up in the managed signature in any way)
542 m_slIL.AdjustTargetStackDeltaForExtraParam();
547 void SwapStubSignatures(MethodDesc* pStubMD)
549 STANDARD_VM_CONTRACT;
552 // Since the stub handles native-to-managed transitions, we have to swap the
553 // stub-state-calculated stub target sig with the stub sig itself. This is
554 // because the stub target sig represents the native signature and the stub
555 // sig represents the managed signature.
557 // The first step is to convert the managed signature to a module-independent
558 // signature and then pass it off to SetStubTargetMethodSig. Note that the
559 // ILStubResolver will copy the sig, so we only need to make a temporary copy
562 SigBuilder sigBuilder;
565 SigPointer sigPtr(pStubMD->GetSig());
566 sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder);
570 // The second step is to reset the sig on the stub MethodDesc to be the
571 // stub-state-calculated stub target sig.
575 // make a domain-local copy of the sig so that this state can outlive the
576 // compile time state.
579 PCCOR_SIGNATURE pNewSig;
581 cbNewSig = GetStubTargetMethodSigLength();
582 pNewSig = (PCCOR_SIGNATURE)(void *)pStubMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig));
584 memcpyNoGCRefs((void *)pNewSig, GetStubTargetMethodSig(), cbNewSig);
586 pStubMD->AsDynamicMethodDesc()->SetStoredMethodSig(pNewSig, cbNewSig);
588 SigPointer sigPtr(pNewSig, cbNewSig);
590 IfFailThrow(sigPtr.GetCallingConvInfo(&callConvInfo));
592 if (callConvInfo & CORINFO_CALLCONV_HASTHIS)
594 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags &= ~mdStatic;
595 pStubMD->ClearStatic();
599 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags |= mdStatic;
600 pStubMD->SetStatic();
604 // we store the real managed argument stack size in the stub MethodDesc on non-X86
605 UINT stackSize = pStubMD->SizeOfArgStack();
607 if (!FitsInU2(stackSize))
608 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
610 pStubMD->AsDynamicMethodDesc()->SetNativeStackArgSize(static_cast<WORD>(stackSize));
611 #endif // _TARGET_X86_
614 DWORD cbTempModuleIndependentSigLength;
615 BYTE * pTempModuleIndependentSig = (BYTE *)sigBuilder.GetSignature(&cbTempModuleIndependentSigLength);
618 SetStubTargetMethodSig(pTempModuleIndependentSig,
619 cbTempModuleIndependentSigLength);
622 void EmitInvokeTarget(MethodDesc *pStubMD)
624 STANDARD_VM_CONTRACT;
626 m_slIL.DoNDirect(m_slIL.GetDispatchCodeStream(), m_dwStubFlags, pStubMD);
629 #ifdef FEATURE_COMINTEROP
630 void EmitExceptionHandler(LocalDesc* pNativeReturnType, LocalDesc* pManagedReturnType,
631 ILCodeLabel** ppTryEndAndCatchBeginLabel, ILCodeLabel ** ppCatchEndAndReturnLabel)
633 STANDARD_VM_CONTRACT;
635 ILCodeStream* pcsExceptionHandler = m_slIL.NewCodeStream(ILStubLinker::kExceptionHandler);
636 *ppTryEndAndCatchBeginLabel = pcsExceptionHandler->NewCodeLabel();
637 *ppCatchEndAndReturnLabel = pcsExceptionHandler->NewCodeLabel();
639 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
640 pcsExceptionHandler->EmitLabel(*ppTryEndAndCatchBeginLabel);
642 BYTE nativeReturnElemType = pNativeReturnType->ElementType[0]; // return type of the stub
643 BYTE managedReturnElemType = pManagedReturnType->ElementType[0]; // return type of the mananged target
645 bool returnTheHRESULT = SF_IsHRESULTSwapping(m_dwStubFlags) ||
646 (managedReturnElemType == ELEMENT_TYPE_I4) ||
647 (managedReturnElemType == ELEMENT_TYPE_U4);
650 if (!returnTheHRESULT)
652 MdaExceptionSwallowedOnCallFromCom* mda = MDA_GET_ASSISTANT(ExceptionSwallowedOnCallFromCom);
655 // on the stack: exception object, but the stub linker doesn't know it
656 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
657 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__TRIGGER_EXCEPTION_SWALLOWED_MDA,
658 1, // WARNING: This method takes 2 input args, the exception object and the stub context.
659 // But the ILStubLinker has no knowledge that the exception object is on the
660 // stack (because it is unaware that we've just entered a catch block), so we
661 // lie and claim that we only take one input argument.
662 1); // returns the exception object back
665 #endif // MDA_SUPPORTED
667 DWORD retvalLocalNum = m_slIL.GetReturnValueLocalNum();
668 BinderMethodID getHRForException;
669 if (SF_IsWinRTStub(m_dwStubFlags))
671 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION_WINRT;
675 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION;
678 pcsExceptionHandler->EmitCALL(getHRForException,
679 0, // WARNING: This method takes 1 input arg, the exception object. But the ILStubLinker
680 // has no knowledge that the exception object is on the stack (because it is
681 // unaware that we've just entered a catch block), so we lie and claim that we
682 // don't take any input arguments.
685 switch (nativeReturnElemType)
688 UNREACHABLE_MSG("Unexpected element type found on native return type.");
690 case ELEMENT_TYPE_VOID:
691 _ASSERTE(retvalLocalNum == (DWORD)-1);
692 pcsExceptionHandler->EmitPOP();
694 case ELEMENT_TYPE_I4:
695 case ELEMENT_TYPE_U4:
697 if (!returnTheHRESULT)
699 pcsExceptionHandler->EmitPOP();
700 pcsExceptionHandler->EmitLDC(0);
701 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
703 _ASSERTE(retvalLocalNum != (DWORD)-1);
704 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
707 case ELEMENT_TYPE_R4:
708 pcsExceptionHandler->EmitPOP();
709 pcsExceptionHandler->EmitLDC_R4(CLR_NAN_32);
710 _ASSERTE(retvalLocalNum != (DWORD)-1);
711 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
713 case ELEMENT_TYPE_R8:
714 pcsExceptionHandler->EmitPOP();
715 pcsExceptionHandler->EmitLDC_R8(CLR_NAN_64);
716 _ASSERTE(retvalLocalNum != (DWORD)-1);
717 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
719 case ELEMENT_TYPE_INTERNAL:
721 TypeHandle returnTypeHnd = pNativeReturnType->InternalToken;
722 CONSISTENCY_CHECK(returnTypeHnd.IsValueType());
723 _ASSERTE(retvalLocalNum != (DWORD)-1);
724 pcsExceptionHandler->EmitLDLOCA(retvalLocalNum);
725 pcsExceptionHandler->EmitINITOBJ(m_slIL.GetDispatchCodeStream()->GetToken(returnTypeHnd));
728 case ELEMENT_TYPE_BOOLEAN:
729 case ELEMENT_TYPE_CHAR:
730 case ELEMENT_TYPE_I1:
731 case ELEMENT_TYPE_U1:
732 case ELEMENT_TYPE_I2:
733 case ELEMENT_TYPE_U2:
734 case ELEMENT_TYPE_I8:
735 case ELEMENT_TYPE_U8:
738 pcsExceptionHandler->EmitPOP();
739 pcsExceptionHandler->EmitLDC(0);
740 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
741 _ASSERTE(retvalLocalNum != (DWORD)-1);
742 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
746 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
747 pcsExceptionHandler->EmitLabel(*ppCatchEndAndReturnLabel);
748 if (nativeReturnElemType != ELEMENT_TYPE_VOID)
750 _ASSERTE(retvalLocalNum != (DWORD)-1);
751 pcsExceptionHandler->EmitLDLOC(retvalLocalNum);
753 pcsExceptionHandler->EmitRET();
755 #endif // FEATURE_COMINTEROP
757 void FinishEmit(MethodDesc* pStubMD)
759 STANDARD_VM_CONTRACT;
761 ILCodeStream* pcsMarshal = m_slIL.GetMarshalCodeStream();
762 ILCodeStream* pcsUnmarshal = m_slIL.GetUnmarshalCodeStream();
763 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
765 if (SF_IsHRESULTSwapping(m_dwStubFlags) && m_slIL.StubHasVoidReturnType())
767 // if the return type is void, but we're doing HRESULT swapping, we
768 // need to set the return type here. Otherwise, the return value
769 // marshaler will do this.
770 pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4); // HRESULT
772 if (SF_IsReverseStub(m_dwStubFlags))
774 // reverse interop needs to seed the return value if the
775 // managed function returns void but we're doing hresult
777 pcsUnmarshal->EmitLDC(S_OK);
781 LocalDesc nativeReturnType;
782 LocalDesc managedReturnType;
783 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(m_dwStubFlags)
784 && !SF_IsFieldGetterStub(m_dwStubFlags)
785 && !SF_IsFieldSetterStub(m_dwStubFlags);
787 #ifdef FEATURE_COMINTEROP
788 if (hasTryCatchForHRESULT)
790 m_slIL.GetStubTargetReturnType(&nativeReturnType);
791 m_slIL.GetStubReturnType(&managedReturnType);
793 #endif // FEATURE_COMINTEROP
795 if (SF_IsHRESULTSwapping(m_dwStubFlags) && SF_IsReverseStub(m_dwStubFlags))
797 m_slIL.AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
800 if (SF_IsForwardCOMStub(m_dwStubFlags))
802 // Compensate for the 'this' parameter.
803 m_slIL.AdjustTargetStackDeltaForExtraParam();
806 #if defined(_TARGET_X86_)
807 // unmanaged CALLI will get an extra arg with the real target address if host hook is enabled
808 if (SF_IsCALLIStub(m_dwStubFlags) && NDirect::IsHostHookEnabled())
810 pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I, false);
812 #endif // _TARGET_X86_
814 // Don't touch target signatures from this point on otherwise it messes up the
815 // cache in ILStubState::GetStubTargetMethodSig.
819 // The native and local signatures should not have any tokens.
820 // All token references should have been converted to
821 // ELEMENT_TYPE_INTERNAL.
823 // Note that MetaSig::GetReturnType and NextArg will normalize
824 // ELEMENT_TYPE_INTERNAL back to CLASS or VALUETYPE.
826 // <TODO> need to recursively check ELEMENT_TYPE_FNPTR signatures </TODO>
828 SigTypeContext typeContext; // this is an empty type context: COM calls are guaranteed to not be generics.
830 GetStubTargetMethodSig(),
831 GetStubTargetMethodSigLength(),
832 MscorlibBinder::GetModule(),
836 IfFailThrow(nsig.GetReturnProps().PeekElemType(&type));
837 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
839 while (ELEMENT_TYPE_END != (type = nsig.NextArg()))
841 IfFailThrow(nsig.GetArgProps().PeekElemType(&type));
842 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
847 #ifdef FEATURE_COMINTEROP
848 if (SF_IsForwardCOMStub(m_dwStubFlags))
850 #if defined(MDA_SUPPORTED)
851 // We won't use this NGEN'ed stub if RaceOnRCWCleanup is enabled at run-time
852 if (!SF_IsNGENedStub(m_dwStubFlags))
854 // This code may change the type of the frame we use, so it has to be run before the code below where we
855 // retrieve the stack arg size based on the frame type.
856 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
859 // Here we have to register the RCW of the "this" object to the RCWStack and schedule the clean-up for it.
860 // Emit a call to StubHelpers::StubRegisterRCW() and StubHelpers::StubUnregisterRCW() to do this.
861 m_slIL.EmitLoadRCWThis(pcsMarshal, m_dwStubFlags);
862 pcsMarshal->EmitCALL(METHOD__STUBHELPERS__STUB_REGISTER_RCW, 1, 0);
864 // We use an extra local to track whether we need to unregister the RCW on cleanup
865 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
866 DWORD dwRCWRegisteredLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
867 pcsSetup->EmitLDC(0);
868 pcsSetup->EmitSTLOC(dwRCWRegisteredLocalNum);
870 pcsMarshal->EmitLDC(1);
871 pcsMarshal->EmitSTLOC(dwRCWRegisteredLocalNum);
873 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
874 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
876 m_slIL.SetCleanupNeeded();
877 pcsCleanup->EmitLDLOC(dwRCWRegisteredLocalNum);
878 pcsCleanup->EmitBRFALSE(pSkipCleanupLabel);
880 m_slIL.EmitLoadRCWThis(pcsCleanup, m_dwStubFlags);
881 pcsCleanup->EmitCALL(METHOD__STUBHELPERS__STUB_UNREGISTER_RCW, 1, 0);
883 pcsCleanup->EmitLabel(pSkipCleanupLabel);
886 #endif // MDA_SUPPORTED
888 #endif // FEATURE_COMINTEROP
891 // The profiler helpers below must be called immediately before and after the call to the target.
892 // The debugger trace call helpers are invoked from StubRareDisableWorker
895 #if defined(PROFILING_SUPPORTED)
896 DWORD dwMethodDescLocalNum = -1;
898 // Notify the profiler of call out of the runtime
899 if (!SF_IsReverseCOMStub(m_dwStubFlags) && (CORProfilerTrackTransitions() || SF_IsNGENedStubForProfiling(m_dwStubFlags)))
901 dwMethodDescLocalNum = m_slIL.EmitProfilerBeginTransitionCallback(pcsDispatch, m_dwStubFlags);
902 _ASSERTE(dwMethodDescLocalNum != -1);
904 #endif // PROFILING_SUPPORTED
907 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
908 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
910 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
912 #endif // MDA_SUPPORTED
914 #ifdef FEATURE_CORECLR
915 // For CoreClr, clear the last error before calling the target that returns last error.
916 // There isn't always a way to know the function have failed without checking last error,
917 // in particular on Unix.
918 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
920 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CLEAR_LAST_ERROR, 0, 0);
922 #endif // FEATURE_CORECLR
924 // Invoke the target (calli, call method, call delegate, get/set field, etc.)
925 EmitInvokeTarget(pStubMD);
927 // Saving last error must be the first thing we do after returning from the target
928 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
930 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__SET_LAST_ERROR, 0, 0);
933 #if defined(_TARGET_X86_)
934 if (SF_IsForwardDelegateStub(m_dwStubFlags))
936 // the delegate may have an intercept stub attached to its sync block so we should
937 // prevent it from being garbage collected when the call is in progress
938 pcsDispatch->EmitLoadThis();
939 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
941 #endif // defined(_TARGET_X86_)
944 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
945 MDA_GET_ASSISTANT(GcUnmanagedToManaged))
947 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
949 #endif // MDA_SUPPORTED
952 if (SF_IsForwardStub(m_dwStubFlags) && g_pConfig->InteropValidatePinnedObjects())
954 // call StubHelpers.ValidateObject/StubHelpers.ValidateByref on pinned locals
955 m_slIL.EmitObjectValidation(pcsDispatch, m_dwStubFlags);
957 #endif // VERIFY_HEAP
959 #if defined(PROFILING_SUPPORTED)
960 // Notify the profiler of return back into the runtime
961 if (dwMethodDescLocalNum != -1)
963 m_slIL.EmitProfilerEndTransitionCallback(pcsDispatch, m_dwStubFlags, dwMethodDescLocalNum);
965 #endif // PROFILING_SUPPORTED
967 #ifdef FEATURE_COMINTEROP
968 if (SF_IsForwardCOMStub(m_dwStubFlags))
970 // Make sure that the RCW stays alive for the duration of the call. Note that if we do HRESULT
971 // swapping, we'll pass 'this' to GetCOMHRExceptionObject after returning from the target so
972 // GC.KeepAlive is not necessary.
973 if (!SF_IsHRESULTSwapping(m_dwStubFlags))
975 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
976 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
979 #endif // FEATURE_COMINTEROP
981 if (SF_IsHRESULTSwapping(m_dwStubFlags))
983 if (SF_IsForwardStub(m_dwStubFlags))
985 ILCodeLabel* pSkipThrowLabel = pcsDispatch->NewCodeLabel();
987 pcsDispatch->EmitDUP();
988 pcsDispatch->EmitLDC(0);
989 pcsDispatch->EmitBGE(pSkipThrowLabel);
991 #ifdef FEATURE_COMINTEROP
992 if (SF_IsCOMStub(m_dwStubFlags))
994 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
995 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
997 if (SF_IsWinRTStub(m_dwStubFlags))
999 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT_WINRT, 3, 1);
1003 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT, 3, 1);
1007 #endif // FEATURE_COMINTEROP
1009 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_HR_EXCEPTION_OBJECT, 1, 1);
1012 pcsDispatch->EmitTHROW();
1013 pcsDispatch->EmitLDC(0); // keep the IL stack balanced across the branch and the fall-through
1014 pcsDispatch->EmitLabel(pSkipThrowLabel);
1015 pcsDispatch->EmitPOP();
1019 m_slIL.End(m_dwStubFlags);
1020 if (!hasTryCatchForHRESULT) // we will 'leave' the try scope and then 'ret' from outside
1022 pcsUnmarshal->EmitRET();
1025 DWORD dwJitFlags = CORJIT_FLG_IL_STUB;
1027 if (m_slIL.HasInteropParamExceptionInfo())
1029 // This code will not use the secret parameter, so we do not
1030 // tell the JIT to bother with it.
1032 m_slIL.GenerateInteropParamException(pcsMarshal);
1034 else if (SF_IsFieldGetterStub(m_dwStubFlags) || SF_IsFieldSetterStub(m_dwStubFlags))
1036 // Field access stubs are not shared and do not use the secret parameter.
1039 else if (SF_IsForwardDelegateStub(m_dwStubFlags) ||
1040 (SF_IsForwardCOMStub(m_dwStubFlags) && SF_IsWinRTDelegateStub(m_dwStubFlags)))
1042 // Forward delegate stubs get all the context they need in 'this' so they
1043 // don't use the secret parameter. Except for AMD64 where we use the secret
1044 // argument to pass the real target to the stub-for-host.
1049 // All other IL stubs will need to use the secret parameter.
1050 dwJitFlags |= CORJIT_FLG_PUBLISH_SECRET_PARAM;
1053 if (SF_IsReverseStub(m_dwStubFlags))
1055 SwapStubSignatures(pStubMD);
1058 ILCodeLabel* pTryEndAndCatchBeginLabel = NULL; // try ends at the same place the catch begins
1059 ILCodeLabel* pCatchEndAndReturnLabel = NULL; // catch ends at the same place we resume afterwards
1060 #ifdef FEATURE_COMINTEROP
1061 if (hasTryCatchForHRESULT)
1063 EmitExceptionHandler(&nativeReturnType, &managedReturnType, &pTryEndAndCatchBeginLabel, &pCatchEndAndReturnLabel);
1065 #endif // FEATURE_COMINTEROP
1073 cbCode = m_slIL.Link(&maxStack);
1074 cbSig = m_slIL.GetLocalSigSize();
1076 ILStubResolver * pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
1077 COR_ILMETHOD_DECODER * pILHeader = pResolver->AllocGeneratedIL(cbCode, cbSig, maxStack);
1078 pbBuffer = (BYTE *)pILHeader->Code;
1079 pbLocalSig = (BYTE *)pILHeader->LocalVarSig;
1080 _ASSERTE(cbSig == pILHeader->cbLocalVarSig);
1082 ILStubEHClause cleanupTryFinally = { 0 };
1083 ILStubEHClause convertToHRTryCatch = { 0 };
1084 m_slIL.GetCleanupFinallyOffsets(&cleanupTryFinally);
1086 #ifdef FEATURE_COMINTEROP
1087 if (hasTryCatchForHRESULT)
1089 convertToHRTryCatch.kind = ILStubEHClause::kTypedCatch;
1090 convertToHRTryCatch.dwTryBeginOffset = 0;
1091 convertToHRTryCatch.dwHandlerBeginOffset = ((DWORD)pTryEndAndCatchBeginLabel->GetCodeOffset());
1092 convertToHRTryCatch.cbTryLength = convertToHRTryCatch.dwHandlerBeginOffset - convertToHRTryCatch.dwTryBeginOffset;
1093 convertToHRTryCatch.cbHandlerLength = ((DWORD)pCatchEndAndReturnLabel->GetCodeOffset()) - convertToHRTryCatch.dwHandlerBeginOffset;
1094 convertToHRTryCatch.dwTypeToken = pcsDispatch->GetToken(g_pObjectClass);
1096 #endif // FEATURE_COMINTEROP
1100 if (convertToHRTryCatch.cbHandlerLength != 0)
1103 if (cleanupTryFinally.cbHandlerLength != 0)
1108 COR_ILMETHOD_SECT_EH* pEHSect = pResolver->AllocEHSect(nEHClauses);
1109 PopulateEHSect(pEHSect, nEHClauses, &cleanupTryFinally, &convertToHRTryCatch);
1112 m_slIL.GenerateCode(pbBuffer, cbCode);
1113 m_slIL.GetLocalSig(pbLocalSig, cbSig);
1115 pResolver->SetJitFlags(dwJitFlags);
1118 LOG((LF_STUBS, LL_INFO1000, "---------------------------------------------------------------------\n"));
1119 LOG((LF_STUBS, LL_INFO1000, "NDirect IL stub dump: %s::%s\n", pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
1120 if (LoggingEnabled() && LoggingOn(LF_STUBS, LL_INFO1000))
1122 CQuickBytes qbManaged;
1123 CQuickBytes qbLocal;
1125 PCCOR_SIGNATURE pManagedSig;
1128 IMDInternalImport* pIMDI = MscorlibBinder::GetModule()->GetMDImport();
1130 pStubMD->GetSig(&pManagedSig, &cManagedSig);
1132 PrettyPrintSig(pManagedSig, cManagedSig, "*", &qbManaged, pStubMD->GetMDImport(), NULL);
1133 PrettyPrintSig(pbLocalSig, cbSig, NULL, &qbLocal, pIMDI, NULL);
1135 LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, qbManaged.Ptr()));
1136 LOG((LF_STUBS, LL_INFO1000, "locals sig: %p: %s\n", pbLocalSig+1, qbLocal.Ptr()));
1138 if (cleanupTryFinally.cbHandlerLength != 0)
1140 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x finally_begin: 0x%04x finally_end: 0x%04x \n",
1141 cleanupTryFinally.dwTryBeginOffset, cleanupTryFinally.dwTryBeginOffset + cleanupTryFinally.cbTryLength,
1142 cleanupTryFinally.dwHandlerBeginOffset, cleanupTryFinally.dwHandlerBeginOffset + cleanupTryFinally.cbHandlerLength));
1144 if (convertToHRTryCatch.cbHandlerLength != 0)
1146 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x catch_begin: 0x%04x catch_end: 0x%04x type_token: 0x%08x\n",
1147 convertToHRTryCatch.dwTryBeginOffset, convertToHRTryCatch.dwTryBeginOffset + convertToHRTryCatch.cbTryLength,
1148 convertToHRTryCatch.dwHandlerBeginOffset, convertToHRTryCatch.dwHandlerBeginOffset + convertToHRTryCatch.cbHandlerLength,
1149 convertToHRTryCatch.dwTypeToken));
1152 LogILStubFlags(LF_STUBS, LL_INFO1000, m_dwStubFlags);
1154 m_slIL.LogILStub(dwJitFlags);
1156 LOG((LF_STUBS, LL_INFO1000, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
1159 #ifndef FEATURE_CORECLR
1161 // Publish ETW events for IL stubs
1164 // If the category and the event is enabled...
1165 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ILStubGenerated))
1167 EtwOnILStubGenerated(
1172 &convertToHRTryCatch,
1178 #endif // !FEATURE_CORECLR
1181 #ifndef FEATURE_CORECLR
1182 //---------------------------------------------------------------------------------------
1185 EtwOnILStubGenerated(
1186 MethodDesc * pStubMD,
1187 PCCOR_SIGNATURE pbLocalSig,
1190 ILStubEHClause * pConvertToHRTryCatchBounds,
1191 ILStubEHClause * pCleanupTryFinallyBounds,
1195 STANDARD_VM_CONTRACT;
1198 // Interop Method Information
1200 MethodDesc *pTargetMD = m_slIL.GetTargetMD();
1201 SString strNamespaceOrClassName, strMethodName, strMethodSignature;
1202 UINT64 uModuleId = 0;
1206 pTargetMD->GetMethodInfoWithNewSig(strNamespaceOrClassName, strMethodName, strMethodSignature);
1207 uModuleId = (UINT64)pTargetMD->GetModule()->GetAddrModuleID();
1211 // Stub Method Signature
1213 SString stubNamespaceOrClassName, stubMethodName, stubMethodSignature;
1214 pStubMD->GetMethodInfoWithNewSig(stubNamespaceOrClassName, stubMethodName, stubMethodSignature);
1216 IMDInternalImport *pStubImport = pStubMD->GetModule()->GetMDImport();
1218 CQuickBytes qbLocal;
1219 PrettyPrintSig(pbLocalSig, (DWORD)cbSig, NULL, &qbLocal, pStubImport, NULL);
1221 SString strLocalSig(SString::Utf8, (LPCUTF8)qbLocal.Ptr());
1226 SString strNativeSignature(SString::Utf8);
1227 if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
1229 // Reverse interop. Use StubSignature
1230 strNativeSignature = stubMethodSignature;
1234 // Forward interop. Use StubTarget siganture
1235 PCCOR_SIGNATURE pCallTargetSig = GetStubTargetMethodSig();
1236 DWORD cCallTargetSig = GetStubTargetMethodSigLength();
1238 CQuickBytes qbCallTargetSig;
1240 PrettyPrintSig(pCallTargetSig, cCallTargetSig, "", &qbCallTargetSig, pStubImport, NULL);
1242 strNativeSignature.SetUTF8((LPCUTF8)qbCallTargetSig.Ptr());
1246 // Dump IL stub code
1248 SString strILStubCode;
1249 strILStubCode.Preallocate(4096); // Preallocate 4K bytes to avoid unnecessary growth
1251 SString codeSizeFormat;
1252 codeSizeFormat.LoadResource(CCompRC::Optional, IDS_EE_INTEROP_CODE_SIZE_COMMENT);
1253 strILStubCode.AppendPrintf(W("// %s\t%d (0x%04x)\n"), codeSizeFormat.GetUnicode(), cbCode, cbCode);
1254 strILStubCode.AppendPrintf(W(".maxstack %d \n"), maxStack);
1255 strILStubCode.AppendPrintf(W(".locals %s\n"), strLocalSig.GetUnicode());
1257 m_slIL.LogILStub(dwJitFlags, &strILStubCode);
1259 if (pConvertToHRTryCatchBounds->cbTryLength != 0 && pConvertToHRTryCatchBounds->cbHandlerLength != 0)
1261 strILStubCode.AppendPrintf(
1262 W(".try IL_%04x to IL_%04x catch handler IL_%04x to IL_%04x\n"),
1263 pConvertToHRTryCatchBounds->dwTryBeginOffset,
1264 pConvertToHRTryCatchBounds->dwTryBeginOffset + pConvertToHRTryCatchBounds->cbTryLength,
1265 pConvertToHRTryCatchBounds->dwHandlerBeginOffset,
1266 pConvertToHRTryCatchBounds->dwHandlerBeginOffset + pConvertToHRTryCatchBounds->cbHandlerLength);
1269 if (pCleanupTryFinallyBounds->cbTryLength != 0 && pCleanupTryFinallyBounds->cbHandlerLength != 0)
1271 strILStubCode.AppendPrintf(
1272 W(".try IL_%04x to IL_%04x finally handler IL_%04x to IL_%04x\n"),
1273 pCleanupTryFinallyBounds->dwTryBeginOffset,
1274 pCleanupTryFinallyBounds->dwTryBeginOffset + pCleanupTryFinallyBounds->cbTryLength,
1275 pCleanupTryFinallyBounds->dwHandlerBeginOffset,
1276 pCleanupTryFinallyBounds->dwHandlerBeginOffset + pCleanupTryFinallyBounds->cbHandlerLength);
1283 if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
1284 dwFlags |= ETW_IL_STUB_FLAGS_REVERSE_INTEROP;
1285 #ifdef FEATURE_COMINTEROP
1286 if (m_dwStubFlags & NDIRECTSTUB_FL_COM)
1287 dwFlags |= ETW_IL_STUB_FLAGS_COM_INTEROP;
1288 #endif // FEATURE_COMINTEROP
1289 if (m_dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)
1290 dwFlags |= ETW_IL_STUB_FLAGS_NGENED_STUB;
1291 if (m_dwStubFlags & NDIRECTSTUB_FL_DELEGATE)
1292 dwFlags |= ETW_IL_STUB_FLAGS_DELEGATE;
1293 if (m_dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)
1294 dwFlags |= ETW_IL_STUB_FLAGS_VARARG;
1295 if (m_dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)
1296 dwFlags |= ETW_IL_STUB_FLAGS_UNMANAGED_CALLI;
1300 dwToken = pTargetMD->GetMemberDef();
1304 // Truncate string fields. Make sure the whole event is less than 64KB
1306 TruncateUnicodeString(strNamespaceOrClassName, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1307 TruncateUnicodeString(strMethodName, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1308 TruncateUnicodeString(strMethodSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1309 TruncateUnicodeString(strNativeSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1310 TruncateUnicodeString(stubMethodSignature, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
1311 TruncateUnicodeString(strILStubCode, ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE);
1316 FireEtwILStubGenerated(
1317 GetClrInstanceId(), // ClrInstanceId
1318 uModuleId, // ModuleIdentifier
1319 (UINT64)pStubMD, // StubMethodIdentifier
1320 dwFlags, // StubFlags
1321 dwToken, // ManagedInteropMethodToken
1322 strNamespaceOrClassName.GetUnicode(), // ManagedInteropMethodNamespace
1323 strMethodName.GetUnicode(), // ManagedInteropMethodName
1324 strMethodSignature.GetUnicode(), // ManagedInteropMethodSignature
1325 strNativeSignature.GetUnicode(), // NativeSignature
1326 stubMethodSignature.GetUnicode(), // StubMethodSigature
1327 strILStubCode.GetUnicode() // StubMethodILCode
1329 } // EtwOnILStubGenerated
1330 #endif // !FEATURE_CORECLR
1333 //---------------------------------------------------------------------------------------
1335 static inline void LogOneFlag(DWORD flags, DWORD flag, LPCSTR str, DWORD facility, DWORD level)
1337 LIMITED_METHOD_CONTRACT;
1340 LOG((facility, level, str));
1344 static void LogILStubFlags(DWORD facility, DWORD level, DWORD dwStubFlags)
1346 LIMITED_METHOD_CONTRACT;
1347 LOG((facility, level, "dwStubFlags: 0x%08x\n", dwStubFlags));
1348 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_CONVSIGASVARARG, " NDIRECTSTUB_FL_CONVSIGASVARARG\n", facility, level);
1349 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_BESTFIT, " NDIRECTSTUB_FL_BESTFIT\n", facility, level);
1350 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR, " NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR\n", facility, level);
1351 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUB, " NDIRECTSTUB_FL_NGENEDSTUB\n", facility, level);
1352 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DELEGATE, " NDIRECTSTUB_FL_DELEGATE\n", facility, level);
1353 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DOHRESULTSWAPPING, " NDIRECTSTUB_FL_DOHRESULTSWAPPING\n", facility, level);
1354 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_REVERSE_INTEROP, " NDIRECTSTUB_FL_REVERSE_INTEROP\n", facility, level);
1355 #ifdef FEATURE_COMINTEROP
1356 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_COM, " NDIRECTSTUB_FL_COM\n", facility, level);
1357 #endif // FEATURE_COMINTEROP
1358 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING, " NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING\n", facility, level);
1359 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL, " NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL\n", facility, level);
1360 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_HASDECLARATIVESECURITY, " NDIRECTSTUB_FL_HASDECLARATIVESECURITY\n", facility, level);
1361 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_UNMANAGED_CALLI, " NDIRECTSTUB_FL_UNMANAGED_CALLI\n", facility, level);
1362 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_TRIGGERCCTOR, " NDIRECTSTUB_FL_TRIGGERCCTOR\n", facility, level);
1363 #ifdef FEATURE_COMINTEROP
1364 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDGETTER, " NDIRECTSTUB_FL_FIELDGETTER\n", facility, level);
1365 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDSETTER, " NDIRECTSTUB_FL_FIELDSETTER\n", facility, level);
1366 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRT, " NDIRECTSTUB_FL_WINRT\n", facility, level);
1367 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTDELEGATE, " NDIRECTSTUB_FL_WINRTDELEGATE\n", facility, level);
1368 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSHAREDGENERIC, " NDIRECTSTUB_FL_WINRTSHAREDGENERIC\n", facility, level);
1369 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCTOR, " NDIRECTSTUB_FL_WINRTCTOR\n", facility, level);
1370 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCOMPOSITION, " NDIRECTSTUB_FL_WINRTCOMPOSITION\n", facility, level);
1371 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSTATIC, " NDIRECTSTUB_FL_WINRTSTATIC\n", facility, level);
1372 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTHASREDIRECTION, " NDIRECTSTUB_FL_WINRTHASREDIRECTION\n", facility, level);
1373 #endif // FEATURE_COMINTEROP
1376 // no need to log the internal flags, let's just assert what we expect to see...
1378 CONSISTENCY_CHECK(!SF_IsCOMLateBoundStub(dwStubFlags));
1379 CONSISTENCY_CHECK(!SF_IsCOMEventCallStub(dwStubFlags));
1382 NDIRECTSTUB_FL_CONVSIGASVARARG |
1383 NDIRECTSTUB_FL_BESTFIT |
1384 NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR |
1385 NDIRECTSTUB_FL_NGENEDSTUB |
1386 NDIRECTSTUB_FL_DELEGATE |
1387 NDIRECTSTUB_FL_DOHRESULTSWAPPING |
1388 NDIRECTSTUB_FL_REVERSE_INTEROP |
1389 NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING |
1390 NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL |
1391 NDIRECTSTUB_FL_HASDECLARATIVESECURITY |
1392 NDIRECTSTUB_FL_UNMANAGED_CALLI |
1393 NDIRECTSTUB_FL_TRIGGERCCTOR |
1394 #ifdef FEATURE_COMINTEROP
1395 NDIRECTSTUB_FL_COM |
1396 NDIRECTSTUB_FL_COMLATEBOUND | // internal
1397 NDIRECTSTUB_FL_COMEVENTCALL | // internal
1398 NDIRECTSTUB_FL_FIELDGETTER |
1399 NDIRECTSTUB_FL_FIELDSETTER |
1400 NDIRECTSTUB_FL_WINRT |
1401 NDIRECTSTUB_FL_WINRTDELEGATE |
1402 NDIRECTSTUB_FL_WINRTCTOR |
1403 NDIRECTSTUB_FL_WINRTCOMPOSITION |
1404 NDIRECTSTUB_FL_WINRTSTATIC |
1405 NDIRECTSTUB_FL_WINRTHASREDIRECTION |
1406 #endif // FEATURE_COMINTEROP
1409 DWORD dwUnknownFlags = dwStubFlags & ~dwKnownMask;
1410 if (0 != dwUnknownFlags)
1412 LOG((facility, level, "UNKNOWN FLAGS: 0x%08x\n", dwUnknownFlags));
1417 PCCOR_SIGNATURE GetStubTargetMethodSig()
1419 CONTRACT(PCCOR_SIGNATURE)
1422 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
1428 if (!m_qbNativeFnSigBuffer.Size())
1430 DWORD cb = m_slIL.GetStubTargetMethodSigSize();
1431 pb = (BYTE *)m_qbNativeFnSigBuffer.AllocThrows(cb);
1433 m_slIL.GetStubTargetMethodSig(pb, cb);
1437 pb = (BYTE*)m_qbNativeFnSigBuffer.Ptr();
1444 GetStubTargetMethodSigLength()
1446 WRAPPER_NO_CONTRACT;
1448 return m_slIL.GetStubTargetMethodSigSize();
1451 void SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1453 WRAPPER_NO_CONTRACT;
1455 m_slIL.SetStubTargetMethodSig(pSig, cSig);
1456 m_qbNativeFnSigBuffer.Shrink(0);
1459 TokenLookupMap* GetTokenLookupMap() { WRAPPER_NO_CONTRACT; return m_slIL.GetTokenLookupMap(); }
1462 CQuickBytes m_qbNativeFnSigBuffer;
1463 NDirectStubLinker m_slIL;
1464 BOOL m_fSetLastError;
1465 DWORD m_dwStubFlags;
1469 class PInvoke_ILStubState : public ILStubState
1473 PInvoke_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1474 CorPinvokeMap unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
1479 TargetHasThis(dwStubFlags),
1480 StubHasThis(dwStubFlags),
1485 STANDARD_VM_CONTRACT;
1487 if (SF_IsForwardStub(dwStubFlags))
1489 m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
1494 static BOOL TargetHasThis(DWORD dwStubFlags)
1497 // in reverse pinvoke on delegate, the managed target will
1498 // have a 'this' pointer, but the unmanaged signature does
1501 return SF_IsReverseDelegateStub(dwStubFlags);
1504 static BOOL StubHasThis(DWORD dwStubFlags)
1507 // in forward pinvoke on a delegate, the stub will have a
1508 // 'this' pointer, but the unmanaged target will not.
1510 return SF_IsForwardDelegateStub(dwStubFlags);
1514 #ifdef FEATURE_COMINTEROP
1515 class CLRToCOM_ILStubState : public ILStubState
1519 CLRToCOM_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1520 int iLCIDParamIdx, MethodDesc* pTargetMD)
1526 !SF_IsWinRTStaticStub(dwStubFlags), // fStubHasThis
1531 STANDARD_VM_CONTRACT;
1533 if (SF_IsForwardStub(dwStubFlags))
1535 m_slIL.SetCallingConvention(pmCallConvStdcall, SF_IsVarArgStub(dwStubFlags));
1539 void BeginEmit(DWORD dwStubFlags) // CLR to COM IL
1541 STANDARD_VM_CONTRACT;
1543 ILStubState::BeginEmit(dwStubFlags);
1545 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1547 // add the 'this' COM IP parameter to the target CALLI
1548 m_slIL.GetMarshalCodeStream()->SetStubTargetArgType(ELEMENT_TYPE_I, false);
1550 // convert 'this' to COM IP and the target method entry point
1551 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
1554 if (SF_IsWinRTDelegateStub(m_dwStubFlags))
1556 // write the stub context (EEImplMethodDesc representing the Invoke)
1557 // into the secret arg so it shows up in the InlinedCallFrame and can
1558 // be used by stub for host
1560 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
1561 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1562 pcsDispatch->EmitSTIND_I();
1563 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1568 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1571 pcsDispatch->EmitLDLOCA(m_slIL.GetTargetEntryPointLocalNum());
1573 BinderMethodID getCOMIPMethod;
1574 bool fDoPostCallIPCleanup = true;
1576 if (!SF_IsNGENedStub(dwStubFlags) && NDirect::IsHostHookEnabled())
1578 // always use the non-optimized helper if we are hosted
1579 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1581 else if (SF_IsWinRTStub(dwStubFlags))
1583 // WinRT uses optimized helpers
1584 if (SF_IsWinRTSharedGenericStub(dwStubFlags))
1585 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_SHARED_GENERIC;
1586 else if (SF_IsWinRTDelegateStub(dwStubFlags))
1587 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_DELEGATE;
1589 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT;
1591 // GetCOMIPFromRCW_WinRT, GetCOMIPFromRCW_WinRTSharedGeneric, and GetCOMIPFromRCW_WinRTDelegate
1592 // always cache the COM interface pointer so no post-call cleanup is needed
1593 fDoPostCallIPCleanup = false;
1597 // classic COM interop uses the non-optimized helper
1598 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1601 DWORD dwIPRequiresCleanupLocalNum = (DWORD)-1;
1602 if (fDoPostCallIPCleanup)
1604 dwIPRequiresCleanupLocalNum = pcsDispatch->NewLocal(ELEMENT_TYPE_BOOLEAN);
1605 pcsDispatch->EmitLDLOCA(dwIPRequiresCleanupLocalNum);
1607 // StubHelpers.GetCOMIPFromRCW(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget, out bool pfNeedsRelease)
1608 pcsDispatch->EmitCALL(getCOMIPMethod, 4, 1);
1612 // StubHelpers.GetCOMIPFromRCW_WinRT*(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget)
1613 pcsDispatch->EmitCALL(getCOMIPMethod, 3, 1);
1617 // save it because we'll need it to compute the CALLI target and release it
1618 pcsDispatch->EmitDUP();
1619 pcsDispatch->EmitSTLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1621 if (fDoPostCallIPCleanup)
1623 // make sure it's Release()'ed after the call
1624 m_slIL.SetCleanupNeeded();
1625 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
1627 ILCodeLabel *pSkipThisCleanup = pcsCleanup->NewCodeLabel();
1629 // and if it requires cleanup (i.e. it's not taken from the RCW cache)
1630 pcsCleanup->EmitLDLOC(dwIPRequiresCleanupLocalNum);
1631 pcsCleanup->EmitBRFALSE(pSkipThisCleanup);
1633 pcsCleanup->EmitLDLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1634 pcsCleanup->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
1635 pcsCleanup->EmitLabel(pSkipThisCleanup);
1640 class COMToCLR_ILStubState : public ILStubState
1644 COMToCLR_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1645 int iLCIDParamIdx, MethodDesc* pTargetMD)
1656 STANDARD_VM_CONTRACT;
1659 void BeginEmit(DWORD dwStubFlags) // COM to CLR IL
1661 STANDARD_VM_CONTRACT;
1663 ILStubState::BeginEmit(dwStubFlags);
1665 if (SF_IsWinRTStaticStub(dwStubFlags))
1667 // we are not loading 'this' because the target is static
1668 m_slIL.AdjustTargetStackDeltaForExtraParam();
1673 m_slIL.GetDispatchCodeStream()->EmitLoadThis();
1677 void MarshalFactoryReturn()
1682 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
1686 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
1687 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1688 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
1689 ILCodeStream *pcsExCleanup = m_slIL.GetExceptionCleanupCodeStream();
1691 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
1692 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
1693 pcsSetup->EmitLoadNullPtr();
1694 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
1696 locDescFactoryRetVal.MakeByRef();
1698 // expect one additional argument - pointer to a location that receives the created instance
1699 DWORD dwRetValArgNum = pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
1700 m_slIL.AdjustTargetStackDeltaForExtraParam();
1702 // convert 'this' to an interface pointer corresponding to the default interface of this class
1703 pcsUnmarshal->EmitLoadThis();
1704 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1705 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_RETURN_VALUE, 2, 1);
1706 pcsUnmarshal->EmitSTLOC(dwFactoryRetValLocalNum);
1708 // assign it to the location pointed to by the argument
1709 pcsUnmarshal->EmitLDARG(dwRetValArgNum);
1710 pcsUnmarshal->EmitLDLOC(dwFactoryRetValLocalNum);
1711 pcsUnmarshal->EmitSTIND_I();
1713 // on exception, we want to release the IInspectable's and assign NULL to output locations
1714 m_slIL.SetExceptionCleanupNeeded();
1716 EmitInterfaceClearNative(pcsExCleanup, dwFactoryRetValLocalNum);
1719 pcsExCleanup->EmitLDARG(dwRetValArgNum);
1720 pcsExCleanup->EmitLoadNullPtr();
1721 pcsExCleanup->EmitSTIND_I();
1726 class COMToCLRFieldAccess_ILStubState : public COMToCLR_ILStubState
1730 COMToCLRFieldAccess_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext,
1731 DWORD dwStubFlags, FieldDesc* pFD)
1732 : COMToCLR_ILStubState(
1740 STANDARD_VM_CONTRACT;
1742 _ASSERTE(pFD != NULL);
1746 void EmitInvokeTarget(MethodDesc *pStubMD)
1748 STANDARD_VM_CONTRACT;
1750 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
1752 if (SF_IsFieldGetterStub(m_dwStubFlags))
1754 pcsDispatch->EmitLDFLD(pcsDispatch->GetToken(m_pFD));
1758 CONSISTENCY_CHECK(SF_IsFieldSetterStub(m_dwStubFlags));
1759 pcsDispatch->EmitSTFLD(pcsDispatch->GetToken(m_pFD));
1766 #endif // FEATURE_COMINTEROP
1769 NDirectStubLinker::NDirectStubLinker(
1772 const Signature &signature,
1773 SigTypeContext *pTypeContext,
1774 MethodDesc* pTargetMD,
1776 BOOL fTargetHasThis,
1778 : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, fTargetHasThis, fStubHasThis, !SF_IsCOMStub(dwStubFlags)),
1779 m_pCleanupFinallyBeginLabel(NULL),
1780 m_pCleanupFinallyEndLabel(NULL),
1781 m_pSkipExceptionCleanupLabel(NULL),
1782 #ifdef FEATURE_COMINTEROP
1783 m_dwWinRTFactoryObjectLocalNum(-1),
1784 #endif // FEATURE_COMINTEROP
1785 m_fHasCleanupCode(FALSE),
1786 m_fHasExceptionCleanupCode(FALSE),
1787 m_fCleanupWorkListIsSetup(FALSE),
1788 m_dwThreadLocalNum(-1),
1789 m_dwCleanupWorkListLocalNum(-1),
1790 m_dwRetValLocalNum(-1),
1791 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
1792 m_dwFirstCopyCtorCookieLocalNum(-1),
1793 m_dwLastCopyCtorCookieLocalNum(-1),
1794 #endif // _TARGET_X86_ && !FEATURE_CORECLR
1796 m_ErrorParamIdx(-1),
1797 m_iLCIDParamIdx(iLCIDParamIdx),
1798 m_dwStubFlags(dwStubFlags)
1800 STANDARD_VM_CONTRACT;
1803 m_pcsSetup = NewCodeStream(ILStubLinker::kSetup); // do any one-time setup work
1804 m_pcsMarshal = NewCodeStream(ILStubLinker::kMarshal); // marshals arguments
1805 m_pcsDispatch = NewCodeStream(ILStubLinker::kDispatch); // sets up arguments and makes call
1806 m_pcsRetUnmarshal = NewCodeStream(ILStubLinker::kReturnUnmarshal); // unmarshals return value
1807 m_pcsUnmarshal = NewCodeStream(ILStubLinker::kUnmarshal); // unmarshals arguments
1808 m_pcsExceptionCleanup = NewCodeStream(ILStubLinker::kExceptionCleanup); // MAY NOT THROW: goes in a finally and does exception-only cleanup
1809 m_pcsCleanup = NewCodeStream(ILStubLinker::kCleanup); // MAY NOT THROW: goes in a finally and does unconditional cleanup
1813 m_dwArgMarshalIndexLocalNum = NewLocal(ELEMENT_TYPE_I4);
1814 m_pcsMarshal->EmitLDC(0);
1815 m_pcsMarshal->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1817 #ifdef FEATURE_COMINTEROP
1819 // Forward COM interop needs a local to hold target interface pointer
1821 if (SF_IsForwardCOMStub(m_dwStubFlags))
1823 m_dwTargetEntryPointLocalNum = NewLocal(ELEMENT_TYPE_I);
1824 m_dwTargetInterfacePointerLocalNum = NewLocal(ELEMENT_TYPE_I);
1825 m_pcsSetup->EmitLoadNullPtr();
1826 m_pcsSetup->EmitSTLOC(m_dwTargetInterfacePointerLocalNum);
1828 #endif // FEATURE_COMINTEROP
1831 void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg)
1833 LIMITED_METHOD_CONTRACT;
1834 ULONG uNativeCallingConv = 0;
1836 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
1839 // The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM:
1840 // any float values must be duplicated in the corresponding general-purpose registers.
1841 uNativeCallingConv = CORINFO_CALLCONV_NATIVEVARARG;
1844 #endif // _TARGET_AMD64_ || _TARGET_ARM_
1846 switch (unmngCallConv)
1848 case pmCallConvCdecl:
1849 uNativeCallingConv = CORINFO_CALLCONV_C;
1851 case pmCallConvStdcall:
1852 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1854 case pmCallConvThiscall:
1855 uNativeCallingConv = CORINFO_CALLCONV_THISCALL;
1858 _ASSERTE(!"Invalid calling convention.");
1859 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1864 SetStubTargetCallingConv((CorCallingConvention)uNativeCallingConv);
1867 void NDirectStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx)
1869 WRAPPER_NO_CONTRACT;
1872 // This sets our state local variable that tracks the progress of the stub execution.
1873 // In the finally block we test this variable to see what cleanup we need to do. The
1874 // variable starts with the value of 0 and is assigned the following values as the
1877 // CLEANUP_INDEX_ARG0_MARSHAL + 1 - 1st argument marshaled
1878 // CLEANUP_INDEX_ARG0_MARSHAL + 2 - 2nd argument marshaled
1880 // CLEANUP_INDEX_ARG0_MARSHAL + n - nth argument marshaled
1881 // CLEANUP_INDEX_RETVAL_UNMARSHAL + 1 - return value unmarshaled
1882 // CLEANUP_INDEX_ARG0_UNMARSHAL + 1 - 1st argument unmarshaled
1883 // CLEANUP_INDEX_ARG0_UNMARSHAL + 2 - 2nd argument unmarshaled
1885 // CLEANUP_INDEX_ARG0_UNMARSHAL + n - nth argument unmarshaled
1886 // CLEANUP_INDEX_ALL_DONE + 1 - ran to completion, no exception thrown
1888 // Note: There may be gaps, i.e. if say 2nd argument does not need cleanup, the
1889 // state variable will never be assigned the corresponding value. However, the
1890 // value must always monotonically increase so we can use <=, >, etc.
1893 pcsEmit->EmitLDC(uArgIdx + 1);
1894 pcsEmit->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1897 void NDirectStubLinker::EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel)
1899 STANDARD_VM_CONTRACT;
1903 // See EmitSetArgMarshalIndex.
1904 pcsEmit->EmitLDLOC(m_dwArgMarshalIndexLocalNum);
1905 pcsEmit->EmitLDC(uArgIdx);
1909 case BranchIfMarshaled:
1911 // we branch to the label if the argument has been marshaled
1912 pcsEmit->EmitBGT(pSkipCleanupLabel);
1916 case BranchIfNotMarshaled:
1918 // we branch to the label if the argument has not been marshaled
1919 pcsEmit->EmitBLE(pSkipCleanupLabel);
1928 int NDirectStubLinker::GetLCIDParamIdx()
1930 LIMITED_METHOD_CONTRACT;
1931 return m_iLCIDParamIdx;
1934 ILCodeStream* NDirectStubLinker::GetSetupCodeStream()
1936 LIMITED_METHOD_CONTRACT;
1940 ILCodeStream* NDirectStubLinker::GetMarshalCodeStream()
1942 LIMITED_METHOD_CONTRACT;
1943 return m_pcsMarshal;
1946 ILCodeStream* NDirectStubLinker::GetUnmarshalCodeStream()
1948 LIMITED_METHOD_CONTRACT;
1949 return m_pcsUnmarshal;
1952 ILCodeStream* NDirectStubLinker::GetReturnUnmarshalCodeStream()
1954 LIMITED_METHOD_CONTRACT;
1955 return m_pcsRetUnmarshal;
1958 ILCodeStream* NDirectStubLinker::GetDispatchCodeStream()
1960 LIMITED_METHOD_CONTRACT;
1961 return m_pcsDispatch;
1964 ILCodeStream* NDirectStubLinker::GetCleanupCodeStream()
1966 LIMITED_METHOD_CONTRACT;
1967 return m_pcsCleanup;
1970 ILCodeStream* NDirectStubLinker::GetExceptionCleanupCodeStream()
1972 LIMITED_METHOD_CONTRACT;
1973 return m_pcsExceptionCleanup;
1976 void NDirectStubLinker::AdjustTargetStackDeltaForExtraParam()
1978 LIMITED_METHOD_CONTRACT;
1980 // Compensate for the extra parameter.
1982 m_iTargetStackDelta++;
1985 void NDirectStubLinker::AdjustTargetStackDeltaForReverseInteropHRESULTSwapping()
1987 WRAPPER_NO_CONTRACT;
1989 // In the case of reverse pinvoke, we build up the 'target'
1990 // signature as if it were normal forward pinvoke and then
1991 // switch that signature (representing the native sig) with
1992 // the stub's sig (representing the managed sig). However,
1993 // as a side-effect, our calcualted target stack delta is
1996 // The only way that we support a different stack delta is
1997 // through hresult swapping. So this code "undoes" the
1998 // deltas that would have been applied in that case.
2001 if (StubHasVoidReturnType())
2004 // If the managed return type is void, undo the HRESULT
2005 // return type added to our target sig for HRESULT swapping.
2006 // No extra argument will have been added because it makes
2007 // no sense to add an extry byref void argument.
2009 m_iTargetStackDelta--;
2014 // no longer pop the extra byref argument from the stack
2016 m_iTargetStackDelta++;
2020 void NDirectStubLinker::SetInteropParamExceptionInfo(UINT resID, UINT paramIdx)
2022 LIMITED_METHOD_CONTRACT;
2024 // only keep the first one
2025 if (HasInteropParamExceptionInfo())
2030 m_ErrorResID = resID;
2031 m_ErrorParamIdx = paramIdx;
2034 bool NDirectStubLinker::HasInteropParamExceptionInfo()
2036 LIMITED_METHOD_CONTRACT;
2038 return !(((DWORD)-1 == m_ErrorResID) && ((DWORD)-1 == m_ErrorParamIdx));
2041 void NDirectStubLinker::GenerateInteropParamException(ILCodeStream* pcsEmit)
2043 STANDARD_VM_CONTRACT;
2045 pcsEmit->EmitLDC(m_ErrorResID);
2046 pcsEmit->EmitLDC(m_ErrorParamIdx);
2047 pcsEmit->EmitCALL(METHOD__STUBHELPERS__THROW_INTEROP_PARAM_EXCEPTION, 2, 0);
2049 pcsEmit->EmitLDNULL();
2050 pcsEmit->EmitTHROW();
2053 #ifdef FEATURE_COMINTEROP
2054 DWORD NDirectStubLinker::GetTargetInterfacePointerLocalNum()
2056 LIMITED_METHOD_CONTRACT;
2057 CONSISTENCY_CHECK(m_dwTargetInterfacePointerLocalNum != (DWORD)-1);
2058 return m_dwTargetInterfacePointerLocalNum;
2060 DWORD NDirectStubLinker::GetTargetEntryPointLocalNum()
2062 LIMITED_METHOD_CONTRACT;
2063 CONSISTENCY_CHECK(m_dwTargetEntryPointLocalNum != (DWORD)-1);
2064 return m_dwTargetEntryPointLocalNum;
2067 void NDirectStubLinker::EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2069 STANDARD_VM_CONTRACT;
2071 if (SF_IsForwardStub(dwStubFlags) &&
2072 (SF_IsWinRTCtorStub(dwStubFlags) || SF_IsWinRTStaticStub(dwStubFlags)))
2074 // WinRT ctor/static stubs make the call on the factory object instead of 'this'
2075 if (m_dwWinRTFactoryObjectLocalNum == (DWORD)-1)
2077 m_dwWinRTFactoryObjectLocalNum = NewLocal(ELEMENT_TYPE_OBJECT);
2079 // get the factory object
2080 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2081 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_OBJECT, 1, 1);
2082 m_pcsSetup->EmitSTLOC(m_dwWinRTFactoryObjectLocalNum);
2085 pcsEmit->EmitLDLOC(m_dwWinRTFactoryObjectLocalNum);
2089 pcsEmit->EmitLoadThis();
2092 #endif // FEATURE_COMINTEROP
2094 DWORD NDirectStubLinker::GetCleanupWorkListLocalNum()
2096 LIMITED_METHOD_CONTRACT;
2097 CONSISTENCY_CHECK(m_dwCleanupWorkListLocalNum != (DWORD)-1);
2098 return m_dwCleanupWorkListLocalNum;
2101 DWORD NDirectStubLinker::GetThreadLocalNum()
2103 STANDARD_VM_CONTRACT;
2105 if (m_dwThreadLocalNum == (DWORD)-1)
2107 // The local is created and initialized lazily when first asked.
2108 m_dwThreadLocalNum = NewLocal(ELEMENT_TYPE_I);
2109 m_pcsSetup->EmitCALL(METHOD__THREAD__INTERNAL_GET_CURRENT_THREAD, 0, 1);
2110 m_pcsSetup->EmitSTLOC(m_dwThreadLocalNum);
2113 return m_dwThreadLocalNum;
2116 DWORD NDirectStubLinker::GetReturnValueLocalNum()
2118 LIMITED_METHOD_CONTRACT;
2119 return m_dwRetValLocalNum;
2122 BOOL NDirectStubLinker::IsCleanupNeeded()
2124 LIMITED_METHOD_CONTRACT;
2126 return (m_fHasCleanupCode || IsCleanupWorkListSetup());
2129 BOOL NDirectStubLinker::IsExceptionCleanupNeeded()
2131 LIMITED_METHOD_CONTRACT;
2133 return m_fHasExceptionCleanupCode;
2136 void NDirectStubLinker::InitCleanupCode()
2141 PRECONDITION(NULL == m_pCleanupFinallyBeginLabel);
2145 m_pCleanupFinallyBeginLabel = NewCodeLabel();
2146 m_pcsExceptionCleanup->EmitLabel(m_pCleanupFinallyBeginLabel);
2149 void NDirectStubLinker::InitExceptionCleanupCode()
2154 PRECONDITION(NULL == m_pSkipExceptionCleanupLabel);
2160 // we want to skip the entire exception cleanup if no exception has been thrown
2161 m_pSkipExceptionCleanupLabel = NewCodeLabel();
2162 EmitCheckForArgCleanup(m_pcsExceptionCleanup, CLEANUP_INDEX_ALL_DONE, BranchIfMarshaled, m_pSkipExceptionCleanupLabel);
2165 void NDirectStubLinker::SetCleanupNeeded()
2167 WRAPPER_NO_CONTRACT;
2169 if (!m_fHasCleanupCode)
2171 m_fHasCleanupCode = TRUE;
2176 void NDirectStubLinker::SetExceptionCleanupNeeded()
2178 WRAPPER_NO_CONTRACT;
2180 if (!m_fHasExceptionCleanupCode)
2182 m_fHasExceptionCleanupCode = TRUE;
2183 InitExceptionCleanupCode();
2187 void NDirectStubLinker::NeedsCleanupList()
2189 STANDARD_VM_CONTRACT;
2191 if (!IsCleanupWorkListSetup())
2193 m_fCleanupWorkListIsSetup = TRUE;
2196 // we setup a new local that will hold the cleanup work list
2197 LocalDesc desc(MscorlibBinder::GetClass(CLASS__CLEANUP_WORK_LIST));
2198 m_dwCleanupWorkListLocalNum = NewLocal(desc);
2203 BOOL NDirectStubLinker::IsCleanupWorkListSetup ()
2205 LIMITED_METHOD_CONTRACT;
2207 return m_fCleanupWorkListIsSetup;
2211 void NDirectStubLinker::LoadCleanupWorkList(ILCodeStream* pcsEmit)
2213 STANDARD_VM_CONTRACT;
2216 pcsEmit->EmitLDLOCA(GetCleanupWorkListLocalNum());
2219 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
2221 BOOL NDirectStubLinker::IsCopyCtorStubNeeded()
2223 LIMITED_METHOD_CONTRACT;
2224 return (m_dwFirstCopyCtorCookieLocalNum != (DWORD)-1);
2227 DWORD NDirectStubLinker::CreateCopyCtorCookie(ILCodeStream* pcsEmit)
2229 STANDARD_VM_CONTRACT;
2231 MethodTable *pCookieMT = MscorlibBinder::GetClass(CLASS__COPYCTORSTUBCOOKIE);
2233 LocalDesc desc(pCookieMT);
2234 DWORD dwCookieLocalNum = pcsEmit->NewLocal(desc);
2236 // <dwCookieLocalNum> = new CopyCtorStubCookie()
2237 pcsEmit->EmitLDLOCA(dwCookieLocalNum);
2238 pcsEmit->EmitINITOBJ(pcsEmit->GetToken(pCookieMT));
2240 if (m_dwLastCopyCtorCookieLocalNum == (DWORD)-1)
2242 // this is the first cookie in this stub
2243 m_dwFirstCopyCtorCookieLocalNum = dwCookieLocalNum;
2247 // this is not the first cookie - build a linked list
2248 // <m_dwLastCopyCtorCookieLocalNum>.SetNext(&<dwCookieLocalNum>)
2249 pcsEmit->EmitLDLOCA(m_dwLastCopyCtorCookieLocalNum);
2250 pcsEmit->EmitLDLOCA(dwCookieLocalNum);
2251 pcsEmit->EmitCALL(METHOD__COPYCTORSTUBCOOKIE__SET_NEXT, 2, 0);
2254 m_dwLastCopyCtorCookieLocalNum = dwCookieLocalNum;
2255 return dwCookieLocalNum;
2258 #endif // _TARGET_X86_ && !FEATURE_CORECLR
2260 void NDirectStubLinker::Begin(DWORD dwStubFlags)
2262 STANDARD_VM_CONTRACT;
2264 #ifdef FEATURE_COMINTEROP
2265 if (SF_IsWinRTHasRedirection(dwStubFlags))
2267 _ASSERTE(SF_IsForwardCOMStub(dwStubFlags));
2269 // The very first thing we need to do is check whether the call should be routed to
2270 // the marshaling stub for the corresponding projected WinRT interface. If so, we
2272 m_pcsSetup->EmitLoadThis();
2273 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2274 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__SHOULD_CALL_WINRT_INTERFACE, 2, 1);
2276 ILCodeLabel *pNoRedirection = m_pcsSetup->NewCodeLabel();
2277 m_pcsSetup->EmitBRFALSE(pNoRedirection);
2279 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(
2281 TypeHandle::Interop_ManagedToNative);
2283 CONSISTENCY_CHECK(pAdapterMD != NULL && !pAdapterMD->HasMethodInstantiation());
2285 m_pcsSetup->EmitJMP(m_pcsSetup->GetToken(pAdapterMD));
2287 m_pcsSetup->EmitLabel(pNoRedirection);
2289 #endif // FEATURE_COMINTEROP
2291 if (SF_IsForwardStub(dwStubFlags))
2293 #ifndef FEATURE_CORECLR // CAS
2294 // we may need to demand security permission
2295 if (SF_IsStubWithDemand(dwStubFlags))
2297 if (SF_IsCOMStub(dwStubFlags) || SF_IsDelegateStub(dwStubFlags))
2299 // pass NULL NDirectMethodDesc for COM and delegate P/Invoke
2300 m_pcsSetup->EmitLoadNullPtr();
2304 // pass the real MD for direct P/Invoke
2305 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2307 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__DEMAND_PERMISSION, 1, 0);
2309 #endif // !FEATURE_CORECLR
2311 if (SF_IsStubWithCctorTrigger(dwStubFlags))
2313 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2314 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__INIT_DECLARING_TYPE, 1, 0);
2319 #ifdef MDA_SUPPORTED
2320 if (!SF_IsNGENedStub(dwStubFlags) && MDA_GET_ASSISTANT(GcUnmanagedToManaged))
2322 EmitCallGcCollectForMDA(m_pcsSetup, dwStubFlags);
2324 #endif // MDA_SUPPORTED
2326 if (SF_IsDelegateStub(dwStubFlags))
2328 #if defined(MDA_SUPPORTED) || (defined(CROSSGEN_COMPILE) && !defined(FEATURE_CORECLR))
2329 // GC was induced (gcUnmanagedToManagedMDA), arguments have been marshaled, and we are about
2330 // to touch the UMEntryThunk and extract the delegate target from it so this is the right time
2331 // to do the collected delegate MDA check.
2333 // The call to CheckCollectedDelegateMDA is emitted regardless of whether the MDA is on at the
2334 // moment. This is to avoid having to ignore NGENed stubs without the call just as we do for
2335 // the GC MDA (callbackOncollectedDelegateMDA is turned on under managed debugger by default
2336 // so the impact would be substantial). The helper bails out fast if the MDA is not enabled.
2337 EmitLoadStubContext(m_pcsDispatch, dwStubFlags);
2338 m_pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CHECK_COLLECTED_DELEGATE_MDA, 1, 0);
2339 #endif // MDA_SUPPORTED
2342 // recover delegate object from UMEntryThunk
2344 EmitLoadStubContext(m_pcsDispatch, dwStubFlags); // load UMEntryThunk*
2346 m_pcsDispatch->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2347 m_pcsDispatch->EmitADD();
2348 m_pcsDispatch->EmitLDIND_I(); // get OBJECTHANDLE
2349 m_pcsDispatch->EmitLDIND_REF(); // get Delegate object
2350 m_pcsDispatch->EmitLDFLD(GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__TARGET)));
2354 m_pCleanupTryBeginLabel = NewCodeLabel();
2355 m_pcsMarshal->EmitLabel(m_pCleanupTryBeginLabel);
2358 void NDirectStubLinker::End(DWORD dwStubFlags)
2360 STANDARD_VM_CONTRACT;
2362 ILCodeStream* pcs = m_pcsUnmarshal;
2364 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(dwStubFlags)
2365 && !SF_IsFieldGetterStub(dwStubFlags)
2366 && !SF_IsFieldSetterStub(dwStubFlags);
2369 // Create a local for the return value and store the return value in it.
2371 if (IsCleanupNeeded() || hasTryCatchForHRESULT)
2373 // Save the return value if necessary, since the IL stack will be emptied when we leave a try block.
2374 LocalDesc locDescRetVal;
2375 if (SF_IsForwardStub(dwStubFlags))
2377 GetStubReturnType(&locDescRetVal);
2381 GetStubTargetReturnType(&locDescRetVal);
2384 if (!( (locDescRetVal.cbType == 1) && (locDescRetVal.ElementType[0] == ELEMENT_TYPE_VOID) ))
2386 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2387 if (SF_IsReverseStub(dwStubFlags) && StubHasVoidReturnType())
2389 // if the target returns void and we are doing HRESULT swapping, S_OK is loaded
2390 // in the unmarshal stream
2391 m_pcsUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2395 // otherwise the return value is loaded in the return unmarshal stream
2396 m_pcsRetUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2399 else if (hasTryCatchForHRESULT && (locDescRetVal.ElementType[0] != ELEMENT_TYPE_VOID))
2401 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2406 // Emit end-of-try and end-of-finally code for the try/finally
2408 if (IsCleanupNeeded())
2410 m_pCleanupFinallyEndLabel = NewCodeLabel();
2411 m_pCleanupTryEndLabel = NewCodeLabel();
2413 if (IsExceptionCleanupNeeded())
2415 // if we made it here, no exception has been thrown
2416 EmitSetArgMarshalIndex(m_pcsUnmarshal, CLEANUP_INDEX_ALL_DONE);
2419 // Emit a leave at the end of the try block. If we have an outer try/catch, we need
2420 // to leave to the beginning of the ExceptionHandler code stream, which follows the
2421 // Cleanup code stream. If we don't, we can just leave to the tail end of the
2422 // Unmarshal code stream where we'll emit our RET.
2424 ILCodeLabel* pLeaveTarget = m_pCleanupTryEndLabel;
2425 if (hasTryCatchForHRESULT)
2427 pLeaveTarget = m_pCleanupFinallyEndLabel;
2430 m_pcsUnmarshal->EmitLEAVE(pLeaveTarget);
2431 m_pcsUnmarshal->EmitLabel(m_pCleanupTryEndLabel);
2433 // Emit a call to destroy the clean-up list if needed.
2434 if (IsCleanupWorkListSetup())
2436 LoadCleanupWorkList(m_pcsCleanup);
2437 m_pcsCleanup->EmitCALL(METHOD__STUBHELPERS__DESTROY_CLEANUP_LIST, 1, 0);
2440 // Emit the endfinally.
2441 m_pcsCleanup->EmitENDFINALLY();
2442 m_pcsCleanup->EmitLabel(m_pCleanupFinallyEndLabel);
2445 #ifdef MDA_SUPPORTED
2446 if (SF_IsReverseStub(dwStubFlags) && !SF_IsNGENedStub(dwStubFlags) &&
2447 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
2449 EmitCallGcCollectForMDA(pcs, dwStubFlags);
2451 #endif // MDA_SUPPORTED
2453 if (IsExceptionCleanupNeeded())
2455 m_pcsExceptionCleanup->EmitLabel(m_pSkipExceptionCleanupLabel);
2458 // Reload the return value
2459 if ((m_dwRetValLocalNum != (DWORD)-1) && !hasTryCatchForHRESULT)
2461 pcs->EmitLDLOC(m_dwRetValLocalNum);
2465 void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD)
2467 STANDARD_VM_CONTRACT;
2468 if (SF_IsForwardStub(dwStubFlags)) // managed-to-native
2470 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
2471 // set the copy ctor cookie chain if needed
2472 if (IsCopyCtorStubNeeded())
2474 // StubHelpers.SetCopyCtorCookieChain(pStubArg, pUnmngThis, dwStubFlags, &<m_dwFirstCopyCtorCookieLocalNum>)
2475 if (SF_IsDelegateStub(dwStubFlags))
2477 // for forward delegate P/Invoke load the target from 'this'
2478 pcsEmit->EmitLoadThis();
2479 pcsEmit->EmitLDFLD(pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR_AUX)));
2483 // otherwise load the secret argument
2484 EmitLoadStubContext(pcsEmit, dwStubFlags);
2487 if (SF_IsCOMStub(dwStubFlags))
2489 // for forward COM load the unmanaged interface pointer
2490 pcsEmit->EmitLDLOC(m_dwTargetInterfacePointerLocalNum);
2495 pcsEmit->EmitLoadNullPtr();
2497 pcsEmit->EmitLDC(dwStubFlags);
2498 pcsEmit->EmitLDLOCA(m_dwFirstCopyCtorCookieLocalNum);
2499 pcsEmit->EmitCALL(METHOD__STUBHELPERS__SET_COPY_CTOR_COOKIE_CHAIN, 4, 0);
2501 #endif // _TARGET_X86_ && !FEATURE_CORECLR
2503 if (SF_IsDelegateStub(dwStubFlags)) // delegate invocation
2505 // get the delegate unmanaged target - we call a helper instead of just grabbing
2506 // the _methodPtrAux field because we may need to intercept the call for host, MDA, etc.
2507 pcsEmit->EmitLoadThis();
2509 // on AMD64 GetDelegateTarget will return address of the generic stub for host when we are hosted
2510 // and update the secret argument with real target - the secret arg will be embedded in the
2511 // InlinedCallFrame by the JIT and fetched via TLS->Thread->Frame->Datum by the stub for host
2512 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
2514 // we don't need to do this on x86 because stub for host is generated dynamically per target
2515 pcsEmit->EmitLDNULL();
2517 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_TARGET, 2, 1);
2519 else // direct invocation
2521 if (SF_IsCALLIStub(dwStubFlags)) // unmanaged CALLI
2523 // if we ever NGEN CALLI stubs, this would have to be done differently
2524 _ASSERTE(!SF_IsNGENedStub(dwStubFlags));
2526 #ifndef CROSSGEN_COMPILE
2530 #ifndef FEATURE_CORECLR
2531 if (IsCopyCtorStubNeeded())
2533 // if we need to call copy ctor(s), we go to the copy ctor stub
2534 Stub *pCopyCtorStub = NDirect::GetStubForCopyCtor();
2535 pcsEmit->EmitLDC((DWORD_PTR)pCopyCtorStub->GetEntryPoint());
2538 #endif // !FEATURE_CORECLR
2540 // for managed-to-unmanaged CALLI that requires marshaling, the target is passed
2541 // as the secret argument to the stub by GenericPInvokeCalliHelper (asmhelpers.asm)
2542 EmitLoadStubContext(pcsEmit, dwStubFlags);
2545 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2546 if (NDirect::IsHostHookEnabled())
2548 // we need to call to the host hook, real target is passed as the last argument
2549 Stub *pHostStub = NDirect::GenerateStubForHost(
2551 (CorUnmanagedCallingConvention)(GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_MASK),
2552 pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize());
2554 pcsEmit->EmitLDC((DWORD_PTR)pHostStub->GetEntryPoint());
2556 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2558 #else // _TARGET_X86_
2560 if (NDirect::IsHostHookEnabled())
2562 // the stub for host will get the original target from the secret arg
2563 pcsEmit->EmitLDC((DWORD_PTR)GetEEFuncEntryPoint(PInvokeStubForHost));
2567 // the secret arg has been shifted to left and ORed with 1 (see code:GenericPInvokeCalliHelper)
2568 EmitLoadStubContext(pcsEmit, dwStubFlags);
2569 #ifndef _TARGET_ARM_
2570 pcsEmit->EmitLDC(1);
2571 pcsEmit->EmitSHR_UN();
2575 #endif // _TARGET_X86_
2577 #endif // CROSSGEN_COMPILE
2580 #ifdef FEATURE_COMINTEROP
2581 if (!SF_IsCOMStub(dwStubFlags)) // forward P/Invoke
2582 #endif // FEATURE_COMINTEROP
2584 EmitLoadStubContext(pcsEmit, dwStubFlags);
2587 if (GetAppDomain()->IsMDILCompilationDomain())
2589 // GetNDirectTarget is understood by the compiler and generates the CALL_PINVOKE instruction
2590 pcsEmit->EmitCALL(pcsEmit->GetToken(MscorlibBinder::GetMethod(METHOD__STUBHELPERS__GET_NDIRECT_TARGET)), 1, 1);
2595 // Perf: inline the helper for now
2596 //pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_NDIRECT_TARGET, 1, 1);
2597 pcsEmit->EmitLDC(offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
2599 pcsEmit->EmitLDIND_I();
2600 pcsEmit->EmitLDIND_I();
2603 #ifdef FEATURE_COMINTEROP
2606 // this is a CLR -> COM call
2607 // the target has been computed by StubHelpers::GetCOMIPFromRCW
2608 pcsEmit->EmitLDLOC(m_dwTargetEntryPointLocalNum);
2610 #endif // FEATURE_COMINTEROP
2613 else // native-to-managed
2615 if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate
2617 int tokDelegate_methodPtr = pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR));
2619 EmitLoadStubContext(pcsEmit, dwStubFlags);
2620 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2622 pcsEmit->EmitLDIND_I(); // Get OBJECTHANDLE
2623 pcsEmit->EmitLDIND_REF(); // Get Delegate object
2624 pcsEmit->EmitLDFLD(tokDelegate_methodPtr); // get _methodPtr
2626 #ifdef FEATURE_COMINTEROP
2627 else if (SF_IsCOMStub(dwStubFlags)) // COM -> CLR call
2629 // managed target is passed directly in the secret argument
2630 EmitLoadStubContext(pcsEmit, dwStubFlags);
2632 #endif // FEATURE_COMINTEROP
2633 else // direct reverse P/Invoke (CoreCLR hosting)
2635 EmitLoadStubContext(pcsEmit, dwStubFlags);
2636 CONSISTENCY_CHECK(0 == offsetof(UMEntryThunk, m_pManagedTarget)); // if this changes, just add back the EmitLDC/EmitADD below
2637 // pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pManagedTarget));
2638 // pcsEmit->EmitADD();
2639 pcsEmit->EmitLDIND_I(); // Get UMEntryThunk::m_pManagedTarget
2643 // For managed-to-native calls, the rest of the work is done by the JIT. It will
2644 // erect InlinedCallFrame, flip GC mode, and use the specified calling convention
2645 // to call the target. For native-to-managed calls, this is an ordinary managed
2646 // CALLI and nothing special happens.
2647 pcsEmit->EmitCALLI(TOKEN_ILSTUB_TARGET_SIG, 0, m_iTargetStackDelta);
2650 void NDirectStubLinker::EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal)
2652 STANDARD_VM_CONTRACT;
2654 if (SF_IsForwardPInvokeStub(m_dwStubFlags) && !SF_IsForwardDelegateStub(m_dwStubFlags))
2656 // get the secret argument via intrinsic
2657 pslILEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2661 // no secret argument
2662 pslILEmit->EmitLoadNullPtr();
2665 pslILEmit->EmitLDLOC(dwPinnedLocal);
2667 pslILEmit->EmitCALL(METHOD__STUBHELPERS__LOG_PINNED_ARGUMENT, 2, 0);
2670 void NDirectStubLinker::GetCleanupFinallyOffsets(ILStubEHClause * pClause)
2675 PRECONDITION(CheckPointer(pClause));
2679 if (m_pCleanupFinallyEndLabel)
2681 _ASSERTE(m_pCleanupFinallyBeginLabel);
2682 _ASSERTE(m_pCleanupTryBeginLabel);
2683 _ASSERTE(m_pCleanupTryEndLabel);
2685 pClause->kind = ILStubEHClause::kFinally;
2686 pClause->dwTryBeginOffset = (DWORD)m_pCleanupTryBeginLabel->GetCodeOffset();
2687 pClause->cbTryLength = (DWORD)m_pCleanupTryEndLabel->GetCodeOffset() - pClause->dwTryBeginOffset;
2688 pClause->dwHandlerBeginOffset = (DWORD)m_pCleanupFinallyBeginLabel->GetCodeOffset();
2689 pClause->cbHandlerLength = (DWORD)m_pCleanupFinallyEndLabel->GetCodeOffset() - pClause->dwHandlerBeginOffset;
2693 void NDirectStubLinker::ClearCode()
2695 WRAPPER_NO_CONTRACT;
2696 ILStubLinker::ClearCode();
2698 m_pCleanupTryBeginLabel = 0;
2699 m_pCleanupTryEndLabel = 0;
2700 m_pCleanupFinallyBeginLabel = 0;
2701 m_pCleanupFinallyEndLabel = 0;
2704 #ifdef PROFILING_SUPPORTED
2705 DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2707 STANDARD_VM_CONTRACT;
2709 if (SF_IsForwardDelegateStub(dwStubFlags) || SF_IsCALLIStub(dwStubFlags))
2711 // secret argument does not contain MD nor UMEntryThunk
2712 pcsEmit->EmitLoadNullPtr();
2716 EmitLoadStubContext(pcsEmit, dwStubFlags);
2719 if (SF_IsForwardStub(dwStubFlags))
2721 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2725 // we use a null pThread to indicate reverse interop
2726 pcsEmit->EmitLDC(NULL);
2729 // In the unmanaged delegate case, we need the "this" object to retrieve the MD
2730 // in StubHelpers::ProfilerEnterCallback().
2731 if (SF_IsDelegateStub(dwStubFlags))
2733 if (SF_IsForwardStub(dwStubFlags))
2735 pcsEmit->EmitLoadThis();
2739 EmitLoadStubContext(pcsEmit, dwStubFlags); // load UMEntryThunk*
2740 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2742 pcsEmit->EmitLDIND_I(); // get OBJECTHANDLE
2743 pcsEmit->EmitLDIND_REF(); // get Delegate object
2748 pcsEmit->EmitLDC(NULL);
2750 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_BEGIN_TRANSITION_CALLBACK, 3, 1);
2752 // Store the MD for StubHelpers::ProfilerLeaveCallback().
2753 DWORD dwMethodDescLocalNum = pcsEmit->NewLocal(ELEMENT_TYPE_I);
2754 pcsEmit->EmitSTLOC(dwMethodDescLocalNum);
2755 return dwMethodDescLocalNum;
2758 void NDirectStubLinker::EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum)
2760 STANDARD_VM_CONTRACT;
2762 pcsEmit->EmitLDLOC(dwMethodDescLocalNum);
2763 if (SF_IsReverseStub(dwStubFlags))
2765 // we use a null pThread to indicate reverse interop
2766 pcsEmit->EmitLDC(NULL);
2770 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2772 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_END_TRANSITION_CALLBACK, 2, 0);
2774 #endif // PROFILING_SUPPPORTED
2777 void NDirectStubLinker::EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags)
2779 STANDARD_VM_CONTRACT;
2781 pcsEmit->EmitLDLOC(dwLocalNum);
2783 if (SF_IsDelegateStub(dwStubFlags))
2785 pcsEmit->EmitLoadNullPtr();
2786 pcsEmit->EmitLoadThis();
2788 else if (SF_IsCALLIStub(dwStubFlags))
2790 pcsEmit->EmitLoadNullPtr();
2791 pcsEmit->EmitLDNULL();
2795 // P/Invoke, CLR->COM
2796 EmitLoadStubContext(pcsEmit, dwStubFlags);
2797 pcsEmit->EmitLDNULL();
2802 // StubHelpers.ValidateByref(byref, pMD, pThis)
2803 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_BYREF, 3, 0);
2807 // StubHelpers.ValidateObject(obj, pMD, pThis)
2808 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_OBJECT, 3, 0);
2812 void NDirectStubLinker::EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2814 STANDARD_VM_CONTRACT;
2816 // generate validation callouts for pinned locals
2817 CQuickBytes qbLocalSig;
2818 DWORD cbSig = GetLocalSigSize();
2820 qbLocalSig.AllocThrows(cbSig);
2821 PCOR_SIGNATURE pSig = (PCOR_SIGNATURE)qbLocalSig.Ptr();
2823 GetLocalSig(pSig, cbSig);
2824 SigPointer ptr(pSig, cbSig);
2826 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
2829 IfFailThrow(ptr.GetData(&numLocals));
2831 for (ULONG i = 0; i < numLocals; i++)
2834 IfFailThrow(ptr.PeekByte(&modifier));
2835 if (modifier == ELEMENT_TYPE_PINNED)
2837 IfFailThrow(ptr.GetByte(NULL));
2838 IfFailThrow(ptr.PeekByte(&modifier));
2839 EmitValidateLocal(pcsEmit, i, (modifier == ELEMENT_TYPE_BYREF), dwStubFlags);
2842 IfFailThrow(ptr.SkipExactlyOne());
2845 #endif // VERIFY_HEAP
2847 // Loads the 'secret argument' passed to the stub.
2848 void NDirectStubLinker::EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2850 STANDARD_VM_CONTRACT;
2852 CONSISTENCY_CHECK(!SF_IsForwardDelegateStub(dwStubFlags));
2853 CONSISTENCY_CHECK(!SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags));
2855 #ifdef FEATURE_COMINTEROP
2856 if (SF_IsWinRTDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags))
2858 // we have the delegate 'this' but we need the EEImpl/Instantiated 'Invoke' MD pointer
2859 // (Delegate.GetInvokeMethod does not return exact instantiated MD so we call our own helper)
2860 pcsEmit->EmitLoadThis();
2861 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_INVOKE_METHOD, 1, 1);
2864 #endif // FEATURE_COMINTEROP
2866 // get the secret argument via intrinsic
2867 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2871 #ifdef MDA_SUPPORTED
2872 void NDirectStubLinker::EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2874 STANDARD_VM_CONTRACT;
2876 ILCodeLabel *pSkipGcLabel = NULL;
2878 if (SF_IsForwardPInvokeStub(dwStubFlags) &&
2879 !SF_IsDelegateStub(dwStubFlags) &&
2880 !SF_IsCALLIStub(dwStubFlags))
2882 // don't call GC if this is a QCall
2883 EmitLoadStubContext(pcsEmit, dwStubFlags);
2884 pcsEmit->EmitCALL(METHOD__STUBHELPERS__IS_QCALL, 1, 1);
2886 pSkipGcLabel = pcsEmit->NewCodeLabel();
2887 pcsEmit->EmitBRTRUE(pSkipGcLabel);
2890 pcsEmit->EmitCALL(METHOD__STUBHELPERS__TRIGGER_GC_FOR_MDA, 0, 0);
2892 if (pSkipGcLabel != NULL)
2894 pcsEmit->EmitLabel(pSkipGcLabel);
2897 #endif // MDA_SUPPORTED
2899 #ifdef FEATURE_COMINTEROP
2901 class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing calls
2908 WRAPPER_NO_CONTRACT;
2911 void SetLastError(BOOL fSetLastError)
2913 LIMITED_METHOD_CONTRACT;
2915 CONSISTENCY_CHECK(!fSetLastError);
2918 void BeginEmit(DWORD dwStubFlags)
2920 LIMITED_METHOD_CONTRACT;
2922 CONSISTENCY_CHECK(SF_IsCOMStub(dwStubFlags));
2923 m_dwStubFlags = dwStubFlags;
2926 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
2932 PRECONDITION(CheckPointer(pInfo));
2937 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
2942 PRECONDITION(CheckPointer(pInfo));
2946 if (SF_IsCOMLateBoundStub(m_dwStubFlags) && pInfo->GetDispWrapperType() != 0)
2948 m_lateBoundFlags |= ComPlusCallInfo::kRequiresArgumentWrapping;
2952 void MarshalLCID(int argIdx)
2954 LIMITED_METHOD_CONTRACT;
2957 #ifdef FEATURE_COMINTEROP
2958 void MarshalHiddenLengthArgument(MarshalInfo *, BOOL)
2960 LIMITED_METHOD_CONTRACT;
2962 void MarshalFactoryReturn()
2964 LIMITED_METHOD_CONTRACT;
2967 #endif // FEATURE_COMINTEROP
2969 void EmitInvokeTarget(MethodDesc *pStubMD)
2971 LIMITED_METHOD_CONTRACT;
2972 UNREACHABLE_MSG("Should never come to DispatchStubState::EmitInvokeTarget");
2975 void FinishEmit(MethodDesc *pMD)
2977 STANDARD_VM_CONTRACT;
2979 // set flags directly on the interop MD
2980 _ASSERTE(pMD->IsComPlusCall());
2982 ((ComPlusCallMethodDesc *)pMD)->SetLateBoundFlags(m_lateBoundFlags);
2986 DWORD m_dwStubFlags;
2987 BYTE m_lateBoundFlags; // ComPlusCallMethodDesc::Flags
2990 #endif // FEATURE_COMINTEROP
2993 void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
3003 // initialize data members
3005 m_pModule = pModule;
3006 m_callConv = (CorPinvokeMap)0;
3007 SetBestFitMapping (TRUE);
3008 SetThrowOnUnmappableChar (FALSE);
3009 SetLinkFlags (nlfNone);
3010 SetCharSet (nltAnsi);
3013 // assembly/type level m_bestFit & m_bThrowOnUnmappableChar
3015 BOOL bThrowOnUnmappableChar;
3019 EEClass::GetBestFitMapping(pMT, &bBestFit, &bThrowOnUnmappableChar);
3023 ReadBestFitCustomAttribute(m_pModule->GetMDImport(), mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
3026 SetBestFitMapping (bBestFit);
3027 SetThrowOnUnmappableChar (bThrowOnUnmappableChar);
3030 void PInvokeStaticSigInfo::PreInit(MethodDesc* pMD)
3040 PreInit(pMD->GetModule(), pMD->GetMethodTable());
3041 SetIsStatic (pMD->IsStatic());
3042 m_sig = pMD->GetSignature();
3043 if (pMD->IsEEImpl())
3045 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
3046 SetIsDelegateInterop(TRUE);
3050 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
3051 MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError)
3061 DllImportInit(pMD, pLibName, pEntryPointName);
3067 PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOnError)
3075 PRECONDITION(CheckPointer(pMD));
3081 MethodTable * pMT = pMD->GetMethodTable();
3083 if (!pMT->IsDelegate())
3085 DllImportInit(pMD, NULL, NULL);
3089 // initialize data members to defaults
3092 // System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute
3095 CorPinvokeMap callConv = (CorPinvokeMap)0;
3097 HRESULT hRESULT = pMT->GetMDImport()->GetCustomAttributeByName(
3098 pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, (const VOID **)(&pData), (ULONG *)&cData);
3099 IfFailThrow(hRESULT);
3102 CustomAttributeParser ca(pData, cData);
3105 args[0].InitEnum(SERIALIZATION_TYPE_I4, (ULONG)m_callConv);
3107 IfFailGo(ParseKnownCaArgs(ca, args, lengthof(args)));
3109 enum UnmanagedFunctionPointerNamedArgs
3113 MDA_ThrowOnUnmappableChar,
3119 CaNamedArg namedArgs[MDA_Last];
3120 namedArgs[MDA_CharSet].InitI4FieldEnum("CharSet", "System.Runtime.InteropServices.CharSet", (ULONG)GetCharSet());
3121 namedArgs[MDA_BestFitMapping].InitBoolField("BestFitMapping", (ULONG)GetBestFitMapping());
3122 namedArgs[MDA_ThrowOnUnmappableChar].InitBoolField("ThrowOnUnmappableChar", (ULONG)GetThrowOnUnmappableChar());
3123 namedArgs[MDA_SetLastError].InitBoolField("SetLastError", 0);
3124 namedArgs[MDA_PreserveSig].InitBoolField("PreserveSig", 0);
3126 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
3128 callConv = (CorPinvokeMap)(args[0].val.u4 << 8);
3129 CorNativeLinkType nlt = (CorNativeLinkType)0;
3131 // XXX Tue 07/19/2005
3132 // Keep in sync with the handling of CorPInvokeMap in
3133 // PInvokeStaticSigInfo::DllImportInit.
3134 switch( namedArgs[MDA_CharSet].val.u4 )
3138 nlt = nltAnsi; break;
3140 case nltAuto: // Since Win9x isn't supported anymore, nltAuto always represents unicode strings.
3141 nlt = nltUnicode; break;
3143 hr = E_FAIL; goto ErrExit;
3146 SetBestFitMapping (namedArgs[MDA_BestFitMapping].val.u1);
3147 SetThrowOnUnmappableChar (namedArgs[MDA_ThrowOnUnmappableChar].val.u1);
3148 if (namedArgs[MDA_SetLastError].val.u1)
3149 SetLinkFlags ((CorNativeLinkFlags)(nlfLastError | GetLinkFlags()));
3150 if (namedArgs[MDA_PreserveSig].val.u1)
3151 SetLinkFlags ((CorNativeLinkFlags)(nlfNoMangle | GetLinkFlags()));
3157 SetError(IDS_EE_NDIRECT_BADNATL);
3159 InitCallConv(callConv, pMD->IsVarArg());
3165 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
3166 Signature sig, Module* pModule, ThrowOnError throwOnError)
3174 PRECONDITION(CheckPointer(pModule));
3178 PreInit(pModule, NULL);
3180 SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
3181 InitCallConv((CorPinvokeMap)0, FALSE);
3187 void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LPCUTF8 *ppEntryPointName)
3195 PRECONDITION(CheckPointer(pMD));
3197 // These preconditions to prevent multithreaded regression
3198 // where pMD->ndirect.m_szLibName was passed in directly, cleared
3199 // by this API, then accessed on another thread before being reset here.
3200 PRECONDITION(CheckPointer(ppLibName, NULL_OK) && (!ppLibName || *ppLibName == NULL));
3201 PRECONDITION(CheckPointer(ppEntryPointName, NULL_OK) && (!ppEntryPointName || *ppEntryPointName == NULL));
3205 // initialize data members to defaults
3208 // System.Runtime.InteropServices.DLLImportAttribute
3209 IMDInternalImport *pInternalImport = pMD->GetMDImport();
3210 CorPinvokeMap mappingFlags = pmMaxValue;
3211 mdModuleRef modref = mdModuleRefNil;
3212 if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
3214 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3215 // The guessing heuristic has been broken with NGen for a long time since we stopped loading
3216 // images at NGen time using full LoadLibrary. The DLL references are not resolved correctly
3217 // without full LoadLibrary.
3219 // Disable the heuristic consistently during NGen so that it does not kick in by accident.
3220 if (!IsCompilationProcess())
3221 BestGuessNDirectDefaults(pMD);
3223 InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
3227 // out parameter pEntryPointName
3228 if (ppEntryPointName && *ppEntryPointName == NULL)
3229 *ppEntryPointName = pMD->GetName();
3231 // out parameter pLibName
3232 if (ppLibName != NULL)
3234 if (FAILED(pInternalImport->GetModuleRefProps(modref, ppLibName)))
3236 SetError(IDS_CLASSLOAD_BADFORMAT);
3242 InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
3245 CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
3246 if (bestFitMask == pmBestFitEnabled)
3247 SetBestFitMapping (TRUE);
3248 else if (bestFitMask == pmBestFitDisabled)
3249 SetBestFitMapping (FALSE);
3251 // m_bThrowOnUnmappableChar
3252 CorPinvokeMap unmappableMask = (CorPinvokeMap)(mappingFlags & pmThrowOnUnmappableCharMask);
3253 if (unmappableMask == pmThrowOnUnmappableCharEnabled)
3254 SetThrowOnUnmappableChar (TRUE);
3255 else if (unmappableMask == pmThrowOnUnmappableCharDisabled)
3256 SetThrowOnUnmappableChar (FALSE);
3258 // inkFlags : CorPinvoke -> CorNativeLinkFlags
3259 if (mappingFlags & pmSupportsLastError)
3260 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3261 if (mappingFlags & pmNoMangle)
3262 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfNoMangle));
3264 // XXX Tue 07/19/2005
3265 // Keep in sync with the handling of CorNativeLinkType in
3266 // PInvokeStaticSigInfo::PInvokeStaticSigInfo.
3268 // charset : CorPinvoke -> CorNativeLinkType
3269 CorPinvokeMap charSetMask = (CorPinvokeMap)(mappingFlags & (pmCharSetNotSpec | pmCharSetAnsi | pmCharSetUnicode | pmCharSetAuto));
3270 if (charSetMask == pmCharSetNotSpec || charSetMask == pmCharSetAnsi)
3272 SetCharSet (nltAnsi);
3274 else if (charSetMask == pmCharSetUnicode || charSetMask == pmCharSetAuto)
3276 // Since Win9x isn't supported anymore, pmCharSetAuto always represents unicode strings.
3277 SetCharSet (nltUnicode);
3281 SetError(IDS_EE_NDIRECT_BADNATL);
3286 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3288 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3289 static BOOL HeuristicDoesThisLooksLikeAnApiCallHelper(LPBYTE pTarget)
3299 // This code is not that useful anymore since this functionality is already embedded in the VC linker.
3300 // The linker will emit the lasterror flag by default for functions residing in modules that are
3301 // a superset of the list below.
3302 // Look for bug VSWhidbey 241895.
3304 static struct SysDllInfo
3309 } gSysDllInfo[] = {{WINDOWS_KERNEL32_DLLNAME_W, 0, 0},
3311 {W("USER32"), 0, 0},
3312 {W("ADVAPI32"), 0, 0}
3316 for (int i = 0; i < sizeof(gSysDllInfo)/sizeof(*gSysDllInfo); i++)
3318 if (gSysDllInfo[i].pImageBase == 0)
3320 IMAGE_DOS_HEADER *pDos = (IMAGE_DOS_HEADER*)CLRGetModuleHandle(gSysDllInfo[i].pName);
3323 if (pDos->e_magic == VAL16(IMAGE_DOS_SIGNATURE))
3325 IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*) (((LPBYTE)pDos) + VAL32(pDos->e_lfanew));
3326 if (pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) &&
3327 pNT->FileHeader.SizeOfOptionalHeader ==
3329 VAL16(sizeof(IMAGE_OPTIONAL_HEADER64))
3331 VAL16(sizeof(IMAGE_OPTIONAL_HEADER32))
3333 && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
3335 gSysDllInfo[i].dwImageSize = VAL32(pNT->OptionalHeader.SizeOfImage);
3339 gSysDllInfo[i].pImageBase = (LPBYTE)pDos;
3342 if (gSysDllInfo[i].pImageBase != 0 &&
3343 pTarget >= gSysDllInfo[i].pImageBase &&
3344 pTarget < gSysDllInfo[i].pImageBase + gSysDllInfo[i].dwImageSize)
3353 LPBYTE FollowIndirect(LPBYTE pTarget)
3360 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3368 AVInRuntimeImplOkayHolder AVOkay;
3371 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3373 pRet = **(LPBYTE**)(pTarget + 2);
3375 #elif defined(_TARGET_AMD64_)
3376 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3378 INT64 rva = *(INT32*)(pTarget + 2);
3379 pRet = *(LPBYTE*)(pTarget + 6 + rva);
3387 EX_END_CATCH(SwallowAllExceptions);
3392 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3393 BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget)
3403 if (pTarget == NULL)
3406 if (HeuristicDoesThisLooksLikeAnApiCallHelper(pTarget))
3409 LPBYTE pTarget2 = FollowIndirect(pTarget);
3412 // jmp [xxxx] - could be an import thunk
3413 return HeuristicDoesThisLooksLikeAnApiCallHelper( pTarget2 );
3419 BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
3429 static LPBYTE pGetLastError = NULL;
3432 // No need to use a holder here, since no cleanup is necessary.
3433 HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
3436 pGetLastError = (LPBYTE)GetProcAddress(hMod, "GetLastError");
3439 // This should never happen but better to be cautious.
3440 pGetLastError = (LPBYTE)-1;
3445 // We failed to get the module handle for kernel32.dll. This is almost impossible
3446 // however better to err on the side of caution.
3447 pGetLastError = (LPBYTE)-1;
3451 if (pTarget == pGetLastError)
3454 if (pTarget == NULL)
3457 LPBYTE pTarget2 = FollowIndirect(pTarget);
3460 // jmp [xxxx] - could be an import thunk
3461 return pTarget2 == pGetLastError;
3467 DWORD __stdcall FalseGetLastError()
3469 WRAPPER_NO_CONTRACT;
3471 return GetThread()->m_dwLastError;
3474 void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
3484 if (!pMD->IsNDirect())
3487 NDirectMethodDesc* pMDD = (NDirectMethodDesc*)pMD;
3489 if (!pMDD->IsEarlyBound())
3492 LPVOID pTarget = NULL;
3494 // NOTE: If we get inside this block, and this is a call to GetLastError,
3495 // then InitEarlyBoundNDirectTarget has not been run yet.
3496 if (pMDD->NDirectTargetIsImportThunk())
3498 // Get the unmanaged callsite.
3499 pTarget = (LPVOID)pMDD->GetModule()->GetInternalPInvokeTarget(pMDD->GetRVA());
3501 // If this is a call to GetLastError, then we haven't overwritten m_pNativeNDirectTarget yet.
3502 if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)pTarget))
3503 pTarget = (BYTE*) FalseGetLastError;
3507 pTarget = pMDD->GetNativeNDirectTarget();
3510 if (HeuristicDoesThisLooksLikeAnApiCall((LPBYTE) pTarget))
3511 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3514 #endif // FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
3517 void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
3527 // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
3528 if (callConv == pmCallConvWinapi)
3529 callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3531 CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
3532 BOOL fSuccess = MetaSig::GetUnmanagedCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv);
3536 SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format
3539 // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
3540 // to do this before we check to make sure the PInvoke map calling convention and the
3541 // signature calling convention match for compatibility reasons.
3542 if (sigCallConv == pmCallConvWinapi)
3543 sigCallConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3545 if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
3546 SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
3548 if (callConv == 0 && sigCallConv == 0)
3549 m_callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3550 else if (callConv != 0)
3551 m_callConv = callConv;
3553 m_callConv = sigCallConv;
3555 if (bIsVarArg && m_callConv != pmCallConvCdecl)
3556 SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
3559 void PInvokeStaticSigInfo::ReportErrors()
3570 COMPlusThrow(kTypeLoadException, m_error);
3574 //---------------------------------------------------------
3575 // Does a class or method have a NAT_L CustomAttribute?
3579 // FAILED = unknown because something failed.
3580 //---------------------------------------------------------
3582 HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs)
3590 PRECONDITION(CheckPointer(pInternalImport));
3591 PRECONDITION(TypeFromToken(token) == mdtMethodDef);
3595 // Check method flags first before trying to find the custom value
3596 if (!IsReallyMdPinvokeImpl(dwMemberAttrs))
3600 LPCSTR pszImportName;
3603 if (SUCCEEDED(pInternalImport->GetPinvokeMap(token, &mappingFlags, &pszImportName, &modref)))
3610 // Either MD or signature & module must be given.
3612 BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*/, Module *pModule /*= NULL*/)
3617 PRECONDITION(pMD != NULL || (pSig != NULL && pModule != NULL));
3621 // As a by-product, when returning FALSE we will also set the native stack size to the MD if it's
3622 // an NDirectMethodDesc. This number is needed to link the P/Invoke (it determines the @n entry
3623 // point name suffix and affects alignment thunk generation on the Mac). If this method returns
3624 // TRUE, the stack size will be set when building the marshaling IL stub.
3625 DWORD dwStackSize = 0;
3626 CorPinvokeMap callConv = (CorPinvokeMap)0;
3630 if (pMD->IsNDirect() || pMD->IsComPlusCall())
3632 // HRESULT swapping is handled by stub
3633 if ((pMD->GetImplAttrs() & miPreserveSig) == 0)
3637 // SetLastError is handled by stub
3638 PInvokeStaticSigInfo sigInfo(pMD);
3639 if (sigInfo.GetLinkFlags() & nlfLastError)
3642 // LCID argument is handled by stub
3643 if (GetLCIDParameterIndex(pMD) != -1)
3646 // making sure that cctor has run may be handled by stub
3647 if (pMD->IsNDirect() && ((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
3650 callConv = sigInfo.GetCallConv();
3655 PREFIX_ASSUME(pMD != NULL);
3657 pSig = pMD->GetSig();
3658 pModule = pMD->GetModule();
3661 // Check to make certain that the signature only contains types that marshal trivially
3662 SigPointer ptr(pSig);
3663 IfFailThrow(ptr.GetCallingConvInfo(NULL));
3665 IfFailThrow(ptr.GetData(&numArgs));
3666 numArgs++; // +1 for return type
3668 // We'll need to parse parameter native types
3669 mdParamDef *pParamTokenArray = (mdParamDef *)_alloca(numArgs * sizeof(mdParamDef));
3670 IMDInternalImport *pMDImport = pModule->GetMDImport();
3672 SigTypeContext emptyTypeContext;
3674 mdMethodDef methodToken = mdMethodDefNil;
3677 methodToken = pMD->GetMemberDef();
3679 CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
3681 for (ULONG i = 0; i < numArgs; i++)
3683 SigPointer arg = ptr;
3684 CorElementType type;
3685 IfFailThrow(arg.PeekElemType(&type));
3689 case ELEMENT_TYPE_PTR:
3691 IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR
3692 IfFailThrow(arg.PeekElemType(&type));
3694 if (type == ELEMENT_TYPE_VALUETYPE)
3696 if ((arg.HasCustomModifier(pModule,
3697 "Microsoft.VisualC.NeedsCopyConstructorModifier",
3698 ELEMENT_TYPE_CMOD_REQD)) ||
3699 (arg.HasCustomModifier(pModule,
3700 "System.Runtime.CompilerServices.IsCopyConstructed",
3701 ELEMENT_TYPE_CMOD_REQD)))
3706 if (i > 0) dwStackSize += sizeof(SLOT);
3710 case ELEMENT_TYPE_INTERNAL:
3712 // this check is not functional in DAC and provides no security against a malicious dump
3713 // the DAC is prepared to receive an invalid type handle
3714 #ifndef DACCESS_COMPILE
3715 if (pModule->IsSigInIL(arg.GetPtr()))
3716 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
3721 case ELEMENT_TYPE_VALUETYPE:
3723 TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext);
3725 // JIT can handle internal blittable value types
3726 if (!hndArgType.IsBlittable() && !hndArgType.IsEnum())
3731 // return value is fine as long as it can be normalized to an integer
3734 CorElementType normalizedType = hndArgType.GetInternalCorElementType();
3735 if (normalizedType == ELEMENT_TYPE_VALUETYPE)
3737 // it is a structure even after normalization
3743 dwStackSize += StackElemSize(hndArgType.GetSize());
3748 case ELEMENT_TYPE_BOOLEAN:
3749 case ELEMENT_TYPE_CHAR:
3751 // Bool requires marshaling
3752 // Char may require marshaling (MARSHAL_TYPE_ANSICHAR)
3758 if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
3760 if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
3764 // other non-primitive type - requires marshaling
3770 // check for explicit MarshalAs
3771 NativeTypeParamInfo paramInfo;
3773 if (pParamTokenArray[i] != mdParamDefNil)
3775 if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, ¶mInfo) ||
3776 paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT)
3778 // Presence of MarshalAs does not necessitate marshaling (it could as well be the default
3779 // for the type), but it's a good enough heuristic. We definitely don't want to duplicate
3780 // the logic from code:MarshalInfo.MarshalInfo here.
3785 IfFailThrow(ptr.SkipExactlyOne());
3788 if (!FitsInU2(dwStackSize))
3791 // do not set the stack size for varargs - the number is call site specific
3792 if (pMD != NULL && !pMD->IsVarArg())
3794 if (pMD->IsNDirect())
3796 ((NDirectMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize), callConv);
3798 #ifdef FEATURE_COMINTEROP
3799 else if (pMD->IsComPlusCall())
3801 // calling convention is always stdcall
3802 ((ComPlusCallMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize));
3804 #endif // FEATURE_COMINTEROP
3811 // factorization of CreateNDirectStubWorker
3812 static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig,
3814 CorNativeLinkType nlType,
3815 CorNativeLinkFlags nlFlags,
3816 UINT argidx, // this is used for reverse pinvoke hresult swapping
3822 UINT& nativeStackOffset,
3823 bool& fStubNeedsCOM,
3825 DEBUG_ARG(LPCUTF8 pDebugName)
3826 DEBUG_ARG(LPCUTF8 pDebugClassName)
3833 PRECONDITION(CheckPointer(params));
3834 PRECONDITION(CheckPointer(pss));
3835 PRECONDITION(CheckPointer(pMD, NULL_OK));
3839 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3841 MarshalInfo::MarshalScenario ms;
3842 #ifdef FEATURE_COMINTEROP
3843 if (SF_IsCOMStub(dwStubFlags))
3845 if (SF_IsWinRTStub(dwStubFlags))
3846 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3848 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3851 #endif // FEATURE_COMINTEROP
3853 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
3856 #ifdef FEATURE_COMINTEROP
3857 if (SF_IsWinRTCtorStub(dwStubFlags))
3859 _ASSERTE(msig.GetReturnType() == ELEMENT_TYPE_VOID);
3860 _ASSERTE(SF_IsHRESULTSwapping(dwStubFlags));
3862 pss->MarshalFactoryReturn();
3863 nativeStackOffset += sizeof(LPVOID);
3864 if (SF_IsWinRTCompositionStub(dwStubFlags))
3866 nativeStackOffset += 2 * sizeof(LPVOID);
3870 #endif // FEATURE_COMINTEROP
3871 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
3873 MarshalInfo returnInfo(msig.GetModule(),
3874 msig.GetReturnProps(),
3875 msig.GetSigTypeContext(),
3882 msig.NumFixedArgs(),
3883 SF_IsBestFit(dwStubFlags),
3884 SF_IsThrowOnUnmappableChar(dwStubFlags),
3888 DEBUG_ARG(pDebugName)
3889 DEBUG_ARG(pDebugClassName)
3893 marshalType = returnInfo.GetMarshalType();
3895 fStubNeedsCOM |= returnInfo.MarshalerRequiresCOM();
3897 #ifdef FEATURE_COMINTEROP
3898 if (marshalType == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3900 // Hidden length arrays are only valid with HRESULT swapping
3901 if (!SF_IsHRESULTSwapping(dwStubFlags))
3903 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3906 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3907 returnInfo.SetHiddenLengthParamIndex(static_cast<UINT16>(nativeArgIndex));
3909 // Inject the hidden argument so that it winds up at the end of the method signature
3910 pss->MarshalHiddenLengthArgument(&returnInfo, TRUE);
3911 nativeStackOffset += returnInfo.GetHiddenLengthParamStackSize();
3913 if (SF_IsReverseStub(dwStubFlags))
3919 if (SF_IsCOMStub(dwStubFlags))
3921 if (marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS ||
3922 marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3923 marshalType == MarshalInfo::MARSHAL_TYPE_GUID ||
3924 marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL)
3926 #ifndef _TARGET_X86_
3927 // We cannot optimize marshalType to MARSHAL_TYPE_GENERIC_* because the JIT works with exact types
3928 // and would refuse to compile the stub if it implicitly converted between scalars and value types (also see
3929 // code:MarshalInfo.MarhalInfo where we do the optimization on x86). We want to throw only if the structure
3930 // is too big to be returned in registers.
3931 if (marshalType != MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3932 IsUnmanagedValueTypeReturnedByRef(returnInfo.GetNativeArgSize()))
3933 #endif // _TARGET_X86_
3935 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3937 // Note that this limitation is very likely not needed anymore and could be lifted if we care.
3938 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3942 pss->MarshalReturn(&returnInfo, argOffset);
3946 // We don't support native methods that return VARIANTs directly.
3947 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT)
3949 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3951 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3955 pss->MarshalReturn(&returnInfo, argOffset);
3959 #endif // FEATURE_COMINTEROP
3961 if (marshalType > MarshalInfo::MARSHAL_TYPE_DOUBLE && IsUnsupportedValueTypeReturn(msig))
3963 if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
3964 || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
3965 || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
3966 #ifdef FEATURE_COMINTEROP
3967 || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
3968 #endif // FEATURE_COMINTEROP
3971 if (SF_IsHRESULTSwapping(dwStubFlags))
3973 // V1 restriction: we could implement this but it's late in the game to do so.
3974 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3977 else if (marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF)
3979 COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION);
3983 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3987 #ifdef FEATURE_COMINTEROP
3988 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
3990 // No support for returning variants. This is a V1 restriction, due to the late date,
3991 // don't want to add the special-case code to support this in light of low demand.
3992 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NOVARIANTRETURN);
3994 #endif // FEATURE_COMINTEROP
3996 pss->MarshalReturn(&returnInfo, argOffset);
4003 static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
4005 LIMITED_METHOD_CONTRACT;
4009 // -1 means that the argument is not on the stack
4010 return (stackSize >= sizeof(SLOT) ? (stackSize - sizeof(SLOT)) : (UINT)-1);
4012 #endif // _TARGET_X86_
4016 #ifdef FEATURE_COMINTEROP
4018 struct HiddenParameterInfo
4020 MarshalInfo *pManagedParam; // Managed parameter which required the hidden parameter
4021 int nativeIndex; // 0 based index into the native method signature where the hidden parameter should be injected
4024 // Get the indexes of any hidden length parameters to be marshaled for the method
4026 // At return, each value in the ppParamIndexes array is a 0 based index into the native method signature where
4027 // the length parameter for a hidden length array should be passed. The MarshalInfo objects will also be
4028 // updated such that they all have explicit marshaling information.
4030 // The caller is responsible for freeing the memory pointed to by ppParamIndexes
4031 void CheckForHiddenParameters(DWORD cParamMarshalInfo,
4032 __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo,
4033 __out DWORD *pcHiddenNativeParameters,
4034 __out_ecount(*pcHiddenNativeParameters) HiddenParameterInfo **ppHiddenNativeParameters)
4039 PRECONDITION(CheckPointer(pParamMarshalInfo));
4040 PRECONDITION(CheckPointer(pcHiddenNativeParameters));
4041 PRECONDITION(CheckPointer(ppHiddenNativeParameters));
4045 NewArrayHolder<HiddenParameterInfo> hiddenParamInfo(new HiddenParameterInfo[cParamMarshalInfo]);
4046 DWORD foundInfoCount = 0;
4048 for (DWORD iParam = 0; iParam < cParamMarshalInfo; ++iParam)
4050 // Look for hidden length arrays, which all require additional parameters to be added
4051 if (pParamMarshalInfo[iParam].GetMarshalType() == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
4053 DWORD currentNativeIndex = iParam + foundInfoCount;
4055 // The location of the length parameter is implicitly just before the array pointer.
4056 // We'll give it our current index, and bumping the found count will push us back a slot.
4058 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
4059 pParamMarshalInfo[iParam].SetHiddenLengthParamIndex(static_cast<UINT16>(currentNativeIndex));
4061 hiddenParamInfo[foundInfoCount].nativeIndex = pParamMarshalInfo[iParam].HiddenLengthParamIndex();
4062 hiddenParamInfo[foundInfoCount].pManagedParam = &(pParamMarshalInfo[iParam]);
4067 *pcHiddenNativeParameters = foundInfoCount;
4068 *ppHiddenNativeParameters = hiddenParamInfo.Extract();
4071 bool IsHiddenParameter(int nativeArgIndex,
4072 DWORD cHiddenParameters,
4073 __in_ecount(cHiddenParameters) HiddenParameterInfo *pHiddenParameters,
4074 __out HiddenParameterInfo **ppHiddenParameterInfo)
4079 PRECONDITION(cHiddenParameters == 0 || CheckPointer(pHiddenParameters));
4080 PRECONDITION(CheckPointer(ppHiddenParameterInfo));
4084 *ppHiddenParameterInfo = NULL;
4086 for (DWORD i = 0; i < cHiddenParameters; ++i)
4088 _ASSERTE(pHiddenParameters[i].nativeIndex != -1);
4089 if (pHiddenParameters[i].nativeIndex == nativeArgIndex)
4091 *ppHiddenParameterInfo = &(pHiddenParameters[i]);
4099 #endif // FEATURE_COMINTEROP
4101 //---------------------------------------------------------
4102 // Creates a new stub for a N/Direct call. Return refcount is 1.
4103 // Note that this function may now throw if it fails to create
4105 //---------------------------------------------------------
4106 static void CreateNDirectStubWorker(StubState* pss,
4107 StubSigDesc* pSigDesc,
4108 CorNativeLinkType nlType,
4109 CorNativeLinkFlags nlFlags,
4110 CorPinvokeMap unmgdCallConv,
4113 mdParamDef* pParamTokenArray,
4121 PRECONDITION(CheckPointer(pss));
4122 PRECONDITION(CheckPointer(pSigDesc));
4123 PRECONDITION(CheckPointer(pMD, NULL_OK));
4124 PRECONDITION(!pMD || pMD->IsILStub() || (0 != pMD->GetMethodTable()->IsDelegate()) == SF_IsDelegateStub(dwStubFlags));
4128 SF_ConsistencyCheck(dwStubFlags);
4131 if (g_pConfig->ShouldBreakOnInteropStubSetup(pSigDesc->m_pDebugName))
4132 CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName));
4137 if (SF_IsCOMStub(dwStubFlags))
4139 _ASSERTE(0 == nlType);
4140 _ASSERTE(0 == nlFlags);
4141 _ASSERTE(0 == unmgdCallConv);
4145 _ASSERTE(nlType == nltAnsi || nlType == nltUnicode);
4147 Module *pModule = pSigDesc->m_pModule;
4150 // Set up signature walking objects.
4153 MetaSig msig(pSigDesc->m_sig,
4155 &pSigDesc->m_typeContext);
4157 if (SF_IsVarArgStub(dwStubFlags))
4158 msig.SetTreatAsVarArg();
4160 bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
4162 pss->SetLastError(nlFlags & nlfLastError);
4164 // This has been in the product since forward P/Invoke via delegates was
4165 // introduced. It's wrong, but please keep it for backward compatibility.
4166 if (SF_IsDelegateStub(dwStubFlags))
4167 pss->SetLastError(TRUE);
4169 pss->BeginEmit(dwStubFlags);
4173 // LCID is not supported on WinRT
4174 _ASSERTE(!SF_IsWinRTStub(dwStubFlags));
4176 // The code to handle the LCID will call MarshalLCID before calling MarshalArgument
4177 // on the argument the LCID should go after. So we just bump up the index here.
4181 int numArgs = msig.NumFixedArgs();
4183 // thiscall must have at least one parameter (the "this")
4184 if (fThisCall && numArgs == 0)
4185 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4188 // Now, emit the IL.
4193 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
4196 // Marshal the return value.
4199 UINT nativeStackSize = (SF_IsCOMStub(dwStubFlags) ? sizeof(SLOT) : 0);
4200 bool fHasCopyCtorArgs = false;
4201 bool fStubNeedsCOM = SF_IsCOMStub(dwStubFlags);
4203 // The return structure secret arg comes first, however byvalue return is processed at
4204 // the end because it could be the HRESULT-swapped argument which always comes last.
4205 bool fMarshalReturnValueFirst = !SF_IsHRESULTSwapping(dwStubFlags) && HasRetBuffArg(&msig);
4207 if (fMarshalReturnValueFirst)
4209 marshalType = DoMarshalReturnValue(msig,
4222 DEBUG_ARG(pSigDesc->m_pDebugName)
4223 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4226 if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE ||
4227 marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY ||
4228 marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET ||
4229 marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF ||
4230 marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
4231 #ifdef FEATURE_COMINTEROP
4232 || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
4233 #endif // FEATURE_COMINTEROP
4236 // These are special non-blittable types returned by-ref in managed,
4237 // but marshaled as primitive values returned by-value in unmanaged.
4241 // This is an ordinary value type - see if it is returned by-ref.
4242 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4243 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4245 nativeStackSize += sizeof(LPVOID);
4251 // Marshal the arguments
4253 MarshalInfo::MarshalScenario ms;
4254 #ifdef FEATURE_COMINTEROP
4255 if (SF_IsCOMStub(dwStubFlags))
4257 if (SF_IsWinRTStub(dwStubFlags))
4258 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
4260 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
4263 #endif // FEATURE_COMINTEROP
4265 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
4268 // Build up marshaling information for each of the method's parameters
4269 SIZE_T cbParamMarshalInfo;
4270 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(MarshalInfo), numArgs, cbParamMarshalInfo))
4272 COMPlusThrowHR(COR_E_OVERFLOW);
4275 NewArrayHolder<BYTE> pbParamMarshalInfo(new BYTE[cbParamMarshalInfo]);
4276 MarshalInfo *pParamMarshalInfo = reinterpret_cast<MarshalInfo *>(pbParamMarshalInfo.GetValue());
4278 MetaSig paramInfoMSig(msig);
4279 for (int i = 0; i < numArgs; ++i)
4281 paramInfoMSig.NextArg();
4282 new(&(pParamMarshalInfo[i])) MarshalInfo(paramInfoMSig.GetModule(),
4283 paramInfoMSig.GetArgProps(),
4284 paramInfoMSig.GetSigTypeContext(),
4285 pParamTokenArray[i + 1],
4292 SF_IsBestFit(dwStubFlags),
4293 SF_IsThrowOnUnmappableChar(dwStubFlags),
4297 DEBUG_ARG(pSigDesc->m_pDebugName)
4298 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4302 #ifdef FEATURE_COMINTEROP
4303 // Check to see if we need to inject any additional hidden parameters
4304 DWORD cHiddenNativeParameters;
4305 NewArrayHolder<HiddenParameterInfo> pHiddenNativeParameters;
4306 CheckForHiddenParameters(numArgs, pParamMarshalInfo, &cHiddenNativeParameters, &pHiddenNativeParameters);
4308 // Hidden parameters and LCID do not mix
4309 _ASSERTE(!(cHiddenNativeParameters > 0 && iLCIDArg != -1));
4310 #endif // FEATURE_COMINTEROP
4312 // Marshal the parameters
4314 int nativeArgIndex = 0;
4315 while (argidx <= numArgs)
4317 #ifdef FEATURE_COMINTEROP
4318 HiddenParameterInfo *pHiddenParameter;
4319 // Check to see if we need to inject a hidden parameter
4320 if (IsHiddenParameter(nativeArgIndex, cHiddenNativeParameters, pHiddenNativeParameters, &pHiddenParameter))
4322 pss->MarshalHiddenLengthArgument(pHiddenParameter->pManagedParam, FALSE);
4323 nativeStackSize += pHiddenParameter->pManagedParam->GetHiddenLengthParamStackSize();
4325 if (SF_IsReverseStub(dwStubFlags))
4331 #endif // FEATURE_COMINTEROP
4334 // Check to see if this is the parameter after which we need to insert the LCID.
4336 if (argidx == iLCIDArg)
4338 pss->MarshalLCID(argidx);
4339 nativeStackSize += sizeof(LPVOID);
4341 if (SF_IsReverseStub(dwStubFlags))
4347 MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4349 #ifdef FEATURE_COMINTEROP
4350 // For the hidden-length array, length parameters must occur before the parameter containing the array pointer
4351 _ASSERTE(info.GetMarshalType() != MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY || nativeArgIndex > info.HiddenLengthParamIndex());
4352 #endif // FEATURE_COMINTEROP
4354 pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4355 nativeStackSize += info.GetNativeArgSize();
4357 fStubNeedsCOM |= info.MarshalerRequiresCOM();
4359 if (fThisCall && argidx == 1)
4361 // make sure that the first parameter is enregisterable
4362 if (info.GetNativeArgSize() > sizeof(SLOT))
4363 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4366 #ifndef FEATURE_CORECLR
4367 if (info.GetMarshalType() == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR)
4369 fHasCopyCtorArgs = true;
4371 #endif // !FEATURE_CORECLR
4379 // Check to see if this is the parameter after which we need to insert the LCID.
4380 if (argidx == iLCIDArg)
4382 pss->MarshalLCID(argidx);
4383 nativeStackSize += sizeof(LPVOID);
4385 if (SF_IsReverseStub(dwStubFlags))
4389 if (!fMarshalReturnValueFirst)
4391 // This could be a HRESULT-swapped argument so it must come last.
4392 marshalType = DoMarshalReturnValue(msig,
4405 DEBUG_ARG(pSigDesc->m_pDebugName)
4406 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4409 // If the return value is a SafeHandle or CriticalHandle, mark the stub method.
4410 // Interop methods that use this stub will have an implicit reliability contract
4411 // (see code:TAStackCrawlCallBack).
4412 if (!SF_IsHRESULTSwapping(dwStubFlags))
4414 if (marshalType == MarshalInfo::MARSHAL_TYPE_SAFEHANDLE ||
4415 marshalType == MarshalInfo::MARSHAL_TYPE_CRITICALHANDLE)
4417 if (pMD->IsDynamicMethod())
4418 pMD->AsDynamicMethodDesc()->SetUnbreakable(true);
4423 if (SF_IsHRESULTSwapping(dwStubFlags))
4425 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
4426 nativeStackSize += sizeof(LPVOID);
4429 if (pMD->IsDynamicMethod())
4431 // Set the native stack size to the IL stub MD. It is needed for alignment
4432 // thunk generation on the Mac and stdcall name decoration on Windows.
4433 // We do not store it directly in the interop MethodDesc here because due
4434 // to sharing we come here only for the first call with given signature and
4435 // the target MD may even be NULL.
4440 _ASSERTE(nativeStackSize >= sizeof(SLOT));
4441 nativeStackSize -= sizeof(SLOT);
4443 #else // _TARGET_X86_
4445 // The algorithm to compute nativeStackSize on the fly is x86-specific.
4446 // Recompute the correct size for other platforms from the stub signature.
4448 if (SF_IsForwardStub(dwStubFlags))
4450 // It would be nice to compute the correct value for forward stubs too.
4451 // The value is only used in MarshalNative::NumParamBytes right now,
4452 // and changing what MarshalNative::NumParamBytes returns is
4453 // a potential breaking change.
4457 // native stack size is updated in code:ILStubState.SwapStubSignatures
4459 #endif // _TARGET_X86_
4461 if (!FitsInU2(nativeStackSize))
4462 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
4464 DynamicMethodDesc *pDMD = pMD->AsDynamicMethodDesc();
4466 pDMD->SetNativeStackArgSize(static_cast<WORD>(nativeStackSize));
4467 pDMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
4468 pDMD->SetStubNeedsCOMStarted(fStubNeedsCOM);
4471 // FinishEmit needs to know the native stack arg size so we call it after the number
4472 // has been set in the stub MD (code:DynamicMethodDesc.SetNativeStackArgSize)
4473 pss->FinishEmit(pMD);
4476 class NDirectStubHashBlob : public ILStubHashBlobBase
4481 WORD m_unmgdCallConv;
4482 BYTE m_nlType; // C_ASSERTS are in NDirect::CreateHashBlob
4489 BYTE m_rgbSigAndParamData[1];
4490 // (dwParamAttr, cbNativeType) // length: number of parameters
4491 // NativeTypeBlob // length: number of parameters
4492 // BYTE m_rgbSigData[]; // length: determined by sig walk
4495 // For better performance and less memory fragmentation,
4496 // I'm using structure here to avoid allocating 3 different arrays.
4501 PCCOR_SIGNATURE pvNativeType;
4504 ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams)
4506 STANDARD_VM_CONTRACT;
4508 NDirectStubHashBlob* pBlob;
4510 IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport();
4512 CQuickBytes paramInfoBytes;
4513 paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens);
4514 ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr();
4515 ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens);
4517 size_t cbNativeTypeTotal = 0;
4520 // Collect information for function parameters
4522 for (int idx = 0; idx < pParams->m_nParamTokens; idx++)
4524 mdParamDef token = pParams->m_pParamTokenArray[idx];
4525 if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token)
4527 USHORT usSequence_Ignore; // We don't need usSequence in the hash as the param array is already sorted
4528 LPCSTR szParamName_Ignore;
4529 IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, ¶mInfos[idx].dwParamAttr, &szParamName_Ignore));
4531 if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal)
4533 IfFailThrow(pInternalImport->GetFieldMarshal(token, ¶mInfos[idx].pvNativeType, ¶mInfos[idx].cbNativeType));
4534 cbNativeTypeTotal += paramInfos[idx].cbNativeType;
4539 SigPointer sigPtr = pParams->m_sig.CreateSigPointer();
4541 // note that ConvertToInternalSignature also resolves generics so different instantiations will get different
4542 // hash blobs for methods that have generic parameters in their signature
4543 SigBuilder sigBuilder;
4544 sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE);
4547 PVOID pSig = sigBuilder.GetSignature(&cbSig);
4550 // Build hash blob for IL stub sharing
4552 S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) +
4553 S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) + // Parameter attributes
4554 S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) + // Native type blob size
4555 S_SIZE_T(cbNativeTypeTotal) + // Native type blob data
4556 S_SIZE_T(cbSig); // Signature
4558 if (cbSizeOfBlob.IsOverflow())
4559 COMPlusThrowHR(COR_E_OVERFLOW);
4561 static_assert_no_msg(nltMaxValue <= 0xFF);
4562 static_assert_no_msg(nlfMaxValue <= 0xFF);
4563 static_assert_no_msg(pmMaxValue <= 0xFFFF);
4565 NewArrayHolder<BYTE> pBytes = new BYTE[cbSizeOfBlob.Value()];
4566 // zero out the hash bytes to ensure all bit fields are deterministically set
4567 ZeroMemory(pBytes, cbSizeOfBlob.Value());
4568 pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes;
4570 pBlob->m_pModule = NULL;
4572 if (SF_IsNGENedStub(pParams->m_dwStubFlags))
4574 // don't share across modules if we are ngening the stub
4575 pBlob->m_pModule = pParams->m_pModule;
4578 pBlob->m_cbSizeOfBlob = cbSizeOfBlob.Value();
4579 pBlob->m_unmgdCallConv = static_cast<WORD>(pParams->m_unmgdCallConv);
4580 pBlob->m_nlType = static_cast<BYTE>(pParams->m_nlType);
4581 pBlob->m_nlFlags = static_cast<BYTE>(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub
4582 pBlob->m_iLCIDArg = pParams->m_iLCIDArg;
4584 pBlob->m_StubFlags = pParams->m_dwStubFlags;
4585 pBlob->m_nParams = pParams->m_nParamTokens;
4587 BYTE* pBlobParams = &pBlob->m_rgbSigAndParamData[0];
4590 // Write (dwParamAttr, cbNativeType) for parameters
4592 // Note that these need to be aligned and it is why they are written before the byte blobs
4593 // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs
4595 _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0);
4596 _ASSERTE(sizeof(DWORD) == sizeof(ULONG));
4598 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4600 // We only care about In/Out/HasFieldMarshal
4601 // Other attr are about optional/default values which are not used in marshalling,
4602 // but only used in compilers
4603 *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal);
4604 pBlobParams += sizeof(DWORD);
4606 *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType;
4607 pBlobParams += sizeof(ULONG);
4611 // Write native type blob for parameters
4613 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4615 memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType);
4616 pBlobParams += paramInfos[i].cbNativeType;
4622 memcpy(pBlobParams, pSig, cbSig);
4624 // Verify that we indeed have reached the end
4625 _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value());
4627 pBytes.SuppressRelease();
4628 return (ILStubHashBlob*)pBlob;
4632 ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams)
4642 // Use the m_pLoaderModule instead of m_pModule
4643 // They could be different for methods on generic types.
4644 return pParams->m_pLoaderModule->GetILStubCache();
4648 MethodDesc* NDirect::GetStubMethodDesc(
4649 MethodDesc *pTargetMD,
4650 NDirectStubParameters* pParams,
4651 ILStubHashBlob* pHashParams,
4652 AllocMemTracker* pamTracker,
4653 bool& bILStubCreator,
4654 MethodDesc* pLastMD)
4656 CONTRACT(MethodDesc*)
4660 PRECONDITION(CheckPointer(pParams));
4661 PRECONDITION(!pParams->m_sig.IsEmpty());
4662 PRECONDITION(CheckPointer(pParams->m_pModule));
4663 PRECONDITION(CheckPointer(pTargetMD, NULL_OK));
4664 POSTCONDITION(CheckPointer(RETVAL));
4670 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4672 pMD = pCache->GetStubMethodDesc(pTargetMD,
4674 pParams->m_dwStubFlags,
4676 pParams->m_sig.GetRawSig(),
4677 pParams->m_sig.GetRawSigLen(),
4687 void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams)
4693 PRECONDITION(CheckPointer(pParams));
4694 PRECONDITION(CheckPointer(pHashParams));
4695 PRECONDITION(!pParams->m_sig.IsEmpty());
4696 PRECONDITION(CheckPointer(pParams->m_pModule));
4700 LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams));
4702 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4704 pCache->DeleteEntry(pHashParams);
4708 void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD)
4714 PRECONDITION(CheckPointer(pParams));
4715 PRECONDITION(!pParams->m_sig.IsEmpty());
4716 PRECONDITION(CheckPointer(pParams->m_pModule));
4720 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4722 pCache->AddMethodDescChunkWithLockTaken(pMD);
4726 // Additional factorization of CreateNDirectStub. This hoists all the metadata accesses
4727 // into one location so that we can leave CreateNDirectStubWorker to just generate the
4728 // IL. This allows us to cache a stub based on the inputs to CreateNDirectStubWorker
4729 // instead of having to generate the IL first before doing the caching.
4731 void CreateNDirectStubAccessMetadata(StubSigDesc* pSigDesc, // IN
4732 CorPinvokeMap unmgdCallConv, // IN
4733 DWORD* pdwStubFlags, // IN/OUT
4734 int* piLCIDArg, // OUT
4735 int* pNumArgs // OUT
4738 STANDARD_VM_CONTRACT;
4740 if (SF_IsCOMStub(*pdwStubFlags))
4742 _ASSERTE(0 == unmgdCallConv);
4746 if (unmgdCallConv != pmCallConvStdcall &&
4747 unmgdCallConv != pmCallConvCdecl &&
4748 unmgdCallConv != pmCallConvThiscall)
4750 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
4754 #ifdef FEATURE_COMINTEROP
4755 if (SF_IsDelegateStub(*pdwStubFlags))
4757 _ASSERTE(!SF_IsWinRTStub(*pdwStubFlags));
4758 if (pSigDesc->m_pMD->GetMethodTable()->IsProjectedFromWinRT())
4760 // We do not allow P/Invoking via WinRT delegates to better segregate WinRT
4761 // from classic interop scenarios.
4762 COMPlusThrow(kMarshalDirectiveException, IDS_EE_DELEGATEPINVOKE_WINRT);
4765 #endif // FEATURE_COMINTEROP
4767 MetaSig msig(pSigDesc->m_sig,
4768 pSigDesc->m_pModule,
4769 &pSigDesc->m_typeContext);
4771 if (SF_IsVarArgStub(*pdwStubFlags))
4772 msig.SetTreatAsVarArg();
4774 (*pNumArgs) = msig.NumFixedArgs();
4776 IMDInternalImport* pInternalImport = pSigDesc->m_pModule->GetMDImport();
4778 _ASSERTE(!SF_IsHRESULTSwapping(*pdwStubFlags));
4780 mdMethodDef md = pSigDesc->m_tkMethodDef;
4781 if (md != mdMethodDefNil)
4783 DWORD dwDescrOffset;
4785 IfFailThrow(pInternalImport->GetMethodImplProps(
4790 #ifdef FEATURE_COMINTEROP
4791 if (SF_IsWinRTStub(*pdwStubFlags))
4793 // All WinRT methods do HRESULT swapping
4794 if (IsMiPreserveSig(dwImplFlags))
4796 COMPlusThrow(kMarshalDirectiveException, IDS_EE_PRESERVESIG_WINRT);
4799 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4802 #endif // FEATURE_COMINTEROP
4803 if (SF_IsReverseStub(*pdwStubFlags))
4805 // only COM-to-CLR call supports hresult swapping in the reverse direction
4806 if (SF_IsCOMStub(*pdwStubFlags) && !IsMiPreserveSig(dwImplFlags))
4808 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4813 // fwd pinvoke, fwd com interop support hresult swapping.
4814 // delegate to an unmanaged method does not.
4815 if (!IsMiPreserveSig(dwImplFlags) && !SF_IsDelegateStub(*pdwStubFlags))
4817 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4822 if (pSigDesc->m_pMD != NULL)
4824 (*piLCIDArg) = GetLCIDParameterIndex(pSigDesc->m_pMD);
4831 // Check to see if we need to do LCID conversion.
4832 if ((*piLCIDArg) != -1 && (*piLCIDArg) > (*pNumArgs))
4834 COMPlusThrow(kIndexOutOfRangeException, IDS_EE_INVALIDLCIDPARAM);
4837 if (SF_IsCOMStub(*pdwStubFlags) && !SF_IsWinRTStaticStub(*pdwStubFlags))
4839 CONSISTENCY_CHECK(msig.HasThis());
4843 if (msig.HasThis() && !SF_IsDelegateStub(*pdwStubFlags))
4845 COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC);
4850 void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError /*= TRUE*/)
4852 if (pNMD->IsSynchronized() && throwOnError)
4853 COMPlusThrow(kTypeLoadException, IDS_EE_NOSYNCHRONIZED);
4855 WORD ndirectflags = 0;
4856 if (pNMD->MethodDesc::IsVarArg())
4857 ndirectflags |= NDirectMethodDesc::kVarArgs;
4859 LPCUTF8 szLibName = NULL, szEntryPointName = NULL;
4860 new (pSigInfo) PInvokeStaticSigInfo(pNMD, &szLibName, &szEntryPointName,
4861 (throwOnError ? PInvokeStaticSigInfo::THROW_ON_ERROR : PInvokeStaticSigInfo::NO_THROW_ON_ERROR));
4863 if (pSigInfo->GetCharSet() == nltAnsi)
4864 ndirectflags |= NDirectMethodDesc::kNativeAnsi;
4866 CorNativeLinkFlags linkflags = pSigInfo->GetLinkFlags();
4867 if (linkflags & nlfLastError)
4868 ndirectflags |= NDirectMethodDesc::kLastError;
4869 if (linkflags & nlfNoMangle)
4870 ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
4872 CorPinvokeMap callConv = pSigInfo->GetCallConv();
4873 if (callConv == pmCallConvStdcall)
4874 ndirectflags |= NDirectMethodDesc::kStdCall;
4875 if (callConv == pmCallConvThiscall)
4876 ndirectflags |= NDirectMethodDesc::kThisCall;
4878 if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
4880 ndirectflags |= NDirectMethodDesc::kIsQCall;
4884 EnsureWritablePages(&pNMD->ndirect);
4885 pNMD->ndirect.m_pszLibName = szLibName;
4886 pNMD->ndirect.m_pszEntrypointName = szEntryPointName;
4890 if (ndirectflags & NDirectMethodDesc::kStdCall)
4892 // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling.
4894 ArgIterator argit(&msig);
4895 if (argit.HasRetBuffArg())
4897 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4898 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4900 ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf;
4904 #endif // _TARGET_X86_
4906 // Call this exactly ONCE per thread. Do not publish incomplete prestub flags
4907 // or you will introduce a race condition.
4908 pNMD->InterlockedSetNDirectFlags(ndirectflags);
4911 #ifdef FEATURE_COMINTEROP
4912 // Find the MethodDesc of the predefined IL stub method by either
4913 // 1) looking at redirected adapter interfaces, OR
4914 // 2) looking at special attributes for the specific interop scenario (specified by dwStubFlags).
4915 // Currently only ManagedToNativeComInteropStubAttribute is supported.
4916 // It returns NULL if no such attribute(s) can be found.
4917 // But if the attribute is found and is invalid, or something went wrong in the looking up
4918 // process, a exception will be thrown. If everything goes well, you'll get the MethodDesc
4919 // of the stub method
4920 HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD)
4927 PRECONDITION(CheckPointer(pTargetMD));
4928 PRECONDITION(CheckPointer(ppRetStubMD));
4929 PRECONDITION(*ppRetStubMD == NULL);
4935 MethodTable *pTargetMT = pTargetMD->GetMethodTable();
4937 // Check if this is a redirected interface - we have static stubs in mscorlib for those.
4938 if (SF_IsForwardCOMStub(dwStubFlags) && pTargetMT->IsInterface())
4941 // Redirect generic redirected interfaces to the corresponding adapter methods in mscorlib
4942 if (pTargetMT->HasInstantiation())
4944 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(pTargetMD, TypeHandle::Interop_ManagedToNative);
4945 if (pAdapterMD != NULL)
4947 *ppRetStubMD = pAdapterMD;
4954 // Find out if we have the attribute
4959 // Support v-table forward classic COM interop calls only
4960 if (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags) && !SF_IsWinRTStub(dwStubFlags))
4962 if (pTargetMT->HasInstantiation())
4964 // ManagedToNativeComInteropStubAttribute is not supported with generics
4968 if (pTargetMD->IsFCall())
4970 // ManagedToNativeComInteropStubAttribute is not supported on FCalls (i.e. methods on legacy
4971 // interfaces forwarded to CustomMarshalers.dll such as IEnumerable::GetEnumerator)
4974 _ASSERTE(pTargetMD->IsComPlusCall());
4976 if (pTargetMD->IsInterface())
4978 _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
4979 hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
4980 pTargetMD->GetMemberDef(),
4981 FORWARD_INTEROP_STUB_METHOD_TYPE,
4987 // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
4988 // Translate that to E_FAIL
4989 else if (hr == S_FALSE)
4994 // We are dealing with the class, use the interface MD instead
4995 // After second thought I believe we don't need to check the class MD.
4996 // We can think stubs as part of public interface, and if the interface is public,
4997 // the stubs should also be accessible
4998 MethodDesc *pInterfaceMD = pTargetMD->GetInterfaceMD();
5001 hr = FindPredefinedILStubMethod(pInterfaceMD, dwStubFlags, ppRetStubMD);
5012 // Parse the attribute
5014 CustomAttributeParser parser(pBytes, cbBytes);
5015 IfFailRet(parser.SkipProlog());
5019 IfFailRet(parser.GetNonEmptyString(&pTypeName, &cbTypeName));
5021 LPCUTF8 pMethodName;
5023 IfFailRet(parser.GetNonEmptyString(&pMethodName, &cbMethodName));
5025 StackSString typeName(SString::Utf8, pTypeName, cbTypeName);
5026 StackSString methodName(SString::Utf8, pMethodName, cbMethodName);
5029 // Retrieve the type
5031 TypeHandle stubClassType;
5032 stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
5034 MethodTable *pStubClassMT = stubClassType.AsMethodTable();
5036 StackSString stubClassName;
5037 pStubClassMT->_GetFullyQualifiedNameForClassNestedAware(stubClassName);
5039 StackSString targetInterfaceName;
5040 pTargetMT->_GetFullyQualifiedNameForClassNestedAware(targetInterfaceName);
5042 // Restrict to same assembly only to reduce test cost
5043 if (stubClassType.GetAssembly() != pTargetMT->GetAssembly())
5047 IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY,
5048 stubClassName.GetUnicode(),
5049 targetInterfaceName.GetUnicode()
5053 if (stubClassType.HasInstantiation())
5057 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC,
5058 stubClassName.GetUnicode()
5062 if (stubClassType.IsInterface())
5066 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE,
5067 stubClassName.GetUnicode()
5072 // Locate the MethodDesc for the stub method
5074 MethodDesc *pStubMD = NULL;
5077 PCCOR_SIGNATURE pTargetSig = NULL;
5078 DWORD pcTargetSig = 0;
5080 SigTypeContext typeContext; // NO generics supported
5082 pTargetMD->GetSig(&pTargetSig, &pcTargetSig);
5084 MetaSig msig(pTargetSig,
5086 pTargetMD->GetModule(),
5088 _ASSERTE(msig.HasThis());
5090 SigBuilder stubSigBuilder;
5093 // Append calling Convention, NumOfArgs + 1,
5095 stubSigBuilder.AppendByte(msig.GetCallingConvention() & ~IMAGE_CEE_CS_CALLCONV_HASTHIS);
5096 stubSigBuilder.AppendData(msig.NumFixedArgs() + 1);
5099 // Append return type
5101 SigPointer pReturn = msig.GetReturnProps();
5102 LPBYTE pReturnTypeBegin = (LPBYTE)pReturn.GetPtr();
5103 IfFailThrow(pReturn.SkipExactlyOne());
5104 LPBYTE pReturnTypeEnd = (LPBYTE)pReturn.GetPtr();
5106 stubSigBuilder.AppendBlob(pReturnTypeBegin, pReturnTypeEnd - pReturnTypeBegin);
5111 stubSigBuilder.AppendElementType(ELEMENT_TYPE_CLASS);
5112 stubSigBuilder.AppendToken(pTargetMT->GetCl());
5115 // Copy rest of the arguments
5117 if (msig.NextArg() != ELEMENT_TYPE_END)
5119 SigPointer pFirstArg = msig.GetArgProps();
5120 LPBYTE pArgBegin = (LPBYTE) pFirstArg.GetPtr();
5121 LPBYTE pArgEnd = (LPBYTE) pTargetSig + pcTargetSig;
5123 stubSigBuilder.AppendBlob(pArgBegin, pArgEnd - pArgBegin);
5127 // Allocate new memory and copy over
5129 DWORD pcStubSig = 0;
5130 PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE) stubSigBuilder.GetSignature(&pcStubSig);
5133 // Find method using name + signature
5135 StackScratchBuffer buffer;
5136 LPCUTF8 szMethodNameUTF8 = methodName.GetUTF8(buffer);
5137 pStubMD = MemberLoader::FindMethod(stubClassType.GetMethodTable(),
5141 pTargetMT->GetModule());
5143 if (pStubMD == NULL)
5152 pTargetMD->GetMDImport(),
5155 // Unfortunately the PrettyPrintSig doesn't print 'static' when the function is static
5156 // so we need to append 'static' here. No need to localize
5157 SString signature(SString::Utf8, (LPCUTF8)"static ");
5158 signature.AppendUTF8((LPCUTF8) qbSig.Ptr());
5161 kMissingMethodException,
5162 IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING,
5163 signature.GetUnicode(),
5164 stubClassName.GetUnicode()
5171 // Check the Stub MD
5174 // Verify that the target interop method can call the stub method
5176 _ASSERTE(pTargetMD != NULL);
5178 StaticAccessCheckContext accessContext(pTargetMD, pTargetMT);
5180 if (!ClassLoader::CanAccess(
5183 stubClassType.GetAssembly(),
5184 pStubMD->GetAttrs(),
5188 StackSString interopMethodName(SString::Utf8, pTargetMD->GetName());
5191 kMethodAccessException,
5192 IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD,
5193 interopMethodName.GetUnicode(),
5194 methodName.GetUnicode()
5198 // The FindMethod call will make sure that it is static by matching signature.
5199 // So there is no need to check and throw
5200 _ASSERTE(pStubMD->IsStatic());
5202 *ppRetStubMD = pStubMD;
5206 #endif // FEATURE_COMINTEROP
5208 MethodDesc* CreateInteropILStub(
5210 StubSigDesc* pSigDesc,
5211 CorNativeLinkType nlType,
5212 CorNativeLinkFlags nlFlags,
5213 CorPinvokeMap unmgdCallConv,
5214 DWORD dwStubFlags, // NDirectStubFlags
5216 mdParamDef* pParamTokenArray,
5220 CONTRACT(MethodDesc*)
5224 PRECONDITION(CheckPointer(pSigDesc));
5225 POSTCONDITION(CheckPointer(RETVAL));
5230 ///////////////////////////////
5232 // MethodDesc creation
5234 ///////////////////////////////
5236 MethodDesc* pStubMD = NULL;
5238 Module* pModule = pSigDesc->m_pModule;
5239 Module* pLoaderModule = pSigDesc->m_pLoaderModule;
5240 MethodDesc* pTargetMD = pSigDesc->m_pMD;
5242 // pTargetMD may be null in the case of calli pinvoke
5243 // and vararg pinvoke.
5246 #ifdef FEATURE_COMINTEROP
5248 // Try to locate predefined IL stub either defined in user code or hardcoded in CLR
5249 // If there is one, use the pointed method as the stub.
5250 // Skip pTargetMD == NULL case for reverse interop calls
5252 if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD)))
5254 #ifndef CROSSGEN_COMPILE
5255 // We are about to execute method in pStubMD which could be in another module.
5256 // Call EnsureActive before make the call
5257 // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here
5258 pStubMD->EnsureActive();
5260 if (pStubMD->IsPreImplemented())
5261 RestoreNGENedStub(pStubMD);
5266 #endif // FEATURE_COMINTEROP
5268 // Otherwise, fall back to generating IL stub on-the-fly
5269 NDirectStubParameters params(pSigDesc->m_sig,
5270 &pSigDesc->m_typeContext,
5282 // The following two ILStubCreatorHelperHolder are to recover the status when an
5283 // exception happen during the generation of the IL stubs. We need to free the
5284 // memory allocated and restore the ILStubCache.
5286 // The following block is logically divided into two phases. The first phase is
5287 // CreateOrGet IL Stub phase which we take a domain level lock. The second phase
5288 // is IL generation phase which we take a MethodDesc level lock. Taking two locks
5289 // is mainly designed for performance.
5291 // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
5292 // allocated memory during the creation of MethodDesc so that we are able to remove
5293 // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
5295 // When removing IL Stub from Cache, we have a constraint that only the thread which
5296 // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
5297 // remove it from cache if OOM occurs
5300 ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, ¶ms);
5302 // take the domain level lock
5303 ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock());
5306 // The holder will free the allocated MethodDesc and restore the ILStubCache
5307 // if exception happen.
5308 ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper);
5309 pStubMD = pCreateOrGetStubHolder->GetStubMD();
5311 ///////////////////////////////
5315 ///////////////////////////////
5318 // take the MethodDesc level locker
5319 ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5321 ListLockEntryLockHolder pEntryLock(pEntry, FALSE);
5323 // We can release the holder for the first phase now
5324 pCreateOrGetStubHolder.SuppressRelease();
5327 // The holder will free the allocated MethodDesc and restore the ILStubCache
5328 // if exception happen. The reason to get the holder again is to
5329 ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper);
5331 if (!pEntryLock.DeadlockAwareAcquire())
5333 // the IL generation is not recursive!
5334 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5337 if (SF_IsSharedStub(params.m_dwStubFlags))
5339 // Assure that pStubMD we have now has not been destroyed by other threads
5340 pGenILHolder->GetStubMethodDesc();
5342 while (pStubMD != pGenILHolder->GetStubMD())
5344 pStubMD = pGenILHolder->GetStubMD();
5346 pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5347 pEntryLock.Assign(pEntry, FALSE);
5349 if (!pEntryLock.DeadlockAwareAcquire())
5351 // the IL generation is not recursive!
5352 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5355 pGenILHolder->GetStubMethodDesc();
5361 // We have the entry lock now, we can release the global lock
5362 pILStubLock.Release();
5364 if (pEntry->m_hrResultCode != S_FALSE)
5366 // We came in to generate the IL but someone
5367 // beat us so there's nothing to do
5371 ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
5373 CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc()));
5375 if (pResolver->IsILGenerated())
5377 // this stub already has its IL generated
5382 // Check that the stub signature and MethodDesc are compatible. The JIT
5383 // interface functions depend on this.
5387 SigPointer ptr = pSigDesc->m_sig.CreateSigPointer();
5390 IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo));
5392 BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS);
5394 // CreateNDirectStubWorker will throw an exception for these cases.
5395 BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags);
5397 if (fSigIsStatic || fCanHaveThis)
5399 CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic);
5404 ILStubGenHolder sgh(pResolver);
5406 pResolver->SetStubMethodDesc(pStubMD);
5407 pResolver->SetStubTargetMethodDesc(pTargetMD);
5409 CreateNDirectStubWorker(pss,
5419 pResolver->SetTokenLookupMap(pss->GetTokenLookupMap());
5421 pResolver->SetStubTargetMethodSig(
5422 pss->GetStubTargetMethodSig(),
5423 pss->GetStubTargetMethodSigLength());
5425 // we successfully generated the IL stub
5426 sgh.SuppressRelease();
5429 pEntry->m_hrResultCode = S_OK;
5433 // Link the MethodDesc onto the method table with the lock taken
5434 NDirect::AddMethodDescChunkWithLockTaken(¶ms, pStubMD);
5436 pGenILHolder.SuppressRelease();
5440 ilStubCreatorHelper.SuppressRelease();
5443 #if defined(_TARGET_X86_)
5444 if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg())
5446 // copy the stack arg byte count from the stub MD to the target MD - this number is computed
5447 // during stub generation and is copied to all target MDs that share the stub
5448 // (we don't set it for varargs - the number is call site specific)
5449 // also copy the "takes parameters with copy constructors" flag which is needed to generate
5450 // appropriate intercept stub
5452 WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
5453 BOOL fHasCopyCtorArgs = pStubMD->AsDynamicMethodDesc()->HasCopyCtorArgs();
5455 if (pTargetMD->IsNDirect())
5457 NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
5459 pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
5460 pTargetNMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5462 #ifdef FEATURE_COMINTEROP
5465 if (SF_IsCOMStub(dwStubFlags))
5467 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD);
5469 if (pComInfo != NULL)
5471 pComInfo->SetStackArgumentSize(cbStackArgSize);
5472 pComInfo->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5476 #endif // FEATURE_COMINTEROP
5478 #endif // defined(_TARGET_X86_)
5483 MethodDesc* NDirect::CreateCLRToNativeILStub(
5484 StubSigDesc* pSigDesc,
5485 CorNativeLinkType nlType,
5486 CorNativeLinkFlags nlFlags,
5487 CorPinvokeMap unmgdCallConv,
5488 DWORD dwStubFlags) // NDirectStubFlags
5490 CONTRACT(MethodDesc*)
5494 PRECONDITION(CheckPointer(pSigDesc));
5495 POSTCONDITION(CheckPointer(RETVAL));
5501 int numParamTokens = 0;
5502 mdParamDef* pParamTokenArray = NULL;
5504 CreateNDirectStubAccessMetadata(pSigDesc,
5510 Module *pModule = pSigDesc->m_pModule;
5511 numParamTokens = numArgs + 1;
5512 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5513 CollateParamTokens(pModule->GetMDImport(), pSigDesc->m_tkMethodDef, numArgs, pParamTokenArray);
5515 // for interop vectors that have declarative security, we need
5516 // to update the stub flags to ensure a unique stub hash
5517 // is generated based on the marshalling signature AND
5518 // any declarative security.
5519 // IMPORTANT: This will only inject the security callouts for
5520 // interop functionality which has a non-null target MethodDesc.
5521 // Currently, this is known to exclude things like native
5522 // function ptrs. It is assumed that if the target is not
5523 // attribute'able for metadata, then it cannot have declarative
5524 // security - and that the target is not attributable if it was
5525 // not passed to this function.
5526 MethodDesc *pMD = pSigDesc->m_pMD;
5527 if (pMD != NULL && SF_IsForwardStub(dwStubFlags))
5529 // In an AppX process there is only one fully trusted AppDomain, so there is never any need to insert
5530 // a security callout on the stubs.
5531 if (!AppX::IsAppXProcess())
5533 #ifdef FEATURE_COMINTEROP
5534 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5536 // To preserve Whidbey behavior, we only enforce the implicit demand for
5537 // unmanaged code permission.
5538 MethodTable* pMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
5539 if (pMT->ClassRequiresUnmanagedCodeCheck() &&
5540 !pMD->HasSuppressUnmanagedCodeAccessAttr())
5542 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5546 #endif // FEATURE_COMPINTEROP
5547 if (pMD->IsInterceptedForDeclSecurity())
5549 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5554 NewHolder<ILStubState> pStubState;
5556 #ifdef FEATURE_COMINTEROP
5557 if (SF_IsCOMStub(dwStubFlags))
5559 if (SF_IsReverseStub(dwStubFlags))
5561 pStubState = new COMToCLR_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5565 pStubState = new CLRToCOM_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5571 pStubState = new PInvoke_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, pMD);
5574 MethodDesc* pStubMD;
5575 pStubMD = CreateInteropILStub(
5591 #ifdef FEATURE_COMINTEROP
5592 MethodDesc* NDirect::CreateFieldAccessILStub(
5593 PCCOR_SIGNATURE szMetaSig,
5594 DWORD cbMetaSigSize,
5597 DWORD dwStubFlags, // NDirectStubFlags
5600 CONTRACT(MethodDesc*)
5604 PRECONDITION(CheckPointer(szMetaSig));
5605 PRECONDITION(CheckPointer(pModule));
5606 PRECONDITION(CheckPointer(pFD, NULL_OK));
5607 PRECONDITION(SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags));
5608 POSTCONDITION(CheckPointer(RETVAL));
5612 int numArgs = (SF_IsFieldSetterStub(dwStubFlags) ? 1 : 0);
5613 int numParamTokens = numArgs + 1;
5615 // make sure we capture marshaling metadata
5616 mdParamDef* pParamTokenArray = (mdParamDef *)_alloca(numParamTokens * sizeof(mdParamDef));
5617 pParamTokenArray[0] = mdParamDefNil;
5618 pParamTokenArray[numArgs] = (mdParamDef)fd;
5620 // fields are never preserve-sig
5621 dwStubFlags |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
5623 // convert field signature to getter/setter signature
5624 SigBuilder sigBuilder;
5626 sigBuilder.AppendData(IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS);
5627 sigBuilder.AppendData(numArgs);
5629 if (SF_IsFieldSetterStub(dwStubFlags))
5631 // managed setter returns void
5632 sigBuilder.AppendElementType(ELEMENT_TYPE_VOID);
5635 CONSISTENCY_CHECK(*szMetaSig == IMAGE_CEE_CS_CALLCONV_FIELD);
5637 sigBuilder.AppendBlob((const PVOID)(szMetaSig + 1), cbMetaSigSize - 1);
5638 szMetaSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbMetaSigSize);
5640 StubSigDesc sigDesc(NULL, Signature(szMetaSig, cbMetaSigSize), pModule);
5643 sigDesc.m_pDebugName = pFD->GetDebugName();
5644 sigDesc.m_pDebugClassName = pFD->GetEnclosingMethodTable()->GetDebugClassName();
5647 Signature signature(szMetaSig, cbMetaSigSize);
5648 NewHolder<ILStubState> pStubState = new COMToCLRFieldAccess_ILStubState(pModule, signature, &sigDesc.m_typeContext, dwStubFlags, pFD);
5650 MethodDesc* pStubMD;
5651 pStubMD = CreateInteropILStub(
5654 (CorNativeLinkType)0,
5655 (CorNativeLinkFlags)0,
5664 #endif // FEATURE_COMINTEROP
5666 MethodDesc* NDirect::CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
5670 STANDARD_VM_CONTRACT;
5672 StubSigDesc sigDesc(pMD, pSigInfo);
5674 if (SF_IsWinRTDelegateStub(dwStubFlags))
5676 _ASSERTE(pMD->IsEEImpl());
5678 return CreateCLRToNativeILStub(&sigDesc,
5679 (CorNativeLinkType)0,
5680 (CorNativeLinkFlags)0,
5682 (pSigInfo->GetStubFlags() | dwStubFlags) & ~NDIRECTSTUB_FL_DELEGATE);
5686 return CreateCLRToNativeILStub(&sigDesc,
5687 pSigInfo->GetCharSet(),
5688 pSigInfo->GetLinkFlags(),
5689 pSigInfo->GetCallConv(),
5690 pSigInfo->GetStubFlags() | dwStubFlags);
5694 MethodDesc* NDirect::GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags)
5696 STANDARD_VM_CONTRACT;
5698 MethodDesc* pStubMD = NULL;
5700 if (!pNMD->IsVarArgs() || SF_IsForNumParamBytes(dwStubFlags))
5702 if (pNMD->IsClassConstructorTriggeredByILStub())
5704 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
5707 pStubMD = CreateCLRToNativeILStub(
5709 dwStubFlags & ~NDIRECTSTUB_FL_FOR_NUMPARAMBYTES,
5716 MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
5718 STANDARD_VM_CONTRACT;
5720 BOOL fGcMdaEnabled = FALSE;
5721 #ifdef MDA_SUPPORTED
5722 if (MDA_GET_ASSISTANT(GcManagedToUnmanaged) || MDA_GET_ASSISTANT(GcUnmanagedToManaged))
5724 // We never generate checks for these MDAs to NGEN'ed stubs so if they are
5725 // enabled, a new stub must be generated (the perf impact is huge anyway).
5726 fGcMdaEnabled = TRUE;
5728 #endif // MDA_SUPPORTED
5730 #ifdef FEATURE_COMINTEROP
5731 if (SF_IsReverseCOMStub(dwStubFlags))
5736 // reverse COM stubs live in a hash table
5737 StubMethodHashTable *pHash = pMD->GetLoaderModule()->GetStubMethodHashTable();
5738 return (pHash == NULL ? NULL : pHash->FindMethodDesc(pMD));
5741 #endif // FEATURE_COMINTEROP
5742 if (pMD->IsNDirect())
5744 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5745 return ((fGcMdaEnabled && !pNMD->IsQCall()) ? NULL : pNMD->ndirect.m_pStubMD.GetValueMaybeNull());
5747 #ifdef FEATURE_COMINTEROP
5748 else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5750 #ifdef MDA_SUPPORTED
5751 if (MDA_GET_ASSISTANT(RaceOnRCWCleanup))
5753 // we never generate this callout to NGEN'ed stubs
5756 #endif // MDA_SUPPORTED
5758 if (NDirect::IsHostHookEnabled())
5760 MethodTable *pMT = pMD->GetMethodTable();
5761 if (pMT->IsProjectedFromWinRT() || pMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative))
5763 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5764 // must be rejected if we are hosted.
5772 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
5773 return (pComInfo == NULL ? NULL : pComInfo->m_pStubMD.GetValueMaybeNull());
5775 #endif // FEATURE_COMINTEROP
5776 else if (pMD->IsEEImpl())
5781 DelegateEEClass *pClass = (DelegateEEClass *)pMD->GetClass();
5782 if (SF_IsReverseStub(dwStubFlags))
5784 return pClass->m_pReverseStubMD;
5788 #ifdef FEATURE_COMINTEROP
5789 if (SF_IsWinRTDelegateStub(dwStubFlags))
5791 if (NDirect::IsHostHookEnabled() && pMD->GetMethodTable()->IsProjectedFromWinRT())
5793 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5794 // must be rejected if we are hosted.
5798 return pClass->m_pComPlusCallInfo->m_pStubMD.GetValueMaybeNull();
5801 #endif // FEATURE_COMINTEROP
5803 return pClass->m_pForwardStubMD;
5807 else if (pMD->IsIL())
5809 // these are currently only created at runtime, not at NGEN time
5814 UNREACHABLE_MSG("unexpected type of MethodDesc");
5818 #ifndef CROSSGEN_COMPILE
5820 PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5826 PRECONDITION(CheckPointer(pManagedMD));
5827 POSTCONDITION(RETVAL != NULL);
5831 // pStubMD, if provided, must be preimplemented.
5832 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5834 if (NULL == *ppStubMD)
5836 PInvokeStaticSigInfo sigInfo(pManagedMD);
5837 *ppStubMD = NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pManagedMD);
5840 RETURN JitILStub(*ppStubMD);
5843 PCODE NDirect::GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5845 STANDARD_VM_CONTRACT;
5849 // pStubMD, if provided, must be preimplemented.
5850 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5852 if (NULL == *ppStubMD)
5854 PInvokeStaticSigInfo sigInfo;
5855 NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo, /* throwOnError = */ !SF_IsForNumParamBytes(dwStubFlags));
5857 *ppStubMD = NDirect::GetILStubMethodDesc(pNMD, &sigInfo, dwStubFlags);
5860 if (SF_IsForNumParamBytes(dwStubFlags))
5865 pStub = JitILStub(*ppStubMD);
5869 CONSISTENCY_CHECK(pNMD->IsVarArgs());
5872 // varargs goes through vararg NDirect stub
5874 pStub = TheVarargNDirectStub(pNMD->HasRetBuffArg());
5877 #ifdef FEATURE_MIXEDMODE // IJW
5878 if (pNMD->IsEarlyBound())
5880 pNMD->InitEarlyBoundNDirectTarget();
5889 // NOTE: there is a race in updating this MethodDesc. We depend on all
5890 // threads getting back the same DynamicMethodDesc for a particular
5891 // NDirectMethodDesc, in that case, the locking around the actual JIT
5892 // operation will prevent the code from being jitted more than once.
5893 // By the time we get here, all threads get the same address of code
5894 // back from the JIT operation and they all just fill in the same value
5897 // In the NGEN case, all threads will get the same preimplemented code
5898 // address much like the JIT case.
5904 PCODE JitILStub(MethodDesc* pStubMD)
5906 STANDARD_VM_CONTRACT;
5908 PCODE pCode = pStubMD->GetNativeCode();
5912 ///////////////////////////////
5916 ///////////////////////////////
5919 if (pStubMD->IsDynamicMethod())
5922 // A dynamically generated IL stub
5925 DWORD dwFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
5926 pCode = pStubMD->MakeJitWorker(NULL, dwFlags, 0);
5928 _ASSERTE(pCode == pStubMD->GetNativeCode());
5933 // A static IL stub that is pointing to a static method in user assembly
5934 // Compile it and return the native code
5937 // This returns the stable entry point
5938 pCode = pStubMD->DoPrestub(NULL);
5940 _ASSERTE(pCode == pStubMD->GetStableEntryPoint());
5944 if (!pStubMD->IsDynamicMethod())
5946 // We need an entry point that can be called multiple times
5947 pCode = pStubMD->GetMultiCallableAddrOfCode();
5953 MethodDesc* RestoreNGENedStub(MethodDesc* pStubMD)
5958 PRECONDITION(CheckPointer(pStubMD));
5962 #ifdef FEATURE_PREJIT
5963 pStubMD->CheckRestore();
5965 PCODE pCode = pStubMD->GetPreImplementedCode();
5968 TADDR pFixupList = pStubMD->GetFixupList();
5969 if (pFixupList != NULL)
5971 Module* pZapModule = pStubMD->GetZapModule();
5972 _ASSERTE(pZapModule != NULL);
5973 if (!pZapModule->FixupDelayList(pFixupList))
5975 _ASSERTE(!"FixupDelayList failed");
5976 ThrowHR(COR_E_BADIMAGEFORMAT);
5980 #if defined(HAVE_GCCOVER)
5981 if (GCStress<cfg_instr_ngen>::IsEnabled())
5982 SetupGcCoverage(pStubMD, (BYTE*) pCode);
5983 #endif // HAVE_GCCOVER
5988 // We only pass a non-NULL pStubMD to GetStubForILStub() below if pStubMD is preimplemeneted.
5991 #endif // FEATURE_PREJIT
5996 PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags, MethodDesc **ppStubMD)
6002 PRECONDITION(CheckPointer(pMD));
6003 PRECONDITION(pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl() || pMD->IsIL());
6008 MethodDesc* pStubMD = NULL;
6010 pStubMD = GetStubMethodDescFromInteropMethodDesc(pMD, dwStubFlags);
6011 if (pStubMD != NULL)
6013 pStubMD = RestoreNGENedStub(pStubMD);
6016 if ((NULL == pStubMD) && (SF_IsNGENedStub(dwStubFlags)))
6018 // Return NULL -- the caller asked only for an ngened stub and
6019 // one does not exist, so don't do any more work.
6020 CONSISTENCY_CHECK(pStub == NULL);
6023 if (pMD->IsNDirect())
6025 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
6026 pStub = NDirect::GetStubForILStub(pNMD, &pStubMD, dwStubFlags);
6028 #ifdef FEATURE_COMINTEROP
6030 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
6032 pStub = ComPlusCall::GetStubForILStub(pMD, &pStubMD);
6034 #endif // FEATURE_COMINTEROP
6036 if (pMD->IsEEImpl())
6038 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
6039 EEImplMethodDesc* pDelegateMD = (EEImplMethodDesc*)pMD;
6040 pStub = COMDelegate::GetStubForILStub(pDelegateMD, &pStubMD, dwStubFlags);
6045 CONSISTENCY_CHECK(SF_IsReverseStub(dwStubFlags));
6046 pStub = NDirect::GetStubForILStub(pMD, &pStubMD, dwStubFlags);
6050 UNREACHABLE_MSG("unexpected MethodDesc type");
6053 if (pStubMD != NULL && pStubMD->IsILStub() && pStubMD->AsDynamicMethodDesc()->IsStubNeedsCOMStarted())
6055 // the stub uses COM so make sure that it is started
6059 if (ppStubMD != NULL)
6060 *EnsureWritablePages(ppStubMD) = pStubMD;
6065 #ifdef FEATURE_COMINTEROP
6066 void CreateCLRToDispatchCOMStub(
6068 DWORD dwStubFlags) // NDirectStubFlags
6074 PRECONDITION(CheckPointer(pMD));
6078 _ASSERTE(SF_IsCOMLateBoundStub(dwStubFlags) || SF_IsCOMEventCallStub(dwStubFlags));
6080 // If we are dealing with a COM event call, then we need to initialize the
6081 // COM event call information.
6082 if (SF_IsCOMEventCallStub(dwStubFlags))
6084 _ASSERTE(pMD->IsComPlusCall()); // no generic COM eventing
6085 ((ComPlusCallMethodDesc *)pMD)->InitComEventCallInfo();
6088 // Get the call signature information
6089 StubSigDesc sigDesc(pMD);
6093 int numParamTokens = 0;
6094 mdParamDef* pParamTokenArray = NULL;
6096 CreateNDirectStubAccessMetadata(&sigDesc,
6102 numParamTokens = numArgs + 1;
6103 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
6104 CollateParamTokens(sigDesc.m_pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray);
6106 DispatchStubState MyStubState;
6108 CreateNDirectStubWorker(&MyStubState,
6110 (CorNativeLinkType)0,
6111 (CorNativeLinkFlags)0,
6113 dwStubFlags | NDIRECTSTUB_FL_COM,
6118 _ASSERTE(pMD->IsComPlusCall()); // no generic disp-calls
6119 ((ComPlusCallMethodDesc *)pMD)->InitRetThunk();
6123 #endif // FEATURE_COMINTEROP
6126 LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod)
6128 // GetProcAddress cannot be called while preemptive GC is disabled.
6129 // It requires the OS to take the loader lock.
6133 PRECONDITION(CheckPointer(pMD));
6134 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6138 g_IBCLogger.LogNDirectCodeAccess(pMD);
6140 #ifdef MDA_SUPPORTED
6141 MDA_TRIGGER_ASSISTANT(PInvokeLog, LogPInvoke(pMD, hMod));
6144 RETURN pMD->FindEntryPoint(hMod);
6147 static BOOL AbsolutePath(LPCWSTR wszLibName)
6155 PRECONDITION(CheckPointer(wszLibName));
6159 // check for UNC or a drive
6160 WCHAR* ptr = (WCHAR*) wszLibName;
6163 // Check for UNC path
6171 if((ptr - wszLibName) == 2)
6175 // Check to see if there is a colon indicating a drive or protocal
6176 for(ptr = start; *ptr; ptr++)
6185 // We did not find a UNC/drive/protocol path
6189 VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget)
6197 PRECONDITION(IsNDirect());
6198 PRECONDITION(pTarget != NULL);
6202 Stub *pInterceptStub = NULL;
6206 // Host hooks are not supported for Mac CoreCLR.
6207 if (NDirect::IsHostHookEnabled())
6210 // we will call CallNeedsHostHook on every invocation for back compat
6213 fHook = CallNeedsHostHook((size_t)pTarget);
6217 if (g_pConfig->ShouldGenerateStubForHost())
6226 #ifndef FEATURE_CORECLR
6227 if (HasCopyCtorArgs())
6229 _ASSERTE(pInterceptStub == NULL);
6231 // static stub that gets its arguments in a thread-static field
6232 pInterceptStub = NDirect::GetStubForCopyCtor();
6234 #endif // !FEATURE_CORECLR
6236 #ifdef MDA_SUPPORTED
6237 if (!IsQCall() && MDA_GET_ASSISTANT(PInvokeStackImbalance))
6239 pInterceptStub = GenerateStubForMDA(pTarget, pInterceptStub, fHook);
6241 #endif // MDA_SUPPORTED
6243 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
6246 pInterceptStub = GenerateStubForHost(pTarget, pInterceptStub);
6248 #endif // FEATURE_INCLUDE_ALL_INTERFACES
6250 #endif // _TARGET_X86_
6253 NDirectWriteableData* pWriteableData = GetWriteableData();
6254 EnsureWritablePages(pWriteableData);
6255 g_IBCLogger.LogNDirectCodeAccess(this);
6257 if (pInterceptStub != NULL WIN64_ONLY(|| fHook))
6259 ndirect.m_pNativeNDirectTarget = pTarget;
6261 #if defined(_TARGET_X86_)
6262 pTarget = (PVOID)pInterceptStub->GetEntryPoint();
6264 LPVOID oldTarget = GetNDirectImportThunkGlue()->GetEntrypoint();
6265 if (FastInterlockCompareExchangePointer(&pWriteableData->m_pNDirectTarget, pTarget,
6266 oldTarget) != oldTarget)
6268 pInterceptStub->DecRef();
6271 _ASSERTE(pInterceptStub == NULL); // we don't intercept for anything else than host on !_TARGET_X86_
6272 pWriteableData->m_pNDirectTarget = (LPVOID)GetEEFuncEntryPoint(PInvokeStubForHost);
6277 pWriteableData->m_pNDirectTarget = pTarget;
6281 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
6283 // Returns a small stub whose purpose is to record current ESP and call code:CopyCtorCallStubWorker
6284 // to invoke copy constructors and destructors as appropriate. This stub operates on arguments
6285 // already pushed to the stack by JITted IL stub and must not create a new frame, i.e. it must
6286 // tail call to the target for it to see the arguments that copy ctors have been called on.
6288 // As a consequence, the stub doesn't take any extra secret arguments and the description of the
6289 // ctors/dtors to call is passed "out-of-band" in a thread static field. The worker returns
6290 // address of the real target (also passed out of band) which enables us to have only one static
6291 // stub in i386\asmhelpers.asm.
6294 Stub *NDirect::GetStubForCopyCtor()
6296 STANDARD_VM_CONTRACT;
6298 static Stub *s_pStub = NULL;
6300 if (s_pStub == NULL)
6302 Stub *pStub = Stub::NewStub(GetEEFuncEntryPoint(CopyCtorCallStub));
6303 if (InterlockedCompareExchangeT(&s_pStub, pStub, NULL) != NULL)
6313 #endif // _TARGET_X86_ && !FEATURE_CORECLR
6315 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
6316 BOOL NDirect::IsHostHookEnabled()
6318 WRAPPER_NO_CONTRACT;
6320 // WARNING: The non-debug portion of this logic is inlined into UMThunkStubAMD64!
6322 return CLRTaskHosted() INDEBUG(|| g_pConfig->ShouldGenerateStubForHost());
6325 EXTERN_C BOOL CallNeedsHostHook(size_t target)
6328 IHostTaskManager *pManager = CorHost2::GetHostTaskManager();
6332 BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
6333 hr = pManager->CallNeedsHostHook(target,&fHook);
6334 END_SO_TOLERANT_CODE_CALLING_HOST;
6335 _ASSERTE (hr == S_OK);
6340 if (g_pConfig->ShouldGenerateStubForHost())
6348 #endif // FEATURE_INCLUDE_ALL_INTERFACES
6350 #if defined(_TARGET_X86_) && defined(MDA_SUPPORTED)
6351 EXTERN_C VOID __stdcall PInvokeStackImbalanceWorker(StackImbalanceCookie *pSICookie, DWORD dwPostESP)
6353 STATIC_CONTRACT_THROWS;
6354 STATIC_CONTRACT_GC_TRIGGERS;
6355 STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6357 // make sure we restore the original Win32 last error before leaving this function - we are
6358 // called right after returning from the P/Invoke target and the error has not been saved yet
6359 BEGIN_PRESERVE_LAST_ERROR;
6361 MdaPInvokeStackImbalance* pProbe = MDA_GET_ASSISTANT(PInvokeStackImbalance);
6363 // This MDA must be active if we generated a call to PInvokeStackImbalanceHelper
6366 pProbe->CheckStack(pSICookie, dwPostESP);
6368 END_PRESERVE_LAST_ERROR;
6370 #endif // _TARGET_X86_ && MDA_SUPPORTED
6372 #if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR)
6373 struct CopyCtorStubCookie // same layout as StubHelpers.CopyCtorStubCookie
6375 LPVOID m_srcInstancePtr;
6376 DWORD m_dstStackOffset;
6377 LPVOID m_ctorPtr; // managed method ptr
6378 LPVOID m_dtorPtr; // managed method ptr
6380 CopyCtorStubCookie *m_pNext;
6383 struct CopyCtorStubDesc // same layout as StubHelpers.CopyCtorStubDesc
6385 CopyCtorStubCookie *m_pCookie;
6389 // Called by CopyCtorCallStub after we have already transitioned to unmanaged. Invokes copy ctor(s)
6390 // and dtor(s) using reverse P/Invoke which has some perf impact but provides all the debugging and
6391 // profiling support. An alternative solution would be CallDescr or some optimized variant of it
6392 // which would probably result in confusing call stacks.
6393 EXTERN_C LPVOID __stdcall CopyCtorCallStubWorker(BYTE *pESP)
6395 STATIC_CONTRACT_THROWS;
6396 STATIC_CONTRACT_GC_TRIGGERS;
6397 STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6399 CopyCtorStubCookie *pCookie;
6403 // get address of the thread-static field
6404 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__STUBHELPERS__COPY_CTOR_STUB_DESC);
6406 CopyCtorStubDesc *pStubDesc = (CopyCtorStubDesc *)Thread::GetStaticFieldAddress(pFD);
6408 // read the fields in cooperative mode
6409 pCookie = pStubDesc->m_pCookie;
6410 pTarget = pStubDesc->m_pTarget;
6412 _ASSERTE(pCookie != NULL && pTarget != NULL);
6414 // make sure we ASSERT/AV reliably if we are called by mistake
6415 pStubDesc->m_pCookie = NULL;
6416 pStubDesc->m_pTarget = NULL;
6419 while (pCookie != NULL)
6421 if (pCookie->m_ctorPtr != NULL)
6423 // get reverse P/Invoke to the copy ctor (cache on AD)
6424 MethodDesc *pMD = Entry2MethodDesc((PCODE)pCookie->m_ctorPtr, NULL);
6425 UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
6427 // GetUMEntryThunk always returns stdcall-able function pointers for ordinary managed methods
6428 // but the ctor can be a P/Invoke (pre-Whidbey MC++ only)
6429 typedef void (__stdcall *CtorFnPtr_StdCall) (LPVOID dst, LPVOID src);
6430 typedef void (__thiscall *CtorFnPtr_ThisCall)(LPVOID dst, LPVOID src);
6431 typedef void (__cdecl *CtorFnPtr_Cdecl) (LPVOID dst, LPVOID src);
6433 // call the copy ctor using the right calling convention
6434 UMThunkMarshInfo *pMarshInfo = pUMEntryThunk->GetUMThunkMarshInfo();
6435 pMarshInfo->RunTimeInit();
6437 switch (pMarshInfo->GetCallingConvention() & pmCallConvMask)
6439 case pmCallConvStdcall:
6440 case pmCallConvWinapi:
6442 CtorFnPtr_StdCall fnPtr = (CtorFnPtr_StdCall)pUMEntryThunk->GetCode();
6443 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6447 case pmCallConvThiscall:
6449 CtorFnPtr_ThisCall fnPtr = (CtorFnPtr_ThisCall)pUMEntryThunk->GetCode();
6450 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6456 _ASSERTE((pMarshInfo->GetCallingConvention() & pmCallConvMask) == pmCallConvCdecl);
6458 CtorFnPtr_Cdecl fnPtr = (CtorFnPtr_Cdecl)pUMEntryThunk->GetCode();
6459 fnPtr(pESP + pCookie->m_dstStackOffset, pCookie->m_srcInstancePtr);
6464 if (pCookie->m_dtorPtr != NULL)
6466 // get reverse P/Invoke to the dtor (cache on AD)
6467 MethodDesc *pMD = Entry2MethodDesc((PCODE)pCookie->m_dtorPtr, NULL);
6468 UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
6470 // GetUMEntryThunk always returns stdcall-able function pointers for ordinary managed methods
6471 // but the dtor can be a P/Invoke (pre-Whidbey MC++ only)
6472 typedef void (__stdcall *DtorFnPtr_StdCall) (LPVOID src);
6473 typedef void (__thiscall *DtorFnPtr_ThisCall)(LPVOID src);
6474 typedef void (__cdecl *DtorFnPtr_Cdecl) (LPVOID src);
6476 // call the dtor using the right calling convention
6477 UMThunkMarshInfo *pMarshInfo = pUMEntryThunk->GetUMThunkMarshInfo();
6478 pMarshInfo->RunTimeInit();
6480 switch (pMarshInfo->GetCallingConvention() & pmCallConvMask)
6482 case pmCallConvStdcall:
6483 case pmCallConvWinapi:
6485 DtorFnPtr_StdCall fnPtr = (DtorFnPtr_StdCall)pUMEntryThunk->GetCode();
6486 fnPtr(pCookie->m_srcInstancePtr);
6490 case pmCallConvThiscall:
6492 DtorFnPtr_ThisCall fnPtr = (DtorFnPtr_ThisCall)pUMEntryThunk->GetCode();
6493 fnPtr(pCookie->m_srcInstancePtr);
6499 _ASSERTE((pMarshInfo->GetCallingConvention() & pmCallConvMask) == pmCallConvCdecl);
6501 DtorFnPtr_Cdecl fnPtr = (DtorFnPtr_Cdecl)pUMEntryThunk->GetCode();
6502 fnPtr(pCookie->m_srcInstancePtr);
6507 pCookie = pCookie->m_pNext;
6512 #endif // _TARGET_X86_ && !FEATURE_CORECLR
6514 // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places
6515 // if earlier loads fail and those later loads obliterate error codes.
6517 // This tracker object will keep track of the error code in accordance to priority:
6519 // low-priority: unknown error code (should never happen)
6520 // medium-priority: dll not found
6521 // high-priority: dll found but error during loading
6523 // We will overwrite the previous load's error code only if the new error code is higher priority.
6526 class LoadLibErrorTracker
6529 static const DWORD const_priorityNotFound = 10;
6530 static const DWORD const_priorityAccessDenied = 20;
6531 static const DWORD const_priorityCouldNotLoad = 99999;
6533 LoadLibErrorTracker()
6535 LIMITED_METHOD_CONTRACT;
6537 m_priorityOfLastError = 0;
6540 VOID TrackErrorCode(DWORD dwLastError)
6542 LIMITED_METHOD_CONTRACT;
6546 switch (dwLastError)
6548 case ERROR_FILE_NOT_FOUND:
6549 case ERROR_PATH_NOT_FOUND:
6550 case ERROR_MOD_NOT_FOUND:
6551 case ERROR_DLL_NOT_FOUND:
6552 priority = const_priorityNotFound;
6555 // If we can't access a location, we can't know if the dll's there or if it's good.
6556 // Still, this is probably more unusual (and thus of more interest) than a dll-not-found
6557 // so give it an intermediate priority.
6558 case ERROR_ACCESS_DENIED:
6559 priority = const_priorityAccessDenied;
6561 // Assume all others are "dll found but couldn't load."
6563 priority = const_priorityCouldNotLoad;
6567 UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError));
6570 // Sets the error code to HRESULT as could not load DLL
6571 void TrackHR_CouldNotLoad(HRESULT hr)
6573 UpdateHR(const_priorityCouldNotLoad, hr);
6581 void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath)
6583 STANDARD_VM_CONTRACT;
6585 HRESULT theHRESULT = GetHR();
6586 if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT))
6588 COMPlusThrow(kBadImageFormatException);
6593 GetHRMsg(theHRESULT, hrString);
6594 COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, libraryNameOrPath.GetUnicode(), hrString);
6601 void UpdateHR(DWORD priority, HRESULT hr)
6603 if (priority > m_priorityOfLastError)
6606 m_priorityOfLastError = priority;
6611 DWORD m_priorityOfLastError;
6612 }; // class LoadLibErrorTracker
6615 // Local helper function for the LoadLibraryModule function below
6616 static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
6618 STANDARD_VM_CONTRACT;
6620 HMODULE hmod = NULL;
6624 if ((flags & 0xFFFFFF00) != 0
6625 #ifndef FEATURE_CORESYSTEM
6626 && NDirect::SecureLoadLibrarySupported()
6627 #endif // !FEATURE_CORESYSTEM
6630 hmod = CLRLoadLibraryEx( name, NULL, flags & 0xFFFFFF00);
6636 DWORD dwLastError = GetLastError();
6637 if (dwLastError != ERROR_INVALID_PARAMETER)
6639 pErrorTracker->TrackErrorCode(dwLastError);
6644 hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF);
6646 #else // !FEATURE_PAL
6647 hmod = CLRLoadLibrary(name);
6648 #endif // !FEATURE_PAL
6652 pErrorTracker->TrackErrorCode(GetLastError());
6658 // Local helper function for the LoadLibraryFromPath function below
6659 static HMODULE LocalLoadLibraryDirectHelper(LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6661 STANDARD_VM_CONTRACT;
6664 return LocalLoadLibraryHelper(name, flags, pErrorTracker);
6665 #else // !FEATURE_PAL
6666 // Load the library directly, and don't register it yet with PAL. The system library handle is required here, not the PAL
6667 // handle. The system library handle is registered with PAL to get a PAL handle in LoadLibraryModuleViaHost().
6668 HMODULE hmod = PAL_LoadLibraryDirect(name);
6672 pErrorTracker->TrackErrorCode(GetLastError());
6676 #endif // !FEATURE_PAL
6680 #if !defined(FEATURE_CORESYSTEM)
6682 #define NATIVE_DLL(d) L#d, L#d W(".dll")
6684 const LPCWSTR wellKnownModules[] =
6686 NATIVE_DLL(advapi32),
6688 NATIVE_DLL(gdiplus),
6689 NATIVE_DLL(kernel32),
6690 NATIVE_DLL(mscoree),
6692 NATIVE_DLL(shfolder),
6697 BOOL CompareLibNames (UPTR val1, UPTR val2)
6706 LPCWSTR wszStr1 = (LPCWSTR)(val1 << 1);
6707 LPCWSTR wszStr2 = (LPCWSTR)val2;
6709 if (SString::_wcsicmp(wszStr1, wszStr2) == 0)
6715 PtrHashMap * NDirect::s_pWellKnownNativeModules = NULL;
6716 bool NDirect::s_fSecureLoadLibrarySupported = false;
6718 HINSTANCE NDirect::CheckForWellKnownModules(LPCWSTR wszLibName, LoadLibErrorTracker *pErrorTracker)
6720 STANDARD_VM_CONTRACT;
6722 ModuleHandleHolder hMod;
6723 ULONG hash = HashiString(wszLibName);
6724 LPCWSTR wszName = NULL;
6725 wszName = (LPCWSTR) s_pWellKnownNativeModules->LookupValue((UPTR) hash, (LPVOID)wszLibName);
6727 if (wszName != (LPCWSTR)INVALIDENTRY)
6729 hMod = LocalLoadLibraryHelper(wszLibName, 0, pErrorTracker);
6732 return hMod.Extract();
6735 #endif // !FEATURE_CORESYSTEM
6737 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
6738 #define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
6740 #ifndef FEATURE_CORECLR
6742 VOID NDirect::CheckUnificationList(NDirectMethodDesc * pMD, DWORD * pDllImportSearchPathFlag, BOOL * pSearchAssemblyDirectory)
6752 // If neither assembly and method have the attribute, check the unification list.
6753 Assembly *pAssembly = pMD->GetAssembly();
6755 if (!pAssembly->IsStrongNamed())
6758 const char * simpleName = pAssembly->GetSimpleName();
6760 StringHashIterator(it, g_arFxPolicy, simpleName);
6764 while ((pos = it.GetNext()) >= 0)
6766 const FrameworkConfig & config = g_arFxPolicy[pos];
6768 FixedSizeString<char> asmName;
6770 config.GetFxAssemblyName(asmName);
6772 if (_stricmp(asmName, simpleName) == 0)
6774 DWORD cbPublicKey = 0;
6775 const void *pbPublicKey = NULL;
6776 pbPublicKey = pAssembly->GetPublicKey(&cbPublicKey);
6779 // StrongNameTokenFromPublicKey is potentially expensive operation. Do it only once we got a match on the simple name.
6781 StrongNameBufferHolder<BYTE> pbStrongNameToken;
6782 DWORD cbStrongNameToken;
6784 if (StrongNameTokenFromPublicKey((BYTE*) pbPublicKey,cbPublicKey,&pbStrongNameToken,&cbStrongNameToken))
6786 BOOL pktIsEqual = TRUE;
6788 LPCWSTR pwzPKT = config.GetPKT();
6790 for (UINT j = 0; j < cbStrongNameToken; j++)
6792 WCHAR firstChar = TOHEX(pbStrongNameToken[j] / 16);
6793 WCHAR secondChar = TOHEX(pbStrongNameToken[j] % 16);
6795 if (firstChar != TOLOWER(pwzPKT[j*2]) || secondChar != TOLOWER(pwzPKT[j*2+1]))
6804 *pDllImportSearchPathFlag = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
6805 *pSearchAssemblyDirectory = TRUE;
6812 #endif // !FEATURE_CORECLR
6815 HMODULE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
6817 STANDARD_VM_CONTRACT;
6819 LoadLibErrorTracker errorTracker;
6820 const HMODULE systemModuleHandle =
6821 LocalLoadLibraryDirectHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
6822 if (systemModuleHandle == nullptr)
6824 SString libraryPathSString(libraryPath);
6825 errorTracker.Throw(libraryPathSString);
6827 return systemModuleHandle;
6830 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6832 HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName)
6834 STANDARD_VM_CONTRACT;
6835 //Dynamic Pinvoke Support:
6836 //Check if we need to provide the host a chance to provide the unmanaged dll
6838 #ifndef PLATFORM_UNIX
6839 // Prevent Overriding of Windows API sets.
6840 // This is replicating quick check from the OS implementation of api sets.
6841 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6848 CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
6849 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6851 PTR_ICLRPrivBinder pBindingContext = pAssembly->GetManifestFile()->GetBindingContext();
6853 //Step 0: Check if the assembly was bound using TPA.
6854 // The Binding Context can be null or an overridden TPA context
6855 if (pBindingContext == NULL)
6860 UINT_PTR assemblyBinderID = 0;
6861 IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6863 ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6865 // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
6866 if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
6871 #ifdef FEATURE_COMINTEROP
6872 CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
6873 if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
6875 // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
6876 // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
6878 // For this, we should use the standard mechanism to make pinvoke call as well.
6881 #endif // FEATURE_COMINTEROP
6883 //Step 1: If the assembly was not bound using TPA,
6884 // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
6885 // The custom assembly context a chance to load the unmanaged dll.
6889 STRINGREF pUnmanagedDllName;
6890 pUnmanagedDllName = StringObject::NewString(wszLibName);
6892 GCPROTECT_BEGIN(pUnmanagedDllName);
6894 // Get the pointer to the managed assembly load context
6895 INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6897 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
6898 PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
6899 DECLARE_ARGHOLDER_ARRAY(args, 2);
6900 args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
6901 args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6904 CALL_MANAGED_METHOD(hmod,LPVOID,args);
6909 if (hmod != nullptr)
6911 // Register the system library handle with PAL and get a PAL library handle
6912 hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6914 #endif // FEATURE_PAL
6916 return (HMODULE)hmod;
6918 #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6921 HINSTANCE NDirect::LoadLibraryModule( NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
6926 PRECONDITION( CheckPointer( pMD ) );
6930 LPCUTF8 name = pMD->GetLibName();
6931 if ( !name || !*name )
6934 ModuleHandleHolder hmod;
6936 DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
6938 PREFIX_ASSUME( name != NULL );
6939 MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
6941 AppDomain* pDomain = GetAppDomain();
6943 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6944 // AssemblyLoadContext is not supported in AppX mode and thus,
6945 // we should not perform PInvoke resolution via it when operating in
6947 if (!AppX::IsAppXProcess())
6949 hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName);
6951 #endif //FEATURE_HOST_ASSEMBLY_RESOLVER
6956 hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
6961 return hmod.Extract();
6964 #if !defined(FEATURE_CORESYSTEM)
6965 hmod = CheckForWellKnownModules(wszLibName, pErrorTracker);
6968 #ifndef FEATURE_CORECLR
6969 // Since fusion.dll has been incorporated into mscorwks.dll, we need to redirect
6970 // any PInvokes for fusion.dll over to this runtime module. In order to avoid picking
6971 // up invalid versions of fusion.dll, we perform this redirection first. Also redirect
6972 // PInvokes to mscorwks.dll and clr.dll to this runtime module (module rename back
6973 // compat and in-proc SxS correctness).
6976 static LPCWSTR const rwszAliases[] =
6978 W("fusion.dll"), W("mscorwks.dll"), W("clr.dll"),
6979 W("fusion"), W("mscorwks"), W("clr")
6982 for (int i = 0; i < COUNTOF(rwszAliases); i++)
6984 if (SString::_wcsicmp(wszLibName, rwszAliases[i]) == 0)
6986 hmod = GetCLRModule();
6991 // Some CLR DLLs cannot be directly PInvoked. They need in-proc SxS intialization - shim
6992 // (mscoreei.dll) takes care of that. Load such DLLs via shim.
6994 // Note that we do not support PInvoking into the newly renamed SxS versions of DLLs directly.
6995 // For example mscorpe.dll functionality was moved to mscorpehost.dll in 4.0. When asked for
6996 // loading mscorpe.dll, shim will load mscorpehost.dll and will call its InitializeSxS function
6997 // first. However shim will not call InitializeSxS when asked for mscorpehost.dll directly.
6998 // As a result users cannot use mscorpehost.dll directly for PInvokes (by design), they can only
6999 // use the old mscorpe.dll name.
7002 static LPCWSTR const rgSxSAwareDlls[] =
7004 W("mscorpe.dll"), W("mscorpe")
7007 for (int i = 0; i < COUNTOF(rgSxSAwareDlls); i++)
7009 if (SString::_wcsicmp(wszLibName, rgSxSAwareDlls[i]) == 0)
7011 // Load the DLL using shim (shim takes care of the DLL SxS initialization)
7012 HRESULT hr = g_pCLRRuntime->LoadLibrary(rgSxSAwareDlls[i], &hmod);
7014 { // We failed to load CLR DLL (probably corrupted installation)
7015 pErrorTracker->TrackHR_CouldNotLoad(hr);
7022 #endif //!FEATURE_CORECLR
7025 // In the PAL version of CoreCLR, the CLR module itself exports the functionality
7026 // that the Windows version obtains from kernel32 and friends. In order to avoid
7027 // picking up the wrong instance, we perform this redirection first.
7028 // This is also true for CoreSystem builds, where mscorlib p/invokes are forwarded through coreclr
7029 // itself so we can control CoreSystem library/API name re-mapping from one central location.
7030 if (SString::_wcsicmp(wszLibName, MAIN_CLR_MODULE_NAME_W) == 0)
7031 hmod = GetCLRModule();
7032 #endif // FEATURE_PAL
7034 #if defined(FEATURE_CORESYSTEM) && !defined(PLATFORM_UNIX)
7037 // Try to go straight to System32 for Windows API sets. This is replicating quick check from
7038 // the OS implementation of api sets.
7039 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
7041 hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
7044 #endif // FEATURE_CORESYSTEM && !FEATURE_PAL
7046 DWORD dllImportSearchPathFlag = 0;
7047 BOOL searchAssemblyDirectory = TRUE;
7050 #ifndef FEATURE_CORECLR
7051 // First checks if the method has DefaultDllImportSearchPathsAttribute. If method has the attribute
7052 // then dllImportSearchPathFlag is set to its value.
7053 // Otherwise checks if the assembly has the attribute.
7054 // If assembly has the attribute then flag ise set to its value.
7055 BOOL attributeIsFound = FALSE;
7057 if (pMD->HasDefaultDllImportSearchPathsAttribute())
7059 dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
7060 searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
7061 attributeIsFound = TRUE;
7065 Module * pModule = pMD->GetModule();
7067 if(pModule->HasDefaultDllImportSearchPathsAttribute())
7069 dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
7070 searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
7071 attributeIsFound = TRUE;
7075 if (!attributeIsFound)
7077 CheckUnificationList(pMD, &dllImportSearchPathFlag, &searchAssemblyDirectory);
7079 #endif // !FEATURE_CORECLR
7081 if (AbsolutePath(wszLibName))
7083 DWORD flags = loadWithAlteredPathFlags;
7084 if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
7086 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
7087 // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
7088 flags |= dllImportSearchPathFlag;
7091 hmod = LocalLoadLibraryHelper(wszLibName, flags, pErrorTracker);
7093 else if (searchAssemblyDirectory)
7095 // Try to load the DLL alongside the assembly where the PInvoke was
7096 // declared using the path of the assembly.
7097 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
7099 SString path = pAssembly->GetManifestFile()->GetPath();
7100 SString::Iterator i = path.End();
7102 if (PEAssembly::FindLastPathSeparator(path, i))
7107 path.Append(wszLibName);
7109 hmod = LocalLoadLibraryHelper(path, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7112 #ifndef FEATURE_CORECLR
7115 // Try to load the DLL alongside the assembly where the PInvoke was
7116 // declared using the codebase of the assembly. This is required for download
7117 // and shadow copy scenarios.
7120 pAssembly->GetCodeBase(codebase);
7121 DWORD dwCodebaseLength = codebase.GetCount();
7123 // Strip off the protocol
7124 for (ptr = codebase.GetUnicode(); *ptr && *ptr != W(':'); ptr++);
7126 // If we have a code base then prepend it to the library name
7129 SString pathFromCodebase;
7131 // After finding the colon move forward until no more forward slashes
7132 for(ptr++; *ptr && *ptr == W('/'); ptr++);
7135 // Calculate the number of characters we are interested in
7136 if (dwCodebaseLength > (DWORD)(ptr - codebase.GetUnicode()) )
7138 // Back up to the last slash (forward or backwards)
7141 for (tail = codebase.GetUnicode() + (dwCodebaseLength - 1); tail > ptr && *tail != W('/') && *tail != W('\\'); tail--);
7145 for(;ptr <= tail; ptr++)
7148 pathFromCodebase.Append(W('\\'));
7150 pathFromCodebase.Append(*ptr);
7156 pathFromCodebase.Append(wszLibName);
7158 if (!pathFromCodebase.EqualsCaseInsensitive(path, PEImage::GetFileSystemLocale()))
7160 hmod = LocalLoadLibraryHelper(pathFromCodebase, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7164 #endif // !FEATURE_CORECLR
7168 #ifdef FEATURE_CORECLR
7169 if (hmod == NULL && pDomain->HasNativeDllSearchDirectories())
7171 AppDomain::PathIterator i = pDomain->IterateNativeDllSearchDirectories();
7172 while (hmod == NULL && i.Next())
7174 SString qualifiedPath(*(i.GetPath()));
7175 qualifiedPath.Append(wszLibName);
7176 if (AbsolutePath(qualifiedPath))
7178 hmod = LocalLoadLibraryHelper(qualifiedPath, loadWithAlteredPathFlags, pErrorTracker);
7182 #endif // FEATURE_CORECLR
7184 // Do we really need to do this. This call searches the application directory
7185 // instead of the location for the library.
7188 hmod = LocalLoadLibraryHelper(wszLibName, dllImportSearchPathFlag, pErrorTracker);
7191 // This may be an assembly name
7194 // Format is "fileName, assemblyDisplayName"
7195 MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
7196 char *szComma = strchr(szLibName, ',');
7200 while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
7203 if (SUCCEEDED(spec.Init(szComma)))
7205 // Need to perform case insensitive hashing.
7208 UTF8_TO_LOWER_CASE(szLibName, qbLC);
7209 szLibName = (LPUTF8) qbLC.Ptr();
7212 Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
7213 Module *pModule = pAssembly->FindModuleByName(szLibName);
7215 hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
7220 // After all this, if we have a handle add it to the cache.
7223 pDomain->AddUnmanagedImageToCache(wszLibName, hmod);
7226 return hmod.Extract();
7230 //---------------------------------------------------------
7231 // Loads the DLL and finds the procaddress for an N/Direct call.
7232 //---------------------------------------------------------
7234 VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
7239 PRECONDITION(CheckPointer(pMD));
7244 // On the phone, we only allow platform assemblies to define pinvokes
7245 // unless the host has asked us otherwise.
7247 #ifdef FEATURE_WINDOWSPHONE
7248 if (!GetAppDomain()->EnablePInvokeAndClassicComInterop())
7250 if (!pMD->GetModule()->GetFile()->GetAssembly()->IsProfileAssembly())
7251 COMPlusThrow(kNotSupportedException, W("NotSupported_UserDllImport"));
7253 #endif //FEATURE_WINDOWS_PHONE
7256 if (pMD->IsClassConstructorTriggeredAtLinkTime())
7258 pMD->GetMethodTable()->CheckRunClassInitThrowing();
7263 LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget;
7265 // Do not repeat the lookup if the QCall was hardbound during ngen
7266 if (pvTarget == NULL)
7268 pvTarget = ECall::GetQCallImpl(pMD);
7272 _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD));
7275 pMD->SetNDirectTarget(pvTarget);
7279 // Loading unmanaged dlls can trigger dllmains which certainly count as code execution!
7280 pMD->EnsureActive();
7282 LoadLibErrorTracker errorTracker;
7284 BOOL fSuccess = FALSE;
7285 HINSTANCE hmod = LoadLibraryModule( pMD, &errorTracker );
7288 LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
7292 #ifdef MDA_SUPPORTED
7293 MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke);
7294 if (pOverlapCheck && pOverlapCheck->ShouldHook(pMD))
7296 LPVOID pNewTarget = pOverlapCheck->Register(hmod,pvTarget);
7299 pvTarget = pNewTarget;
7303 pMD->SetNDirectTarget(pvTarget);
7310 if (pMD->GetLibName() == NULL)
7311 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME);
7313 StackSString ssLibName(SString::Utf8, pMD->GetLibName());
7317 errorTracker.Throw(ssLibName);
7320 WCHAR wszEPName[50];
7321 if(WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0)
7323 wszEPName[0] = W('?');
7324 wszEPName[1] = W('\0');
7327 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS, ssLibName.GetUnicode(), wszEPName);
7332 //---------------------------------------------------------
7334 //---------------------------------------------------------
7335 /*static*/ void NDirect::Init()
7342 INJECT_FAULT(COMPlusThrowOM());
7346 #if !defined(FEATURE_CORECLR)
7347 // Generate a table of some well known native dlls
7348 s_pWellKnownNativeModules = ::new PtrHashMap();
7349 s_pWellKnownNativeModules->Init(sizeof(wellKnownModules)/sizeof(LPCWSTR), CompareLibNames, TRUE, NULL);
7350 for (int index = 0; index < sizeof(wellKnownModules)/sizeof(LPCWSTR); index++)
7352 s_pWellKnownNativeModules->InsertValue((UPTR) HashiString(wellKnownModules[index]), (LPVOID)wellKnownModules[index]);
7355 // Check if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
7356 HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
7357 _ASSERTE(hMod != NULL);
7359 if (GetProcAddress(hMod, "AddDllDirectory") != NULL)
7361 // The AddDllDirectory export was added in KB2533623 together with the new flag support
7362 s_fSecureLoadLibrarySupported = true;
7364 #endif // !FEATURE_CORECLR
7368 //==========================================================================
7369 // This function is reached only via NDirectImportThunk. It's purpose
7370 // is to ensure that the target DLL is fully loaded and ready to run.
7372 // FUN FACTS: Though this function is actually entered in unmanaged mode,
7373 // it can reenter managed mode and throw a COM+ exception if the DLL linking
7375 //==========================================================================
7378 EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD)
7382 BEGIN_PRESERVE_LAST_ERROR;
7393 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7394 // this function is called by CLR to native assembly stubs which are called by
7395 // managed code as a result, we need an unwind and continue handler to translate
7396 // any of our internal exceptions into managed exceptions.
7397 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7399 #ifdef FEATURE_MIXEDMODE // IJW
7400 if (pMD->IsEarlyBound())
7402 if (!pMD->IsZapped())
7404 // we need the MD to be populated in case we decide to build an intercept
7405 // stub to wrap the target in InitEarlyBoundNDirectTarget
7406 PInvokeStaticSigInfo sigInfo;
7407 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7410 pMD->InitEarlyBoundNDirectTarget();
7413 #endif // FEATURE_MIXEDMODE
7416 // Otherwise we're in an inlined pinvoke late bound MD
7418 INDEBUG(Thread *pThread = GetThread());
7420 _ASSERTE(pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr());
7422 CONSISTENCY_CHECK(pMD->IsNDirect());
7424 // With IL stubs, we don't have to do anything but ensure the DLL is loaded.
7427 if (!pMD->GetModule()->GetSecurityDescriptor()->CanCallUnmanagedCode())
7428 Security::ThrowSecurityException(g_SecurityPermissionClassName, SPFLAGSUNMANAGEDCODE);
7430 if (!pMD->IsZapped())
7432 PInvokeStaticSigInfo sigInfo;
7433 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
7437 // must have been populated at NGEN time
7438 _ASSERTE(pMD->GetLibName() != NULL);
7441 pMD->CheckRestore();
7443 NDirect::NDirectLink(pMD);
7447 ret = pMD->GetNDirectTarget();
7449 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7450 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7452 END_PRESERVE_LAST_ERROR;
7457 //===========================================================================
7458 // Support for Pinvoke Calli instruction
7460 //===========================================================================
7462 EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
7464 BEGIN_PRESERVE_LAST_ERROR;
7466 STATIC_CONTRACT_THROWS;
7467 STATIC_CONTRACT_GC_TRIGGERS;
7468 STATIC_CONTRACT_MODE_COOPERATIVE;
7469 STATIC_CONTRACT_ENTRY_POINT;
7471 MAKE_CURRENT_THREAD_AVAILABLE();
7474 Thread::ObjectRefFlush(CURRENT_THREAD);
7477 FrameWithCookie<PrestubMethodFrame> frame(pTransitionBlock, pMD);
7478 PrestubMethodFrame * pFrame = &frame;
7480 pFrame->Push(CURRENT_THREAD);
7482 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7483 _ASSERTE(pMD == pFrame->GetFunction());
7485 GetILStubForCalli(pVASigCookie, pMD);
7487 pFrame->Pop(CURRENT_THREAD);
7489 END_PRESERVE_LAST_ERROR;
7492 EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
7494 BEGIN_PRESERVE_LAST_ERROR;
7496 STATIC_CONTRACT_THROWS;
7497 STATIC_CONTRACT_GC_TRIGGERS;
7498 STATIC_CONTRACT_MODE_COOPERATIVE;
7499 STATIC_CONTRACT_ENTRY_POINT;
7501 MAKE_CURRENT_THREAD_AVAILABLE();
7504 Thread::ObjectRefFlush(CURRENT_THREAD);
7507 FrameWithCookie<PInvokeCalliFrame> frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget);
7508 PInvokeCalliFrame * pFrame = &frame;
7510 pFrame->Push(CURRENT_THREAD);
7512 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
7514 GetILStubForCalli(pVASigCookie, NULL);
7516 pFrame->Pop(CURRENT_THREAD);
7518 END_PRESERVE_LAST_ERROR;
7521 PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
7529 PRECONDITION(CheckPointer(pVASigCookie));
7530 PRECONDITION(CheckPointer(pMD, NULL_OK));
7531 POSTCONDITION(RETVAL != NULL);
7535 PCODE pTempILStub = NULL;
7537 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
7538 // this function is called by CLR to native assembly stubs which are called by
7539 // managed code as a result, we need an unwind and continue handler to translate
7540 // any of our internal exceptions into managed exceptions.
7541 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
7543 // Force a GC if the stress level is high enough
7544 GCStress<cfg_any>::MaybeTrigger();
7548 Signature signature = pVASigCookie->signature;
7549 CorPinvokeMap unmgdCallConv = pmNoMangle;
7551 DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
7553 // The MethodDesc pointer may in fact be the unmanaged target, see PInvokeStubs.asm.
7554 if (pMD == NULL || (UINT_PTR)pMD & 0x1)
7557 dwStubFlags |= NDIRECTSTUB_FL_UNMANAGED_CALLI;
7559 // need to convert the CALLI signature to stub signature with managed calling convention
7560 switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->signature))
7562 case IMAGE_CEE_CS_CALLCONV_C:
7563 unmgdCallConv = pmCallConvCdecl;
7565 case IMAGE_CEE_CS_CALLCONV_STDCALL:
7566 unmgdCallConv = pmCallConvStdcall;
7568 case IMAGE_CEE_CS_CALLCONV_THISCALL:
7569 unmgdCallConv = pmCallConvThiscall;
7571 case IMAGE_CEE_CS_CALLCONV_FASTCALL:
7572 unmgdCallConv = pmCallConvFastcall;
7575 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
7578 LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
7579 PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
7580 CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
7582 // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT
7583 *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK;
7584 *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT;
7586 signature = Signature(new_sig, signature.GetRawSigLen());
7590 _ASSERTE(pMD->IsNDirect());
7591 dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
7593 // vararg P/Invoke must be cdecl
7594 unmgdCallConv = pmCallConvCdecl;
7596 if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
7598 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
7603 CorNativeLinkFlags nlFlags;
7604 CorNativeLinkType nlType;
7608 PInvokeStaticSigInfo sigInfo(pMD);
7610 md = pMD->GetMemberDef();
7611 nlFlags = sigInfo.GetLinkFlags();
7612 nlType = sigInfo.GetCharSet();
7616 md = mdMethodDefNil;
7621 StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule);
7623 MethodDesc* pStubMD = NDirect::CreateCLRToNativeILStub(&sigDesc,
7629 pTempILStub = JitILStub(pStubMD);
7631 InterlockedCompareExchangeT<PCODE>(&pVASigCookie->pNDirectILStub,
7635 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
7636 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
7638 RETURN pVASigCookie->pNDirectILStub;
7641 #endif // CROSSGEN_COMPILE
7643 #endif // #ifndef DACCESS_COMPILE
7646 // Truncates a SString by first converting it to unicode and truncate it
7647 // if it is larger than size. "..." will be appened if it is truncated.
7649 void TruncateUnicodeString(SString &string, COUNT_T bufSize)
7652 if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize)
7654 _ASSERTE(bufSize / sizeof(WCHAR) > 4);
7655 string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4);
7656 string.Append(W("..."));