1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
19 #include "dllimport.h"
21 #include "siginfo.hpp"
23 #include "comdelegate.h"
27 #include "comutilnative.h"
29 #include "asmconstants.h"
30 #include "mdaassistants.h"
31 #include "customattribute.h"
32 #include "ilstubcache.h"
33 #include "typeparse.h"
34 #include "sigbuilder.h"
35 #include "sigformat.h"
36 #include "strongnameholders.h"
39 #include <formattype.h>
40 #include "../md/compiler/custattr.h"
42 #ifdef FEATURE_COMINTEROP
43 #include "runtimecallablewrapper.h"
44 #include "clrtocomcall.h"
45 #endif // FEATURE_COMINTEROP
49 #endif // FEATURE_PREJIT
51 #include "eventtrace.h"
54 #include "clr/fs/path.h"
55 using namespace clr::fs;
57 // remove when we get an updated SDK
58 #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
59 #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
61 void AppendEHClause(int nClauses, COR_ILMETHOD_SECT_EH * pEHSect, ILStubEHClause * pClause, int * pCurIdx)
63 LIMITED_METHOD_CONTRACT;
64 if (pClause->kind == ILStubEHClause::kNone)
70 CorExceptionFlag flags;
71 switch (pClause->kind)
73 case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break;
74 case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break;
76 UNREACHABLE_MSG("unexpected ILStubEHClause kind");
78 _ASSERTE(idx < nClauses);
79 pEHSect->Fat.Clauses[idx].Flags = flags;
80 pEHSect->Fat.Clauses[idx].TryOffset = pClause->dwTryBeginOffset;
81 pEHSect->Fat.Clauses[idx].TryLength = pClause->cbTryLength;
82 pEHSect->Fat.Clauses[idx].HandlerOffset = pClause->dwHandlerBeginOffset;
83 pEHSect->Fat.Clauses[idx].HandlerLength = pClause->cbHandlerLength;
84 pEHSect->Fat.Clauses[idx].ClassToken = pClause->dwTypeToken;
87 VOID PopulateEHSect(COR_ILMETHOD_SECT_EH * pEHSect, int nClauses, ILStubEHClause * pOne, ILStubEHClause * pTwo)
89 LIMITED_METHOD_CONTRACT;
90 pEHSect->Fat.Kind = (CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat);
91 pEHSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(nClauses);
94 AppendEHClause(nClauses, pEHSect, pOne, &curIdx);
95 AppendEHClause(nClauses, pEHSect, pTwo, &curIdx);
98 StubSigDesc::StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo /*= NULL*/)
109 if (pSigInfo != NULL)
111 m_sig = pSigInfo->GetSignature();
112 m_pModule = pSigInfo->GetModule();
116 _ASSERTE(pMD != NULL);
117 m_sig = pMD->GetSignature();
118 m_pModule = pMD->GetModule(); // Used for token resolution.
123 m_tkMethodDef = pMD->GetMemberDef();
124 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
125 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
129 m_tkMethodDef = mdMethodDefNil;
130 m_pLoaderModule = m_pModule;
133 INDEBUG(InitDebugNames());
136 StubSigDesc::StubSigDesc(MethodDesc *pMD, Signature sig, Module *pModule)
143 PRECONDITION(!sig.IsEmpty());
144 PRECONDITION(pModule != NULL);
154 m_tkMethodDef = pMD->GetMemberDef();
155 SigTypeContext::InitTypeContext(pMD, &m_typeContext);
156 m_pLoaderModule = pMD->GetLoaderModule(); // Used for ILStubCache selection and MethodTable creation.
160 m_tkMethodDef = mdMethodDefNil;
161 m_pLoaderModule = m_pModule;
164 INDEBUG(InitDebugNames());
167 #ifndef DACCESS_COMPILE
172 virtual void SetLastError(BOOL fSetLastError) = 0;
173 virtual void BeginEmit(DWORD dwStubFlags) = 0;
174 virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) = 0;
175 virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) = 0;
176 virtual void MarshalLCID(int argIdx) = 0;
178 #ifdef FEATURE_COMINTEROP
179 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray) = 0;
180 virtual void MarshalFactoryReturn() = 0;
181 #endif // FEATURE_COMINTEROP
183 virtual void EmitInvokeTarget(MethodDesc *pStubMD) = 0;
185 virtual void FinishEmit(MethodDesc* pMD) = 0;
189 LIMITED_METHOD_CONTRACT;
193 class ILStubState : public StubState
199 const Signature &signature,
200 SigTypeContext* pTypeContext,
205 MethodDesc* pTargetMD)
206 : m_slIL(dwStubFlags, pStubModule, signature, pTypeContext, pTargetMD, iLCIDParamIdx, fTargetHasThis, fStubHasThis)
208 STANDARD_VM_CONTRACT;
214 void SetLastError(BOOL fSetLastError)
216 LIMITED_METHOD_CONTRACT;
218 m_fSetLastError = fSetLastError;
221 // We use three stub linkers to generate IL stubs. The pre linker is the main one. It does all the marshaling and
222 // then calls the target method. The post return linker is only used to unmarshal the return value after we return
223 // from the target method. The post linker handles all the unmarshaling for by ref arguments and clean-up. It
224 // also checks if we should throw an exception etc.
226 // Currently, we have two "emittable" ILCodeLabel's. The first one is at the beginning of the pre linker. This
227 // label is used to emit code to declare and initialize clean-up flags. Each argument which requires clean-up
228 // emits one flag. This flag is set only after the marshaling is done, and it is checked before we do any clean-up
231 // The second "emittable" ILCodeLabel is at the beginning of the post linker. It is used to emit code which is
232 // not safe to run in the case of an exception. The rest of the post linker is wrapped in a finally, and it contains
233 // with the necessary clean-up which should be executed in both normal and exception cases.
234 void BeginEmit(DWORD dwStubFlags)
237 m_slIL.Begin(dwStubFlags);
238 m_dwStubFlags = dwStubFlags;
241 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
247 PRECONDITION(CheckPointer(pInfo));
251 pInfo->GenerateReturnIL(&m_slIL, argOffset,
252 SF_IsForwardStub(m_dwStubFlags),
253 SF_IsFieldGetterStub(m_dwStubFlags),
254 SF_IsHRESULTSwapping(m_dwStubFlags));
257 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
262 PRECONDITION(CheckPointer(pInfo));
266 pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags));
269 #ifdef FEATURE_COMINTEROP
270 // Marshal the hidden length parameter for the managed parameter in pInfo
271 virtual void MarshalHiddenLengthArgument(MarshalInfo *pInfo, BOOL isForReturnArray)
273 STANDARD_VM_CONTRACT;
275 pInfo->MarshalHiddenLengthArgument(&m_slIL, SF_IsForwardStub(m_dwStubFlags), isForReturnArray);
277 if (SF_IsReverseStub(m_dwStubFlags))
279 // Hidden length arguments appear explicitly in the native signature
280 // however, they are not in the managed signature.
281 m_slIL.AdjustTargetStackDeltaForExtraParam();
285 void MarshalFactoryReturn()
290 PRECONDITION(SF_IsCOMStub(m_dwStubFlags));
291 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
295 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
296 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
297 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
298 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
304 // create a local to hold the returned pUnk and initialize to 0 in case the factory fails
305 // and we try to release it during cleanup
306 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
307 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
308 pcsSetup->EmitLoadNullPtr();
309 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
311 DWORD dwInnerIInspectableLocalNum = -1;
312 DWORD dwOuterIInspectableLocalNum = -1;
313 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
315 // Create locals to store the outer and inner IInspectable values and initialize to null
316 // Note that we do this in the setup stream so that we're guaranteed to have a null-initialized
317 // value in the cleanup stream
318 LocalDesc locDescOuterIInspectable(ELEMENT_TYPE_I);
319 dwOuterIInspectableLocalNum = pcsSetup->NewLocal(locDescOuterIInspectable);
320 pcsSetup->EmitLoadNullPtr();
321 pcsSetup->EmitSTLOC(dwOuterIInspectableLocalNum);
322 LocalDesc locDescInnerIInspectable(ELEMENT_TYPE_I);
323 dwInnerIInspectableLocalNum = pcsSetup->NewLocal(locDescInnerIInspectable);
324 pcsSetup->EmitLoadNullPtr();
325 pcsSetup->EmitSTLOC(dwInnerIInspectableLocalNum);
332 // For composition factories, add the two extra params
333 if (SF_IsWinRTCompositionStub(m_dwStubFlags))
335 // Get outer IInspectable. The helper will return NULL if this is the "top-level" constructor,
336 // and the appropriate outer pointer otherwise.
337 pcsDispatch->EmitLoadThis();
338 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
339 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_OUTER_INSPECTABLE, 2, 1);
340 pcsDispatch->EmitSTLOC(dwOuterIInspectableLocalNum);
342 // load the outer IInspectable (3rd last argument)
343 pcsDispatch->SetStubTargetArgType(ELEMENT_TYPE_I, false);
344 pcsDispatch->EmitLDLOC(dwOuterIInspectableLocalNum);
346 // pass pointer to where inner non-delegating IInspectable should be stored (2nd last argument)
347 LocalDesc locDescInnerPtr(ELEMENT_TYPE_I);
348 locDescInnerPtr.MakeByRef();
349 pcsDispatch->SetStubTargetArgType(&locDescInnerPtr, false);
350 pcsDispatch->EmitLDLOCA(dwInnerIInspectableLocalNum);
353 // pass pointer to the local to the factory method (last argument)
354 locDescFactoryRetVal.MakeByRef();
355 pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
356 pcsDispatch->EmitLDLOCA(dwFactoryRetValLocalNum);
362 // Mark that the factory method has succesfully returned and so cleanup will be necessary after
364 m_slIL.EmitSetArgMarshalIndex(pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL);
366 // associate the 'this' RCW with one of the returned interface pointers
367 pcsUnmarshal->EmitLoadThis();
369 // now we need to find the right interface pointer to load
370 if (dwInnerIInspectableLocalNum != -1)
372 // We may have a composition scenario
373 ILCodeLabel* pNonCompositionLabel = pcsUnmarshal->NewCodeLabel();
374 ILCodeLabel* pLoadedLabel = pcsUnmarshal->NewCodeLabel();
376 // Did we pass an outer IInspectable?
377 pcsUnmarshal->EmitLDLOC(dwOuterIInspectableLocalNum);
378 pcsUnmarshal->EmitBRFALSE(pNonCompositionLabel);
380 // yes, this is a composition scenario
382 // ignore the delegating interface pointer (will be released in cleanup below) - we can
383 // re-create it by QI'ing the non-delegating one.
384 // Note that using this could be useful in the future (avoids an extra QueryInterface call)
385 // Just load the non-delegating interface pointer
386 pcsUnmarshal->EmitLDLOCA(dwInnerIInspectableLocalNum);
387 pcsUnmarshal->EmitBR(pLoadedLabel);
389 // else, no this is a non-composition scenario
391 pcsUnmarshal->EmitLabel(pNonCompositionLabel);
393 // ignore the non-delegating interface pointer (which should be null, but will regardless get
394 // cleaned up below in the event the factory doesn't follow the pattern properly).
395 // Just load the regular delegating interface pointer
396 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
399 pcsUnmarshal->EmitLabel(pLoadedLabel);
403 // Definitely can't be a composition scenario - use the only pointer we have
404 pcsUnmarshal->EmitLDLOCA(dwFactoryRetValLocalNum);
407 pcsUnmarshal->EmitCALL(METHOD__MARSHAL__INITIALIZE_WRAPPER_FOR_WINRT, 2, 0);
413 // release the returned interface pointer in the finally block
414 m_slIL.SetCleanupNeeded();
416 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
418 m_slIL.EmitCheckForArgCleanup(pcsCleanup,
419 NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL,
420 NDirectStubLinker::BranchIfNotMarshaled,
423 EmitInterfaceClearNative(pcsCleanup, dwFactoryRetValLocalNum);
425 // Note that it's a no-op to pass NULL to Clear_Native, so we call it even though we don't
426 // know if we assigned to the inner/outer IInspectable
427 if (dwInnerIInspectableLocalNum != -1)
429 EmitInterfaceClearNative(pcsCleanup, dwInnerIInspectableLocalNum);
431 if (dwOuterIInspectableLocalNum != -1)
433 EmitInterfaceClearNative(pcsCleanup, dwOuterIInspectableLocalNum);
436 pcsCleanup->EmitLabel(pSkipCleanupLabel);
439 static void EmitInterfaceClearNative(ILCodeStream* pcsEmit, DWORD dwLocalNum)
441 STANDARD_VM_CONTRACT;
443 ILCodeLabel *pSkipClearNativeLabel = pcsEmit->NewCodeLabel();
444 pcsEmit->EmitLDLOC(dwLocalNum);
445 pcsEmit->EmitBRFALSE(pSkipClearNativeLabel);
446 pcsEmit->EmitLDLOC(dwLocalNum);
447 pcsEmit->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
448 pcsEmit->EmitLabel(pSkipClearNativeLabel);
451 #endif // FEATURE_COMINTEROP
453 void MarshalLCID(int argIdx)
455 STANDARD_VM_CONTRACT;
457 ILCodeStream* pcs = m_slIL.GetDispatchCodeStream();
459 #ifdef FEATURE_USE_LCID
460 if (SF_IsReverseStub(m_dwStubFlags))
462 if ((m_slIL.GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_HASTHIS) == IMAGE_CEE_CS_CALLCONV_HASTHIS)
464 // the arg number will be incremented by LDARG if we are in an instance method
465 _ASSERTE(argIdx > 0);
469 LocalDesc locDescThread(MscorlibBinder::GetClass(CLASS__THREAD));
470 DWORD dwThreadLocalNum = pcs->NewLocal(locDescThread);
472 // call Thread.get_CurrentThread()
473 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
475 pcs->EmitSTLOC(dwThreadLocalNum);
477 // call current_thread.get_CurrentCulture()
478 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
480 // save the current culture
481 LocalDesc locDescCulture(MscorlibBinder::GetClass(CLASS__CULTURE_INFO));
482 DWORD dwCultureLocalNum = pcs->NewLocal(locDescCulture);
484 pcs->EmitSTLOC(dwCultureLocalNum);
486 // set a new one based on the LCID passed from unmanaged
487 pcs->EmitLDLOC(dwThreadLocalNum);
488 pcs->EmitLDARG(argIdx);
490 // call CultureInfo..ctor(lcid)
491 // call current_thread.set_CurrentCulture(culture)
492 pcs->EmitNEWOBJ(METHOD__CULTURE_INFO__INT_CTOR, 1);
493 pcs->EmitCALL(METHOD__THREAD__SET_CULTURE, 2, 0);
495 // and restore the current one after the call
496 m_slIL.SetCleanupNeeded();
497 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
499 // call current_thread.set_CurrentCulture(original_culture)
500 pcsCleanup->EmitLDLOC(dwThreadLocalNum);
501 pcsCleanup->EmitLDLOC(dwCultureLocalNum);
502 pcsCleanup->EmitCALL(METHOD__THREAD__SET_CULTURE, 1, 1);
507 if (SF_IsCOMStub(m_dwStubFlags))
509 // We used to get LCID from current thread's culture here. The code
510 // was replaced by the hardcoded LCID_ENGLISH_US as requested by VSTO.
511 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
515 // call Thread.get_CurrentThread()
516 // call current_thread.get_CurrentCulture()
517 pcs->EmitCALL(METHOD__THREAD__GET_CURRENT_THREAD, 0, 1);
518 pcs->EmitCALL(METHOD__THREAD__GET_CULTURE, 1, 1);
520 //call CultureInfo.get_LCID(this)
521 pcs->EmitCALL(METHOD__CULTURE_INFO__GET_ID, 1, 1);
524 #else // FEATURE_USE_LCID
525 if (SF_IsForwardStub(m_dwStubFlags))
527 pcs->EmitLDC(0x0409); // LCID_ENGLISH_US
529 #endif // FEATURE_USE_LCID
531 // add the extra arg to the unmanaged signature
532 LocalDesc locDescNative(ELEMENT_TYPE_I4);
533 pcs->SetStubTargetArgType(&locDescNative, false);
535 if (SF_IsReverseStub(m_dwStubFlags))
537 // reverse the effect of SetStubTargetArgType on the stack delta
538 // (the LCID argument is explicitly passed from unmanaged but does not
539 // show up in the managed signature in any way)
540 m_slIL.AdjustTargetStackDeltaForExtraParam();
545 void SwapStubSignatures(MethodDesc* pStubMD)
547 STANDARD_VM_CONTRACT;
550 // Since the stub handles native-to-managed transitions, we have to swap the
551 // stub-state-calculated stub target sig with the stub sig itself. This is
552 // because the stub target sig represents the native signature and the stub
553 // sig represents the managed signature.
555 // The first step is to convert the managed signature to a module-independent
556 // signature and then pass it off to SetStubTargetMethodSig. Note that the
557 // ILStubResolver will copy the sig, so we only need to make a temporary copy
560 SigBuilder sigBuilder;
563 SigPointer sigPtr(pStubMD->GetSig());
564 sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder);
568 // The second step is to reset the sig on the stub MethodDesc to be the
569 // stub-state-calculated stub target sig.
573 // make a domain-local copy of the sig so that this state can outlive the
574 // compile time state.
577 PCCOR_SIGNATURE pNewSig;
579 cbNewSig = GetStubTargetMethodSigLength();
580 pNewSig = (PCCOR_SIGNATURE)(void *)pStubMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig));
582 memcpyNoGCRefs((void *)pNewSig, GetStubTargetMethodSig(), cbNewSig);
584 pStubMD->AsDynamicMethodDesc()->SetStoredMethodSig(pNewSig, cbNewSig);
586 SigPointer sigPtr(pNewSig, cbNewSig);
588 IfFailThrow(sigPtr.GetCallingConvInfo(&callConvInfo));
590 if (callConvInfo & CORINFO_CALLCONV_HASTHIS)
592 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags &= ~mdStatic;
593 pStubMD->ClearStatic();
597 ((PTR_DynamicMethodDesc)pStubMD)->m_dwExtendedFlags |= mdStatic;
598 pStubMD->SetStatic();
602 // we store the real managed argument stack size in the stub MethodDesc on non-X86
603 UINT stackSize = pStubMD->SizeOfArgStack();
605 if (!FitsInU2(stackSize))
606 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
608 pStubMD->AsDynamicMethodDesc()->SetNativeStackArgSize(static_cast<WORD>(stackSize));
609 #endif // _TARGET_X86_
612 DWORD cbTempModuleIndependentSigLength;
613 BYTE * pTempModuleIndependentSig = (BYTE *)sigBuilder.GetSignature(&cbTempModuleIndependentSigLength);
616 SetStubTargetMethodSig(pTempModuleIndependentSig,
617 cbTempModuleIndependentSigLength);
620 void EmitInvokeTarget(MethodDesc *pStubMD)
622 STANDARD_VM_CONTRACT;
624 m_slIL.DoNDirect(m_slIL.GetDispatchCodeStream(), m_dwStubFlags, pStubMD);
627 #ifdef FEATURE_COMINTEROP
628 void EmitExceptionHandler(LocalDesc* pNativeReturnType, LocalDesc* pManagedReturnType,
629 ILCodeLabel** ppTryEndAndCatchBeginLabel, ILCodeLabel ** ppCatchEndAndReturnLabel)
631 STANDARD_VM_CONTRACT;
633 ILCodeStream* pcsExceptionHandler = m_slIL.NewCodeStream(ILStubLinker::kExceptionHandler);
634 *ppTryEndAndCatchBeginLabel = pcsExceptionHandler->NewCodeLabel();
635 *ppCatchEndAndReturnLabel = pcsExceptionHandler->NewCodeLabel();
637 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
638 pcsExceptionHandler->EmitLabel(*ppTryEndAndCatchBeginLabel);
640 BYTE nativeReturnElemType = pNativeReturnType->ElementType[0]; // return type of the stub
641 BYTE managedReturnElemType = pManagedReturnType->ElementType[0]; // return type of the mananged target
643 bool returnTheHRESULT = SF_IsHRESULTSwapping(m_dwStubFlags) ||
644 (managedReturnElemType == ELEMENT_TYPE_I4) ||
645 (managedReturnElemType == ELEMENT_TYPE_U4);
648 if (!returnTheHRESULT)
650 MdaExceptionSwallowedOnCallFromCom* mda = MDA_GET_ASSISTANT(ExceptionSwallowedOnCallFromCom);
653 // on the stack: exception object, but the stub linker doesn't know it
654 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
655 pcsExceptionHandler->EmitCALL(METHOD__STUBHELPERS__TRIGGER_EXCEPTION_SWALLOWED_MDA,
656 1, // WARNING: This method takes 2 input args, the exception object and the stub context.
657 // But the ILStubLinker has no knowledge that the exception object is on the
658 // stack (because it is unaware that we've just entered a catch block), so we
659 // lie and claim that we only take one input argument.
660 1); // returns the exception object back
663 #endif // MDA_SUPPORTED
665 DWORD retvalLocalNum = m_slIL.GetReturnValueLocalNum();
666 BinderMethodID getHRForException;
667 if (SF_IsWinRTStub(m_dwStubFlags))
669 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION_WINRT;
673 getHRForException = METHOD__MARSHAL__GET_HR_FOR_EXCEPTION;
676 pcsExceptionHandler->EmitCALL(getHRForException,
677 0, // WARNING: This method takes 1 input arg, the exception object. But the ILStubLinker
678 // has no knowledge that the exception object is on the stack (because it is
679 // unaware that we've just entered a catch block), so we lie and claim that we
680 // don't take any input arguments.
683 switch (nativeReturnElemType)
686 UNREACHABLE_MSG("Unexpected element type found on native return type.");
688 case ELEMENT_TYPE_VOID:
689 _ASSERTE(retvalLocalNum == (DWORD)-1);
690 pcsExceptionHandler->EmitPOP();
692 case ELEMENT_TYPE_I4:
693 case ELEMENT_TYPE_U4:
695 if (!returnTheHRESULT)
697 pcsExceptionHandler->EmitPOP();
698 pcsExceptionHandler->EmitLDC(0);
699 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
701 _ASSERTE(retvalLocalNum != (DWORD)-1);
702 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
705 case ELEMENT_TYPE_R4:
706 pcsExceptionHandler->EmitPOP();
707 pcsExceptionHandler->EmitLDC_R4(CLR_NAN_32);
708 _ASSERTE(retvalLocalNum != (DWORD)-1);
709 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
711 case ELEMENT_TYPE_R8:
712 pcsExceptionHandler->EmitPOP();
713 pcsExceptionHandler->EmitLDC_R8(CLR_NAN_64);
714 _ASSERTE(retvalLocalNum != (DWORD)-1);
715 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
717 case ELEMENT_TYPE_INTERNAL:
719 TypeHandle returnTypeHnd = pNativeReturnType->InternalToken;
720 CONSISTENCY_CHECK(returnTypeHnd.IsValueType());
721 _ASSERTE(retvalLocalNum != (DWORD)-1);
722 pcsExceptionHandler->EmitLDLOCA(retvalLocalNum);
723 pcsExceptionHandler->EmitINITOBJ(m_slIL.GetDispatchCodeStream()->GetToken(returnTypeHnd));
726 case ELEMENT_TYPE_BOOLEAN:
727 case ELEMENT_TYPE_CHAR:
728 case ELEMENT_TYPE_I1:
729 case ELEMENT_TYPE_U1:
730 case ELEMENT_TYPE_I2:
731 case ELEMENT_TYPE_U2:
732 case ELEMENT_TYPE_I8:
733 case ELEMENT_TYPE_U8:
736 pcsExceptionHandler->EmitPOP();
737 pcsExceptionHandler->EmitLDC(0);
738 pcsExceptionHandler->EmitCONV_T((CorElementType)nativeReturnElemType);
739 _ASSERTE(retvalLocalNum != (DWORD)-1);
740 pcsExceptionHandler->EmitSTLOC(retvalLocalNum);
744 pcsExceptionHandler->EmitLEAVE(*ppCatchEndAndReturnLabel);
745 pcsExceptionHandler->EmitLabel(*ppCatchEndAndReturnLabel);
746 if (nativeReturnElemType != ELEMENT_TYPE_VOID)
748 _ASSERTE(retvalLocalNum != (DWORD)-1);
749 pcsExceptionHandler->EmitLDLOC(retvalLocalNum);
751 pcsExceptionHandler->EmitRET();
753 #endif // FEATURE_COMINTEROP
755 void FinishEmit(MethodDesc* pStubMD)
757 STANDARD_VM_CONTRACT;
759 ILCodeStream* pcsMarshal = m_slIL.GetMarshalCodeStream();
760 ILCodeStream* pcsUnmarshal = m_slIL.GetUnmarshalCodeStream();
761 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
763 if (SF_IsHRESULTSwapping(m_dwStubFlags) && m_slIL.StubHasVoidReturnType())
765 // if the return type is void, but we're doing HRESULT swapping, we
766 // need to set the return type here. Otherwise, the return value
767 // marshaler will do this.
768 pcsMarshal->SetStubTargetReturnType(ELEMENT_TYPE_I4); // HRESULT
770 if (SF_IsReverseStub(m_dwStubFlags))
772 // reverse interop needs to seed the return value if the
773 // managed function returns void but we're doing hresult
775 pcsUnmarshal->EmitLDC(S_OK);
779 LocalDesc nativeReturnType;
780 LocalDesc managedReturnType;
781 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(m_dwStubFlags)
782 && !SF_IsFieldGetterStub(m_dwStubFlags)
783 && !SF_IsFieldSetterStub(m_dwStubFlags);
785 #ifdef FEATURE_COMINTEROP
786 if (hasTryCatchForHRESULT)
788 m_slIL.GetStubTargetReturnType(&nativeReturnType);
789 m_slIL.GetStubReturnType(&managedReturnType);
791 #endif // FEATURE_COMINTEROP
793 if (SF_IsHRESULTSwapping(m_dwStubFlags) && SF_IsReverseStub(m_dwStubFlags))
795 m_slIL.AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
798 if (SF_IsForwardCOMStub(m_dwStubFlags))
800 // Compensate for the 'this' parameter.
801 m_slIL.AdjustTargetStackDeltaForExtraParam();
804 #if defined(_TARGET_X86_)
805 // unmanaged CALLI will get an extra arg with the real target address if host hook is enabled
806 if (SF_IsCALLIStub(m_dwStubFlags) && NDirect::IsHostHookEnabled())
808 pcsMarshal->SetStubTargetArgType(ELEMENT_TYPE_I, false);
810 #endif // _TARGET_X86_
812 // Don't touch target signatures from this point on otherwise it messes up the
813 // cache in ILStubState::GetStubTargetMethodSig.
817 // The native and local signatures should not have any tokens.
818 // All token references should have been converted to
819 // ELEMENT_TYPE_INTERNAL.
821 // Note that MetaSig::GetReturnType and NextArg will normalize
822 // ELEMENT_TYPE_INTERNAL back to CLASS or VALUETYPE.
824 // <TODO> need to recursively check ELEMENT_TYPE_FNPTR signatures </TODO>
826 SigTypeContext typeContext; // this is an empty type context: COM calls are guaranteed to not be generics.
828 GetStubTargetMethodSig(),
829 GetStubTargetMethodSigLength(),
830 MscorlibBinder::GetModule(),
834 IfFailThrow(nsig.GetReturnProps().PeekElemType(&type));
835 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
837 while (ELEMENT_TYPE_END != (type = nsig.NextArg()))
839 IfFailThrow(nsig.GetArgProps().PeekElemType(&type));
840 CONSISTENCY_CHECK(ELEMENT_TYPE_CLASS != type && ELEMENT_TYPE_VALUETYPE != type);
845 #ifdef FEATURE_COMINTEROP
846 if (SF_IsForwardCOMStub(m_dwStubFlags))
848 #if defined(MDA_SUPPORTED)
849 // We won't use this NGEN'ed stub if RaceOnRCWCleanup is enabled at run-time
850 if (!SF_IsNGENedStub(m_dwStubFlags))
852 // This code may change the type of the frame we use, so it has to be run before the code below where we
853 // retrieve the stack arg size based on the frame type.
854 MdaRaceOnRCWCleanup* mda = MDA_GET_ASSISTANT(RaceOnRCWCleanup);
857 // Here we have to register the RCW of the "this" object to the RCWStack and schedule the clean-up for it.
858 // Emit a call to StubHelpers::StubRegisterRCW() and StubHelpers::StubUnregisterRCW() to do this.
859 m_slIL.EmitLoadRCWThis(pcsMarshal, m_dwStubFlags);
860 pcsMarshal->EmitCALL(METHOD__STUBHELPERS__STUB_REGISTER_RCW, 1, 0);
862 // We use an extra local to track whether we need to unregister the RCW on cleanup
863 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
864 DWORD dwRCWRegisteredLocalNum = pcsSetup->NewLocal(ELEMENT_TYPE_BOOLEAN);
865 pcsSetup->EmitLDC(0);
866 pcsSetup->EmitSTLOC(dwRCWRegisteredLocalNum);
868 pcsMarshal->EmitLDC(1);
869 pcsMarshal->EmitSTLOC(dwRCWRegisteredLocalNum);
871 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
872 ILCodeLabel *pSkipCleanupLabel = pcsCleanup->NewCodeLabel();
874 m_slIL.SetCleanupNeeded();
875 pcsCleanup->EmitLDLOC(dwRCWRegisteredLocalNum);
876 pcsCleanup->EmitBRFALSE(pSkipCleanupLabel);
878 m_slIL.EmitLoadRCWThis(pcsCleanup, m_dwStubFlags);
879 pcsCleanup->EmitCALL(METHOD__STUBHELPERS__STUB_UNREGISTER_RCW, 1, 0);
881 pcsCleanup->EmitLabel(pSkipCleanupLabel);
884 #endif // MDA_SUPPORTED
886 #endif // FEATURE_COMINTEROP
889 // The profiler helpers below must be called immediately before and after the call to the target.
890 // The debugger trace call helpers are invoked from StubRareDisableWorker
893 #if defined(PROFILING_SUPPORTED)
894 DWORD dwMethodDescLocalNum = -1;
896 // Notify the profiler of call out of the runtime
897 if (!SF_IsReverseCOMStub(m_dwStubFlags) && (CORProfilerTrackTransitions() || SF_IsNGENedStubForProfiling(m_dwStubFlags)))
899 dwMethodDescLocalNum = m_slIL.EmitProfilerBeginTransitionCallback(pcsDispatch, m_dwStubFlags);
900 _ASSERTE(dwMethodDescLocalNum != -1);
902 #endif // PROFILING_SUPPORTED
905 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
906 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
908 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
910 #endif // MDA_SUPPORTED
912 // For CoreClr, clear the last error before calling the target that returns last error.
913 // There isn't always a way to know the function have failed without checking last error,
914 // in particular on Unix.
915 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
917 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CLEAR_LAST_ERROR, 0, 0);
920 // Invoke the target (calli, call method, call delegate, get/set field, etc.)
921 EmitInvokeTarget(pStubMD);
923 // Saving last error must be the first thing we do after returning from the target
924 if (m_fSetLastError && SF_IsForwardStub(m_dwStubFlags))
926 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__SET_LAST_ERROR, 0, 0);
929 #if defined(_TARGET_X86_)
930 if (SF_IsForwardDelegateStub(m_dwStubFlags))
932 // the delegate may have an intercept stub attached to its sync block so we should
933 // prevent it from being garbage collected when the call is in progress
934 pcsDispatch->EmitLoadThis();
935 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
937 #endif // defined(_TARGET_X86_)
940 if (SF_IsForwardStub(m_dwStubFlags) && !SF_IsNGENedStub(m_dwStubFlags) &&
941 MDA_GET_ASSISTANT(GcUnmanagedToManaged))
943 m_slIL.EmitCallGcCollectForMDA(pcsDispatch, m_dwStubFlags);
945 #endif // MDA_SUPPORTED
948 if (SF_IsForwardStub(m_dwStubFlags) && g_pConfig->InteropValidatePinnedObjects())
950 // call StubHelpers.ValidateObject/StubHelpers.ValidateByref on pinned locals
951 m_slIL.EmitObjectValidation(pcsDispatch, m_dwStubFlags);
953 #endif // VERIFY_HEAP
955 #if defined(PROFILING_SUPPORTED)
956 // Notify the profiler of return back into the runtime
957 if (dwMethodDescLocalNum != -1)
959 m_slIL.EmitProfilerEndTransitionCallback(pcsDispatch, m_dwStubFlags, dwMethodDescLocalNum);
961 #endif // PROFILING_SUPPORTED
963 #ifdef FEATURE_COMINTEROP
964 if (SF_IsForwardCOMStub(m_dwStubFlags))
966 // Make sure that the RCW stays alive for the duration of the call. Note that if we do HRESULT
967 // swapping, we'll pass 'this' to GetCOMHRExceptionObject after returning from the target so
968 // GC.KeepAlive is not necessary.
969 if (!SF_IsHRESULTSwapping(m_dwStubFlags))
971 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
972 pcsDispatch->EmitCALL(METHOD__GC__KEEP_ALIVE, 1, 0);
975 #endif // FEATURE_COMINTEROP
977 if (SF_IsHRESULTSwapping(m_dwStubFlags))
979 if (SF_IsForwardStub(m_dwStubFlags))
981 ILCodeLabel* pSkipThrowLabel = pcsDispatch->NewCodeLabel();
983 pcsDispatch->EmitDUP();
984 pcsDispatch->EmitLDC(0);
985 pcsDispatch->EmitBGE(pSkipThrowLabel);
987 #ifdef FEATURE_COMINTEROP
988 if (SF_IsCOMStub(m_dwStubFlags))
990 m_slIL.EmitLoadStubContext(pcsDispatch, m_dwStubFlags);
991 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
993 if (SF_IsWinRTStub(m_dwStubFlags))
995 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT_WINRT, 3, 1);
999 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_COM_HR_EXCEPTION_OBJECT, 3, 1);
1003 #endif // FEATURE_COMINTEROP
1005 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_HR_EXCEPTION_OBJECT, 1, 1);
1008 pcsDispatch->EmitTHROW();
1009 pcsDispatch->EmitLDC(0); // keep the IL stack balanced across the branch and the fall-through
1010 pcsDispatch->EmitLabel(pSkipThrowLabel);
1011 pcsDispatch->EmitPOP();
1015 m_slIL.End(m_dwStubFlags);
1016 if (!hasTryCatchForHRESULT) // we will 'leave' the try scope and then 'ret' from outside
1018 pcsUnmarshal->EmitRET();
1021 CORJIT_FLAGS jitFlags(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB);
1023 if (m_slIL.HasInteropParamExceptionInfo())
1025 // This code will not use the secret parameter, so we do not
1026 // tell the JIT to bother with it.
1028 m_slIL.GenerateInteropParamException(pcsMarshal);
1030 else if (SF_IsFieldGetterStub(m_dwStubFlags) || SF_IsFieldSetterStub(m_dwStubFlags))
1032 // Field access stubs are not shared and do not use the secret parameter.
1035 else if (SF_IsForwardDelegateStub(m_dwStubFlags) ||
1036 (SF_IsForwardCOMStub(m_dwStubFlags) && SF_IsWinRTDelegateStub(m_dwStubFlags)))
1038 // Forward delegate stubs get all the context they need in 'this' so they
1039 // don't use the secret parameter. Except for AMD64 where we use the secret
1040 // argument to pass the real target to the stub-for-host.
1045 // All other IL stubs will need to use the secret parameter.
1046 jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_PUBLISH_SECRET_PARAM);
1049 if (SF_IsReverseStub(m_dwStubFlags))
1051 SwapStubSignatures(pStubMD);
1054 ILCodeLabel* pTryEndAndCatchBeginLabel = NULL; // try ends at the same place the catch begins
1055 ILCodeLabel* pCatchEndAndReturnLabel = NULL; // catch ends at the same place we resume afterwards
1056 #ifdef FEATURE_COMINTEROP
1057 if (hasTryCatchForHRESULT)
1059 EmitExceptionHandler(&nativeReturnType, &managedReturnType, &pTryEndAndCatchBeginLabel, &pCatchEndAndReturnLabel);
1061 #endif // FEATURE_COMINTEROP
1069 cbCode = m_slIL.Link(&maxStack);
1070 cbSig = m_slIL.GetLocalSigSize();
1072 ILStubResolver * pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
1073 COR_ILMETHOD_DECODER * pILHeader = pResolver->AllocGeneratedIL(cbCode, cbSig, maxStack);
1074 pbBuffer = (BYTE *)pILHeader->Code;
1075 pbLocalSig = (BYTE *)pILHeader->LocalVarSig;
1076 _ASSERTE(cbSig == pILHeader->cbLocalVarSig);
1078 ILStubEHClause cleanupTryFinally = { 0 };
1079 ILStubEHClause convertToHRTryCatch = { 0 };
1080 m_slIL.GetCleanupFinallyOffsets(&cleanupTryFinally);
1082 #ifdef FEATURE_COMINTEROP
1083 if (hasTryCatchForHRESULT)
1085 convertToHRTryCatch.kind = ILStubEHClause::kTypedCatch;
1086 convertToHRTryCatch.dwTryBeginOffset = 0;
1087 convertToHRTryCatch.dwHandlerBeginOffset = ((DWORD)pTryEndAndCatchBeginLabel->GetCodeOffset());
1088 convertToHRTryCatch.cbTryLength = convertToHRTryCatch.dwHandlerBeginOffset - convertToHRTryCatch.dwTryBeginOffset;
1089 convertToHRTryCatch.cbHandlerLength = ((DWORD)pCatchEndAndReturnLabel->GetCodeOffset()) - convertToHRTryCatch.dwHandlerBeginOffset;
1090 convertToHRTryCatch.dwTypeToken = pcsDispatch->GetToken(g_pObjectClass);
1092 #endif // FEATURE_COMINTEROP
1096 if (convertToHRTryCatch.cbHandlerLength != 0)
1099 if (cleanupTryFinally.cbHandlerLength != 0)
1104 COR_ILMETHOD_SECT_EH* pEHSect = pResolver->AllocEHSect(nEHClauses);
1105 PopulateEHSect(pEHSect, nEHClauses, &cleanupTryFinally, &convertToHRTryCatch);
1108 m_slIL.GenerateCode(pbBuffer, cbCode);
1109 m_slIL.GetLocalSig(pbLocalSig, cbSig);
1111 pResolver->SetJitFlags(jitFlags);
1114 LOG((LF_STUBS, LL_INFO1000, "---------------------------------------------------------------------\n"));
1115 LOG((LF_STUBS, LL_INFO1000, "NDirect IL stub dump: %s::%s\n", pStubMD->m_pszDebugClassName, pStubMD->m_pszDebugMethodName));
1116 if (LoggingEnabled() && LoggingOn(LF_STUBS, LL_INFO1000))
1118 CQuickBytes qbManaged;
1119 CQuickBytes qbLocal;
1121 PCCOR_SIGNATURE pManagedSig;
1124 IMDInternalImport* pIMDI = MscorlibBinder::GetModule()->GetMDImport();
1126 pStubMD->GetSig(&pManagedSig, &cManagedSig);
1128 PrettyPrintSig(pManagedSig, cManagedSig, "*", &qbManaged, pStubMD->GetMDImport(), NULL);
1129 PrettyPrintSig(pbLocalSig, cbSig, NULL, &qbLocal, pIMDI, NULL);
1131 LOG((LF_STUBS, LL_INFO1000, "incoming managed sig: %p: %s\n", pManagedSig, qbManaged.Ptr()));
1132 LOG((LF_STUBS, LL_INFO1000, "locals sig: %p: %s\n", pbLocalSig+1, qbLocal.Ptr()));
1134 if (cleanupTryFinally.cbHandlerLength != 0)
1136 LOG((LF_STUBS, LL_INFO1000, "try_begin: 0x%04x try_end: 0x%04x finally_begin: 0x%04x finally_end: 0x%04x \n",
1137 cleanupTryFinally.dwTryBeginOffset, cleanupTryFinally.dwTryBeginOffset + cleanupTryFinally.cbTryLength,
1138 cleanupTryFinally.dwHandlerBeginOffset, cleanupTryFinally.dwHandlerBeginOffset + cleanupTryFinally.cbHandlerLength));
1140 if (convertToHRTryCatch.cbHandlerLength != 0)
1142 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",
1143 convertToHRTryCatch.dwTryBeginOffset, convertToHRTryCatch.dwTryBeginOffset + convertToHRTryCatch.cbTryLength,
1144 convertToHRTryCatch.dwHandlerBeginOffset, convertToHRTryCatch.dwHandlerBeginOffset + convertToHRTryCatch.cbHandlerLength,
1145 convertToHRTryCatch.dwTypeToken));
1148 LogILStubFlags(LF_STUBS, LL_INFO1000, m_dwStubFlags);
1150 m_slIL.LogILStub(jitFlags);
1152 LOG((LF_STUBS, LL_INFO1000, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
1159 //---------------------------------------------------------------------------------------
1161 static inline void LogOneFlag(DWORD flags, DWORD flag, LPCSTR str, DWORD facility, DWORD level)
1163 LIMITED_METHOD_CONTRACT;
1166 LOG((facility, level, str));
1170 static void LogILStubFlags(DWORD facility, DWORD level, DWORD dwStubFlags)
1172 LIMITED_METHOD_CONTRACT;
1173 LOG((facility, level, "dwStubFlags: 0x%08x\n", dwStubFlags));
1174 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_CONVSIGASVARARG, " NDIRECTSTUB_FL_CONVSIGASVARARG\n", facility, level);
1175 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_BESTFIT, " NDIRECTSTUB_FL_BESTFIT\n", facility, level);
1176 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR, " NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR\n", facility, level);
1177 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUB, " NDIRECTSTUB_FL_NGENEDSTUB\n", facility, level);
1178 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DELEGATE, " NDIRECTSTUB_FL_DELEGATE\n", facility, level);
1179 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_DOHRESULTSWAPPING, " NDIRECTSTUB_FL_DOHRESULTSWAPPING\n", facility, level);
1180 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_REVERSE_INTEROP, " NDIRECTSTUB_FL_REVERSE_INTEROP\n", facility, level);
1181 #ifdef FEATURE_COMINTEROP
1182 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_COM, " NDIRECTSTUB_FL_COM\n", facility, level);
1183 #endif // FEATURE_COMINTEROP
1184 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING, " NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING\n", facility, level);
1185 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL, " NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL\n", facility, level);
1186 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_HASDECLARATIVESECURITY, " NDIRECTSTUB_FL_HASDECLARATIVESECURITY\n", facility, level);
1187 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_UNMANAGED_CALLI, " NDIRECTSTUB_FL_UNMANAGED_CALLI\n", facility, level);
1188 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_TRIGGERCCTOR, " NDIRECTSTUB_FL_TRIGGERCCTOR\n", facility, level);
1189 #ifdef FEATURE_COMINTEROP
1190 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDGETTER, " NDIRECTSTUB_FL_FIELDGETTER\n", facility, level);
1191 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_FIELDSETTER, " NDIRECTSTUB_FL_FIELDSETTER\n", facility, level);
1192 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRT, " NDIRECTSTUB_FL_WINRT\n", facility, level);
1193 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTDELEGATE, " NDIRECTSTUB_FL_WINRTDELEGATE\n", facility, level);
1194 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSHAREDGENERIC, " NDIRECTSTUB_FL_WINRTSHAREDGENERIC\n", facility, level);
1195 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCTOR, " NDIRECTSTUB_FL_WINRTCTOR\n", facility, level);
1196 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTCOMPOSITION, " NDIRECTSTUB_FL_WINRTCOMPOSITION\n", facility, level);
1197 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTSTATIC, " NDIRECTSTUB_FL_WINRTSTATIC\n", facility, level);
1198 LogOneFlag(dwStubFlags, NDIRECTSTUB_FL_WINRTHASREDIRECTION, " NDIRECTSTUB_FL_WINRTHASREDIRECTION\n", facility, level);
1199 #endif // FEATURE_COMINTEROP
1202 // no need to log the internal flags, let's just assert what we expect to see...
1204 CONSISTENCY_CHECK(!SF_IsCOMLateBoundStub(dwStubFlags));
1205 CONSISTENCY_CHECK(!SF_IsCOMEventCallStub(dwStubFlags));
1208 NDIRECTSTUB_FL_CONVSIGASVARARG |
1209 NDIRECTSTUB_FL_BESTFIT |
1210 NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR |
1211 NDIRECTSTUB_FL_NGENEDSTUB |
1212 NDIRECTSTUB_FL_DELEGATE |
1213 NDIRECTSTUB_FL_DOHRESULTSWAPPING |
1214 NDIRECTSTUB_FL_REVERSE_INTEROP |
1215 NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING |
1216 NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL |
1217 NDIRECTSTUB_FL_HASDECLARATIVESECURITY |
1218 NDIRECTSTUB_FL_UNMANAGED_CALLI |
1219 NDIRECTSTUB_FL_TRIGGERCCTOR |
1220 #ifdef FEATURE_COMINTEROP
1221 NDIRECTSTUB_FL_COM |
1222 NDIRECTSTUB_FL_COMLATEBOUND | // internal
1223 NDIRECTSTUB_FL_COMEVENTCALL | // internal
1224 NDIRECTSTUB_FL_FIELDGETTER |
1225 NDIRECTSTUB_FL_FIELDSETTER |
1226 NDIRECTSTUB_FL_WINRT |
1227 NDIRECTSTUB_FL_WINRTDELEGATE |
1228 NDIRECTSTUB_FL_WINRTCTOR |
1229 NDIRECTSTUB_FL_WINRTCOMPOSITION |
1230 NDIRECTSTUB_FL_WINRTSTATIC |
1231 NDIRECTSTUB_FL_WINRTHASREDIRECTION |
1232 #endif // FEATURE_COMINTEROP
1235 DWORD dwUnknownFlags = dwStubFlags & ~dwKnownMask;
1236 if (0 != dwUnknownFlags)
1238 LOG((facility, level, "UNKNOWN FLAGS: 0x%08x\n", dwUnknownFlags));
1243 PCCOR_SIGNATURE GetStubTargetMethodSig()
1245 CONTRACT(PCCOR_SIGNATURE)
1248 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
1254 if (!m_qbNativeFnSigBuffer.Size())
1256 DWORD cb = m_slIL.GetStubTargetMethodSigSize();
1257 pb = (BYTE *)m_qbNativeFnSigBuffer.AllocThrows(cb);
1259 m_slIL.GetStubTargetMethodSig(pb, cb);
1263 pb = (BYTE*)m_qbNativeFnSigBuffer.Ptr();
1270 GetStubTargetMethodSigLength()
1272 WRAPPER_NO_CONTRACT;
1274 return m_slIL.GetStubTargetMethodSigSize();
1277 void SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1279 WRAPPER_NO_CONTRACT;
1281 m_slIL.SetStubTargetMethodSig(pSig, cSig);
1282 m_qbNativeFnSigBuffer.Shrink(0);
1285 TokenLookupMap* GetTokenLookupMap() { WRAPPER_NO_CONTRACT; return m_slIL.GetTokenLookupMap(); }
1288 CQuickBytes m_qbNativeFnSigBuffer;
1289 NDirectStubLinker m_slIL;
1290 BOOL m_fSetLastError;
1291 DWORD m_dwStubFlags;
1295 class PInvoke_ILStubState : public ILStubState
1299 PInvoke_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1300 CorPinvokeMap unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
1305 TargetHasThis(dwStubFlags),
1306 StubHasThis(dwStubFlags),
1311 STANDARD_VM_CONTRACT;
1313 if (SF_IsForwardStub(dwStubFlags))
1315 m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
1320 static BOOL TargetHasThis(DWORD dwStubFlags)
1323 // in reverse pinvoke on delegate, the managed target will
1324 // have a 'this' pointer, but the unmanaged signature does
1327 return SF_IsReverseDelegateStub(dwStubFlags);
1330 static BOOL StubHasThis(DWORD dwStubFlags)
1333 // in forward pinvoke on a delegate, the stub will have a
1334 // 'this' pointer, but the unmanaged target will not.
1336 return SF_IsForwardDelegateStub(dwStubFlags);
1340 #ifdef FEATURE_COMINTEROP
1341 class CLRToCOM_ILStubState : public ILStubState
1345 CLRToCOM_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1346 int iLCIDParamIdx, MethodDesc* pTargetMD)
1352 !SF_IsWinRTStaticStub(dwStubFlags), // fStubHasThis
1357 STANDARD_VM_CONTRACT;
1359 if (SF_IsForwardStub(dwStubFlags))
1361 m_slIL.SetCallingConvention(pmCallConvStdcall, SF_IsVarArgStub(dwStubFlags));
1365 void BeginEmit(DWORD dwStubFlags) // CLR to COM IL
1367 STANDARD_VM_CONTRACT;
1369 ILStubState::BeginEmit(dwStubFlags);
1371 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1373 // add the 'this' COM IP parameter to the target CALLI
1374 m_slIL.GetMarshalCodeStream()->SetStubTargetArgType(ELEMENT_TYPE_I, false);
1376 // convert 'this' to COM IP and the target method entry point
1377 m_slIL.EmitLoadRCWThis(pcsDispatch, m_dwStubFlags);
1380 if (SF_IsWinRTDelegateStub(m_dwStubFlags))
1382 // write the stub context (EEImplMethodDesc representing the Invoke)
1383 // into the secret arg so it shows up in the InlinedCallFrame and can
1384 // be used by stub for host
1386 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
1387 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1388 pcsDispatch->EmitSTIND_I();
1389 pcsDispatch->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1394 m_slIL.EmitLoadStubContext(pcsDispatch, dwStubFlags);
1397 pcsDispatch->EmitLDLOCA(m_slIL.GetTargetEntryPointLocalNum());
1399 BinderMethodID getCOMIPMethod;
1400 bool fDoPostCallIPCleanup = true;
1402 if (!SF_IsNGENedStub(dwStubFlags) && NDirect::IsHostHookEnabled())
1404 // always use the non-optimized helper if we are hosted
1405 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1407 else if (SF_IsWinRTStub(dwStubFlags))
1409 // WinRT uses optimized helpers
1410 if (SF_IsWinRTSharedGenericStub(dwStubFlags))
1411 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_SHARED_GENERIC;
1412 else if (SF_IsWinRTDelegateStub(dwStubFlags))
1413 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT_DELEGATE;
1415 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW_WINRT;
1417 // GetCOMIPFromRCW_WinRT, GetCOMIPFromRCW_WinRTSharedGeneric, and GetCOMIPFromRCW_WinRTDelegate
1418 // always cache the COM interface pointer so no post-call cleanup is needed
1419 fDoPostCallIPCleanup = false;
1423 // classic COM interop uses the non-optimized helper
1424 getCOMIPMethod = METHOD__STUBHELPERS__GET_COM_IP_FROM_RCW;
1427 DWORD dwIPRequiresCleanupLocalNum = (DWORD)-1;
1428 if (fDoPostCallIPCleanup)
1430 dwIPRequiresCleanupLocalNum = pcsDispatch->NewLocal(ELEMENT_TYPE_BOOLEAN);
1431 pcsDispatch->EmitLDLOCA(dwIPRequiresCleanupLocalNum);
1433 // StubHelpers.GetCOMIPFromRCW(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget, out bool pfNeedsRelease)
1434 pcsDispatch->EmitCALL(getCOMIPMethod, 4, 1);
1438 // StubHelpers.GetCOMIPFromRCW_WinRT*(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget)
1439 pcsDispatch->EmitCALL(getCOMIPMethod, 3, 1);
1443 // save it because we'll need it to compute the CALLI target and release it
1444 pcsDispatch->EmitDUP();
1445 pcsDispatch->EmitSTLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1447 if (fDoPostCallIPCleanup)
1449 // make sure it's Release()'ed after the call
1450 m_slIL.SetCleanupNeeded();
1451 ILCodeStream *pcsCleanup = m_slIL.GetCleanupCodeStream();
1453 ILCodeLabel *pSkipThisCleanup = pcsCleanup->NewCodeLabel();
1455 // and if it requires cleanup (i.e. it's not taken from the RCW cache)
1456 pcsCleanup->EmitLDLOC(dwIPRequiresCleanupLocalNum);
1457 pcsCleanup->EmitBRFALSE(pSkipThisCleanup);
1459 pcsCleanup->EmitLDLOC(m_slIL.GetTargetInterfacePointerLocalNum());
1460 pcsCleanup->EmitCALL(METHOD__INTERFACEMARSHALER__CLEAR_NATIVE, 1, 0);
1461 pcsCleanup->EmitLabel(pSkipThisCleanup);
1466 class COMToCLR_ILStubState : public ILStubState
1470 COMToCLR_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
1471 int iLCIDParamIdx, MethodDesc* pTargetMD)
1482 STANDARD_VM_CONTRACT;
1485 void BeginEmit(DWORD dwStubFlags) // COM to CLR IL
1487 STANDARD_VM_CONTRACT;
1489 ILStubState::BeginEmit(dwStubFlags);
1491 if (SF_IsWinRTStaticStub(dwStubFlags))
1493 // we are not loading 'this' because the target is static
1494 m_slIL.AdjustTargetStackDeltaForExtraParam();
1499 m_slIL.GetDispatchCodeStream()->EmitLoadThis();
1503 void MarshalFactoryReturn()
1508 PRECONDITION(SF_IsWinRTCtorStub(m_dwStubFlags));
1512 ILCodeStream *pcsSetup = m_slIL.GetSetupCodeStream();
1513 ILCodeStream *pcsDispatch = m_slIL.GetDispatchCodeStream();
1514 ILCodeStream *pcsUnmarshal = m_slIL.GetReturnUnmarshalCodeStream();
1515 ILCodeStream *pcsExCleanup = m_slIL.GetExceptionCleanupCodeStream();
1517 LocalDesc locDescFactoryRetVal(ELEMENT_TYPE_I);
1518 DWORD dwFactoryRetValLocalNum = pcsSetup->NewLocal(locDescFactoryRetVal);
1519 pcsSetup->EmitLoadNullPtr();
1520 pcsSetup->EmitSTLOC(dwFactoryRetValLocalNum);
1522 locDescFactoryRetVal.MakeByRef();
1524 // expect one additional argument - pointer to a location that receives the created instance
1525 DWORD dwRetValArgNum = pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false);
1526 m_slIL.AdjustTargetStackDeltaForExtraParam();
1528 // convert 'this' to an interface pointer corresponding to the default interface of this class
1529 pcsUnmarshal->EmitLoadThis();
1530 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
1531 pcsUnmarshal->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_RETURN_VALUE, 2, 1);
1532 pcsUnmarshal->EmitSTLOC(dwFactoryRetValLocalNum);
1534 // assign it to the location pointed to by the argument
1535 pcsUnmarshal->EmitLDARG(dwRetValArgNum);
1536 pcsUnmarshal->EmitLDLOC(dwFactoryRetValLocalNum);
1537 pcsUnmarshal->EmitSTIND_I();
1539 // on exception, we want to release the IInspectable's and assign NULL to output locations
1540 m_slIL.SetExceptionCleanupNeeded();
1542 EmitInterfaceClearNative(pcsExCleanup, dwFactoryRetValLocalNum);
1545 pcsExCleanup->EmitLDARG(dwRetValArgNum);
1546 pcsExCleanup->EmitLoadNullPtr();
1547 pcsExCleanup->EmitSTIND_I();
1552 class COMToCLRFieldAccess_ILStubState : public COMToCLR_ILStubState
1556 COMToCLRFieldAccess_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext,
1557 DWORD dwStubFlags, FieldDesc* pFD)
1558 : COMToCLR_ILStubState(
1566 STANDARD_VM_CONTRACT;
1568 _ASSERTE(pFD != NULL);
1572 void EmitInvokeTarget(MethodDesc *pStubMD)
1574 STANDARD_VM_CONTRACT;
1576 ILCodeStream* pcsDispatch = m_slIL.GetDispatchCodeStream();
1578 if (SF_IsFieldGetterStub(m_dwStubFlags))
1580 pcsDispatch->EmitLDFLD(pcsDispatch->GetToken(m_pFD));
1584 CONSISTENCY_CHECK(SF_IsFieldSetterStub(m_dwStubFlags));
1585 pcsDispatch->EmitSTFLD(pcsDispatch->GetToken(m_pFD));
1592 #endif // FEATURE_COMINTEROP
1595 NDirectStubLinker::NDirectStubLinker(
1598 const Signature &signature,
1599 SigTypeContext *pTypeContext,
1600 MethodDesc* pTargetMD,
1602 BOOL fTargetHasThis,
1604 : ILStubLinker(pModule, signature, pTypeContext, pTargetMD, fTargetHasThis, fStubHasThis, !SF_IsCOMStub(dwStubFlags)),
1605 m_pCleanupFinallyBeginLabel(NULL),
1606 m_pCleanupFinallyEndLabel(NULL),
1607 m_pSkipExceptionCleanupLabel(NULL),
1608 #ifdef FEATURE_COMINTEROP
1609 m_dwWinRTFactoryObjectLocalNum(-1),
1610 #endif // FEATURE_COMINTEROP
1611 m_fHasCleanupCode(FALSE),
1612 m_fHasExceptionCleanupCode(FALSE),
1613 m_fCleanupWorkListIsSetup(FALSE),
1614 m_dwThreadLocalNum(-1),
1615 m_dwCleanupWorkListLocalNum(-1),
1616 m_dwRetValLocalNum(-1),
1618 m_ErrorParamIdx(-1),
1619 m_iLCIDParamIdx(iLCIDParamIdx),
1620 m_dwStubFlags(dwStubFlags)
1622 STANDARD_VM_CONTRACT;
1625 m_pcsSetup = NewCodeStream(ILStubLinker::kSetup); // do any one-time setup work
1626 m_pcsMarshal = NewCodeStream(ILStubLinker::kMarshal); // marshals arguments
1627 m_pcsDispatch = NewCodeStream(ILStubLinker::kDispatch); // sets up arguments and makes call
1628 m_pcsRetUnmarshal = NewCodeStream(ILStubLinker::kReturnUnmarshal); // unmarshals return value
1629 m_pcsUnmarshal = NewCodeStream(ILStubLinker::kUnmarshal); // unmarshals arguments
1630 m_pcsExceptionCleanup = NewCodeStream(ILStubLinker::kExceptionCleanup); // MAY NOT THROW: goes in a finally and does exception-only cleanup
1631 m_pcsCleanup = NewCodeStream(ILStubLinker::kCleanup); // MAY NOT THROW: goes in a finally and does unconditional cleanup
1635 m_dwArgMarshalIndexLocalNum = NewLocal(ELEMENT_TYPE_I4);
1636 m_pcsMarshal->EmitLDC(0);
1637 m_pcsMarshal->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1639 #ifdef FEATURE_COMINTEROP
1641 // Forward COM interop needs a local to hold target interface pointer
1643 if (SF_IsForwardCOMStub(m_dwStubFlags))
1645 m_dwTargetEntryPointLocalNum = NewLocal(ELEMENT_TYPE_I);
1646 m_dwTargetInterfacePointerLocalNum = NewLocal(ELEMENT_TYPE_I);
1647 m_pcsSetup->EmitLoadNullPtr();
1648 m_pcsSetup->EmitSTLOC(m_dwTargetInterfacePointerLocalNum);
1650 #endif // FEATURE_COMINTEROP
1653 void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg)
1655 LIMITED_METHOD_CONTRACT;
1656 ULONG uNativeCallingConv = 0;
1658 #if !defined(_TARGET_X86_)
1661 // The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM:
1662 // any float values must be duplicated in the corresponding general-purpose registers.
1663 uNativeCallingConv = CORINFO_CALLCONV_NATIVEVARARG;
1666 #endif // !_TARGET_X86_
1668 switch (unmngCallConv)
1670 case pmCallConvCdecl:
1671 uNativeCallingConv = CORINFO_CALLCONV_C;
1673 case pmCallConvStdcall:
1674 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1676 case pmCallConvThiscall:
1677 uNativeCallingConv = CORINFO_CALLCONV_THISCALL;
1680 _ASSERTE(!"Invalid calling convention.");
1681 uNativeCallingConv = CORINFO_CALLCONV_STDCALL;
1686 SetStubTargetCallingConv((CorCallingConvention)uNativeCallingConv);
1689 void NDirectStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx)
1691 WRAPPER_NO_CONTRACT;
1694 // This sets our state local variable that tracks the progress of the stub execution.
1695 // In the finally block we test this variable to see what cleanup we need to do. The
1696 // variable starts with the value of 0 and is assigned the following values as the
1699 // CLEANUP_INDEX_ARG0_MARSHAL + 1 - 1st argument marshaled
1700 // CLEANUP_INDEX_ARG0_MARSHAL + 2 - 2nd argument marshaled
1702 // CLEANUP_INDEX_ARG0_MARSHAL + n - nth argument marshaled
1703 // CLEANUP_INDEX_RETVAL_UNMARSHAL + 1 - return value unmarshaled
1704 // CLEANUP_INDEX_ARG0_UNMARSHAL + 1 - 1st argument unmarshaled
1705 // CLEANUP_INDEX_ARG0_UNMARSHAL + 2 - 2nd argument unmarshaled
1707 // CLEANUP_INDEX_ARG0_UNMARSHAL + n - nth argument unmarshaled
1708 // CLEANUP_INDEX_ALL_DONE + 1 - ran to completion, no exception thrown
1710 // Note: There may be gaps, i.e. if say 2nd argument does not need cleanup, the
1711 // state variable will never be assigned the corresponding value. However, the
1712 // value must always monotonically increase so we can use <=, >, etc.
1715 pcsEmit->EmitLDC(uArgIdx + 1);
1716 pcsEmit->EmitSTLOC(m_dwArgMarshalIndexLocalNum);
1719 void NDirectStubLinker::EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel)
1721 STANDARD_VM_CONTRACT;
1725 // See EmitSetArgMarshalIndex.
1726 pcsEmit->EmitLDLOC(m_dwArgMarshalIndexLocalNum);
1727 pcsEmit->EmitLDC(uArgIdx);
1731 case BranchIfMarshaled:
1733 // we branch to the label if the argument has been marshaled
1734 pcsEmit->EmitBGT(pSkipCleanupLabel);
1738 case BranchIfNotMarshaled:
1740 // we branch to the label if the argument has not been marshaled
1741 pcsEmit->EmitBLE(pSkipCleanupLabel);
1750 int NDirectStubLinker::GetLCIDParamIdx()
1752 LIMITED_METHOD_CONTRACT;
1753 return m_iLCIDParamIdx;
1756 ILCodeStream* NDirectStubLinker::GetSetupCodeStream()
1758 LIMITED_METHOD_CONTRACT;
1762 ILCodeStream* NDirectStubLinker::GetMarshalCodeStream()
1764 LIMITED_METHOD_CONTRACT;
1765 return m_pcsMarshal;
1768 ILCodeStream* NDirectStubLinker::GetUnmarshalCodeStream()
1770 LIMITED_METHOD_CONTRACT;
1771 return m_pcsUnmarshal;
1774 ILCodeStream* NDirectStubLinker::GetReturnUnmarshalCodeStream()
1776 LIMITED_METHOD_CONTRACT;
1777 return m_pcsRetUnmarshal;
1780 ILCodeStream* NDirectStubLinker::GetDispatchCodeStream()
1782 LIMITED_METHOD_CONTRACT;
1783 return m_pcsDispatch;
1786 ILCodeStream* NDirectStubLinker::GetCleanupCodeStream()
1788 LIMITED_METHOD_CONTRACT;
1789 return m_pcsCleanup;
1792 ILCodeStream* NDirectStubLinker::GetExceptionCleanupCodeStream()
1794 LIMITED_METHOD_CONTRACT;
1795 return m_pcsExceptionCleanup;
1798 void NDirectStubLinker::AdjustTargetStackDeltaForExtraParam()
1800 LIMITED_METHOD_CONTRACT;
1802 // Compensate for the extra parameter.
1804 m_iTargetStackDelta++;
1807 void NDirectStubLinker::AdjustTargetStackDeltaForReverseInteropHRESULTSwapping()
1809 WRAPPER_NO_CONTRACT;
1811 // In the case of reverse pinvoke, we build up the 'target'
1812 // signature as if it were normal forward pinvoke and then
1813 // switch that signature (representing the native sig) with
1814 // the stub's sig (representing the managed sig). However,
1815 // as a side-effect, our calcualted target stack delta is
1818 // The only way that we support a different stack delta is
1819 // through hresult swapping. So this code "undoes" the
1820 // deltas that would have been applied in that case.
1823 if (StubHasVoidReturnType())
1826 // If the managed return type is void, undo the HRESULT
1827 // return type added to our target sig for HRESULT swapping.
1828 // No extra argument will have been added because it makes
1829 // no sense to add an extry byref void argument.
1831 m_iTargetStackDelta--;
1836 // no longer pop the extra byref argument from the stack
1838 m_iTargetStackDelta++;
1842 void NDirectStubLinker::SetInteropParamExceptionInfo(UINT resID, UINT paramIdx)
1844 LIMITED_METHOD_CONTRACT;
1846 // only keep the first one
1847 if (HasInteropParamExceptionInfo())
1852 m_ErrorResID = resID;
1853 m_ErrorParamIdx = paramIdx;
1856 bool NDirectStubLinker::HasInteropParamExceptionInfo()
1858 LIMITED_METHOD_CONTRACT;
1860 return !(((DWORD)-1 == m_ErrorResID) && ((DWORD)-1 == m_ErrorParamIdx));
1863 void NDirectStubLinker::GenerateInteropParamException(ILCodeStream* pcsEmit)
1865 STANDARD_VM_CONTRACT;
1867 pcsEmit->EmitLDC(m_ErrorResID);
1868 pcsEmit->EmitLDC(m_ErrorParamIdx);
1869 pcsEmit->EmitCALL(METHOD__STUBHELPERS__THROW_INTEROP_PARAM_EXCEPTION, 2, 0);
1871 pcsEmit->EmitLDNULL();
1872 pcsEmit->EmitTHROW();
1875 #ifdef FEATURE_COMINTEROP
1876 DWORD NDirectStubLinker::GetTargetInterfacePointerLocalNum()
1878 LIMITED_METHOD_CONTRACT;
1879 CONSISTENCY_CHECK(m_dwTargetInterfacePointerLocalNum != (DWORD)-1);
1880 return m_dwTargetInterfacePointerLocalNum;
1882 DWORD NDirectStubLinker::GetTargetEntryPointLocalNum()
1884 LIMITED_METHOD_CONTRACT;
1885 CONSISTENCY_CHECK(m_dwTargetEntryPointLocalNum != (DWORD)-1);
1886 return m_dwTargetEntryPointLocalNum;
1889 void NDirectStubLinker::EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags)
1891 STANDARD_VM_CONTRACT;
1893 if (SF_IsForwardStub(dwStubFlags) &&
1894 (SF_IsWinRTCtorStub(dwStubFlags) || SF_IsWinRTStaticStub(dwStubFlags)))
1896 // WinRT ctor/static stubs make the call on the factory object instead of 'this'
1897 if (m_dwWinRTFactoryObjectLocalNum == (DWORD)-1)
1899 m_dwWinRTFactoryObjectLocalNum = NewLocal(ELEMENT_TYPE_OBJECT);
1901 // get the factory object
1902 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
1903 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__GET_WINRT_FACTORY_OBJECT, 1, 1);
1904 m_pcsSetup->EmitSTLOC(m_dwWinRTFactoryObjectLocalNum);
1907 pcsEmit->EmitLDLOC(m_dwWinRTFactoryObjectLocalNum);
1911 pcsEmit->EmitLoadThis();
1914 #endif // FEATURE_COMINTEROP
1916 DWORD NDirectStubLinker::GetCleanupWorkListLocalNum()
1918 LIMITED_METHOD_CONTRACT;
1919 CONSISTENCY_CHECK(m_dwCleanupWorkListLocalNum != (DWORD)-1);
1920 return m_dwCleanupWorkListLocalNum;
1923 DWORD NDirectStubLinker::GetThreadLocalNum()
1925 STANDARD_VM_CONTRACT;
1927 if (m_dwThreadLocalNum == (DWORD)-1)
1929 // The local is created and initialized lazily when first asked.
1930 m_dwThreadLocalNum = NewLocal(ELEMENT_TYPE_I);
1931 m_pcsSetup->EmitCALL(METHOD__THREAD__INTERNAL_GET_CURRENT_THREAD, 0, 1);
1932 m_pcsSetup->EmitSTLOC(m_dwThreadLocalNum);
1935 return m_dwThreadLocalNum;
1938 DWORD NDirectStubLinker::GetReturnValueLocalNum()
1940 LIMITED_METHOD_CONTRACT;
1941 return m_dwRetValLocalNum;
1944 BOOL NDirectStubLinker::IsCleanupNeeded()
1946 LIMITED_METHOD_CONTRACT;
1948 return (m_fHasCleanupCode || IsCleanupWorkListSetup());
1951 BOOL NDirectStubLinker::IsExceptionCleanupNeeded()
1953 LIMITED_METHOD_CONTRACT;
1955 return m_fHasExceptionCleanupCode;
1958 void NDirectStubLinker::InitCleanupCode()
1963 PRECONDITION(NULL == m_pCleanupFinallyBeginLabel);
1967 m_pCleanupFinallyBeginLabel = NewCodeLabel();
1968 m_pcsExceptionCleanup->EmitLabel(m_pCleanupFinallyBeginLabel);
1971 void NDirectStubLinker::InitExceptionCleanupCode()
1976 PRECONDITION(NULL == m_pSkipExceptionCleanupLabel);
1982 // we want to skip the entire exception cleanup if no exception has been thrown
1983 m_pSkipExceptionCleanupLabel = NewCodeLabel();
1984 EmitCheckForArgCleanup(m_pcsExceptionCleanup, CLEANUP_INDEX_ALL_DONE, BranchIfMarshaled, m_pSkipExceptionCleanupLabel);
1987 void NDirectStubLinker::SetCleanupNeeded()
1989 WRAPPER_NO_CONTRACT;
1991 if (!m_fHasCleanupCode)
1993 m_fHasCleanupCode = TRUE;
1998 void NDirectStubLinker::SetExceptionCleanupNeeded()
2000 WRAPPER_NO_CONTRACT;
2002 if (!m_fHasExceptionCleanupCode)
2004 m_fHasExceptionCleanupCode = TRUE;
2005 InitExceptionCleanupCode();
2009 void NDirectStubLinker::NeedsCleanupList()
2011 STANDARD_VM_CONTRACT;
2013 if (!IsCleanupWorkListSetup())
2015 m_fCleanupWorkListIsSetup = TRUE;
2018 // we setup a new local that will hold the cleanup work list
2019 LocalDesc desc(MscorlibBinder::GetClass(CLASS__CLEANUP_WORK_LIST));
2020 m_dwCleanupWorkListLocalNum = NewLocal(desc);
2025 BOOL NDirectStubLinker::IsCleanupWorkListSetup ()
2027 LIMITED_METHOD_CONTRACT;
2029 return m_fCleanupWorkListIsSetup;
2033 void NDirectStubLinker::LoadCleanupWorkList(ILCodeStream* pcsEmit)
2035 STANDARD_VM_CONTRACT;
2038 pcsEmit->EmitLDLOCA(GetCleanupWorkListLocalNum());
2042 void NDirectStubLinker::Begin(DWORD dwStubFlags)
2044 STANDARD_VM_CONTRACT;
2046 #ifdef FEATURE_COMINTEROP
2047 if (SF_IsWinRTHasRedirection(dwStubFlags))
2049 _ASSERTE(SF_IsForwardCOMStub(dwStubFlags));
2051 // The very first thing we need to do is check whether the call should be routed to
2052 // the marshaling stub for the corresponding projected WinRT interface. If so, we
2054 m_pcsSetup->EmitLoadThis();
2055 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2056 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__SHOULD_CALL_WINRT_INTERFACE, 2, 1);
2058 ILCodeLabel *pNoRedirection = m_pcsSetup->NewCodeLabel();
2059 m_pcsSetup->EmitBRFALSE(pNoRedirection);
2061 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(
2063 TypeHandle::Interop_ManagedToNative);
2065 CONSISTENCY_CHECK(pAdapterMD != NULL && !pAdapterMD->HasMethodInstantiation());
2067 m_pcsSetup->EmitJMP(m_pcsSetup->GetToken(pAdapterMD));
2069 m_pcsSetup->EmitLabel(pNoRedirection);
2071 #endif // FEATURE_COMINTEROP
2073 if (SF_IsForwardStub(dwStubFlags))
2076 if (SF_IsStubWithCctorTrigger(dwStubFlags))
2078 EmitLoadStubContext(m_pcsSetup, dwStubFlags);
2079 m_pcsSetup->EmitCALL(METHOD__STUBHELPERS__INIT_DECLARING_TYPE, 1, 0);
2084 #ifdef MDA_SUPPORTED
2085 if (!SF_IsNGENedStub(dwStubFlags) && MDA_GET_ASSISTANT(GcUnmanagedToManaged))
2087 EmitCallGcCollectForMDA(m_pcsSetup, dwStubFlags);
2089 #endif // MDA_SUPPORTED
2091 if (SF_IsDelegateStub(dwStubFlags))
2093 #if defined(MDA_SUPPORTED)
2094 // GC was induced (gcUnmanagedToManagedMDA), arguments have been marshaled, and we are about
2095 // to touch the UMEntryThunk and extract the delegate target from it so this is the right time
2096 // to do the collected delegate MDA check.
2098 // The call to CheckCollectedDelegateMDA is emitted regardless of whether the MDA is on at the
2099 // moment. This is to avoid having to ignore NGENed stubs without the call just as we do for
2100 // the GC MDA (callbackOncollectedDelegateMDA is turned on under managed debugger by default
2101 // so the impact would be substantial). The helper bails out fast if the MDA is not enabled.
2102 EmitLoadStubContext(m_pcsDispatch, dwStubFlags);
2103 m_pcsDispatch->EmitCALL(METHOD__STUBHELPERS__CHECK_COLLECTED_DELEGATE_MDA, 1, 0);
2104 #endif // MDA_SUPPORTED
2107 // recover delegate object from UMEntryThunk
2109 EmitLoadStubContext(m_pcsDispatch, dwStubFlags); // load UMEntryThunk*
2111 m_pcsDispatch->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2112 m_pcsDispatch->EmitADD();
2113 m_pcsDispatch->EmitLDIND_I(); // get OBJECTHANDLE
2114 m_pcsDispatch->EmitLDIND_REF(); // get Delegate object
2115 m_pcsDispatch->EmitLDFLD(GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__TARGET)));
2119 m_pCleanupTryBeginLabel = NewCodeLabel();
2120 m_pcsMarshal->EmitLabel(m_pCleanupTryBeginLabel);
2123 void NDirectStubLinker::End(DWORD dwStubFlags)
2125 STANDARD_VM_CONTRACT;
2127 ILCodeStream* pcs = m_pcsUnmarshal;
2129 bool hasTryCatchForHRESULT = SF_IsReverseCOMStub(dwStubFlags)
2130 && !SF_IsFieldGetterStub(dwStubFlags)
2131 && !SF_IsFieldSetterStub(dwStubFlags);
2134 // Create a local for the return value and store the return value in it.
2136 if (IsCleanupNeeded() || hasTryCatchForHRESULT)
2138 // Save the return value if necessary, since the IL stack will be emptied when we leave a try block.
2139 LocalDesc locDescRetVal;
2140 if (SF_IsForwardStub(dwStubFlags))
2142 GetStubReturnType(&locDescRetVal);
2146 GetStubTargetReturnType(&locDescRetVal);
2149 if (!( (locDescRetVal.cbType == 1) && (locDescRetVal.ElementType[0] == ELEMENT_TYPE_VOID) ))
2151 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2152 if (SF_IsReverseStub(dwStubFlags) && StubHasVoidReturnType())
2154 // if the target returns void and we are doing HRESULT swapping, S_OK is loaded
2155 // in the unmarshal stream
2156 m_pcsUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2160 // otherwise the return value is loaded in the return unmarshal stream
2161 m_pcsRetUnmarshal->EmitSTLOC(m_dwRetValLocalNum);
2164 else if (hasTryCatchForHRESULT && (locDescRetVal.ElementType[0] != ELEMENT_TYPE_VOID))
2166 m_dwRetValLocalNum = m_pcsRetUnmarshal->NewLocal(locDescRetVal);
2171 // Emit end-of-try and end-of-finally code for the try/finally
2173 if (IsCleanupNeeded())
2175 m_pCleanupFinallyEndLabel = NewCodeLabel();
2176 m_pCleanupTryEndLabel = NewCodeLabel();
2178 if (IsExceptionCleanupNeeded())
2180 // if we made it here, no exception has been thrown
2181 EmitSetArgMarshalIndex(m_pcsUnmarshal, CLEANUP_INDEX_ALL_DONE);
2184 // Emit a leave at the end of the try block. If we have an outer try/catch, we need
2185 // to leave to the beginning of the ExceptionHandler code stream, which follows the
2186 // Cleanup code stream. If we don't, we can just leave to the tail end of the
2187 // Unmarshal code stream where we'll emit our RET.
2189 ILCodeLabel* pLeaveTarget = m_pCleanupTryEndLabel;
2190 if (hasTryCatchForHRESULT)
2192 pLeaveTarget = m_pCleanupFinallyEndLabel;
2195 m_pcsUnmarshal->EmitLEAVE(pLeaveTarget);
2196 m_pcsUnmarshal->EmitLabel(m_pCleanupTryEndLabel);
2198 // Emit a call to destroy the clean-up list if needed.
2199 if (IsCleanupWorkListSetup())
2201 LoadCleanupWorkList(m_pcsCleanup);
2202 m_pcsCleanup->EmitCALL(METHOD__STUBHELPERS__DESTROY_CLEANUP_LIST, 1, 0);
2205 // Emit the endfinally.
2206 m_pcsCleanup->EmitENDFINALLY();
2207 m_pcsCleanup->EmitLabel(m_pCleanupFinallyEndLabel);
2210 #ifdef MDA_SUPPORTED
2211 if (SF_IsReverseStub(dwStubFlags) && !SF_IsNGENedStub(dwStubFlags) &&
2212 MDA_GET_ASSISTANT(GcManagedToUnmanaged))
2214 EmitCallGcCollectForMDA(pcs, dwStubFlags);
2216 #endif // MDA_SUPPORTED
2218 if (IsExceptionCleanupNeeded())
2220 m_pcsExceptionCleanup->EmitLabel(m_pSkipExceptionCleanupLabel);
2223 // Reload the return value
2224 if ((m_dwRetValLocalNum != (DWORD)-1) && !hasTryCatchForHRESULT)
2226 pcs->EmitLDLOC(m_dwRetValLocalNum);
2230 void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD)
2232 STANDARD_VM_CONTRACT;
2233 if (SF_IsForwardStub(dwStubFlags)) // managed-to-native
2236 if (SF_IsDelegateStub(dwStubFlags)) // delegate invocation
2238 // get the delegate unmanaged target - we call a helper instead of just grabbing
2239 // the _methodPtrAux field because we may need to intercept the call for host, MDA, etc.
2240 pcsEmit->EmitLoadThis();
2242 // on AMD64 GetDelegateTarget will return address of the generic stub for host when we are hosted
2243 // and update the secret argument with real target - the secret arg will be embedded in the
2244 // InlinedCallFrame by the JIT and fetched via TLS->Thread->Frame->Datum by the stub for host
2245 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT_ADDR, 0, 1);
2247 // we don't need to do this on x86 because stub for host is generated dynamically per target
2248 pcsEmit->EmitLDNULL();
2250 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_TARGET, 2, 1);
2252 else // direct invocation
2254 if (SF_IsCALLIStub(dwStubFlags)) // unmanaged CALLI
2256 // if we ever NGEN CALLI stubs, this would have to be done differently
2257 _ASSERTE(!SF_IsNGENedStub(dwStubFlags));
2259 #ifndef CROSSGEN_COMPILE
2264 // for managed-to-unmanaged CALLI that requires marshaling, the target is passed
2265 // as the secret argument to the stub by GenericPInvokeCalliHelper (asmhelpers.asm)
2266 EmitLoadStubContext(pcsEmit, dwStubFlags);
2269 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2270 if (NDirect::IsHostHookEnabled())
2272 // we need to call to the host hook, real target is passed as the last argument
2273 Stub *pHostStub = NDirect::GenerateStubForHost(
2275 (CorUnmanagedCallingConvention)(GetStubTargetCallingConv() & IMAGE_CEE_CS_CALLCONV_MASK),
2276 pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize());
2278 pcsEmit->EmitLDC((DWORD_PTR)pHostStub->GetEntryPoint());
2280 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2282 #else // _TARGET_X86_
2284 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
2285 if (NDirect::IsHostHookEnabled())
2287 // the stub for host will get the original target from the secret arg
2288 pcsEmit->EmitLDC((DWORD_PTR)GetEEFuncEntryPoint(PInvokeStubForHost));
2291 #endif // FEATURE_INCLUDE_ALL_INTERFACES
2293 // the secret arg has been shifted to left and ORed with 1 (see code:GenericPInvokeCalliHelper)
2294 EmitLoadStubContext(pcsEmit, dwStubFlags);
2295 #ifndef _TARGET_ARM_
2296 pcsEmit->EmitLDC(1);
2297 pcsEmit->EmitSHR_UN();
2301 #endif // _TARGET_X86_
2303 #endif // CROSSGEN_COMPILE
2306 #ifdef FEATURE_COMINTEROP
2307 if (!SF_IsCOMStub(dwStubFlags)) // forward P/Invoke
2308 #endif // FEATURE_COMINTEROP
2310 EmitLoadStubContext(pcsEmit, dwStubFlags);
2313 // Perf: inline the helper for now
2314 //pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_NDIRECT_TARGET, 1, 1);
2315 pcsEmit->EmitLDC(offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
2317 pcsEmit->EmitLDIND_I();
2318 pcsEmit->EmitLDIND_I();
2321 #ifdef FEATURE_COMINTEROP
2324 // this is a CLR -> COM call
2325 // the target has been computed by StubHelpers::GetCOMIPFromRCW
2326 pcsEmit->EmitLDLOC(m_dwTargetEntryPointLocalNum);
2328 #endif // FEATURE_COMINTEROP
2331 else // native-to-managed
2333 if (SF_IsDelegateStub(dwStubFlags)) // reverse P/Invoke via delegate
2335 int tokDelegate_methodPtr = pcsEmit->GetToken(MscorlibBinder::GetField(FIELD__DELEGATE__METHOD_PTR));
2337 EmitLoadStubContext(pcsEmit, dwStubFlags);
2338 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2340 pcsEmit->EmitLDIND_I(); // Get OBJECTHANDLE
2341 pcsEmit->EmitLDIND_REF(); // Get Delegate object
2342 pcsEmit->EmitLDFLD(tokDelegate_methodPtr); // get _methodPtr
2344 #ifdef FEATURE_COMINTEROP
2345 else if (SF_IsCOMStub(dwStubFlags)) // COM -> CLR call
2347 // managed target is passed directly in the secret argument
2348 EmitLoadStubContext(pcsEmit, dwStubFlags);
2350 #endif // FEATURE_COMINTEROP
2351 else // direct reverse P/Invoke (CoreCLR hosting)
2353 EmitLoadStubContext(pcsEmit, dwStubFlags);
2354 CONSISTENCY_CHECK(0 == offsetof(UMEntryThunk, m_pManagedTarget)); // if this changes, just add back the EmitLDC/EmitADD below
2355 // pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pManagedTarget));
2356 // pcsEmit->EmitADD();
2357 pcsEmit->EmitLDIND_I(); // Get UMEntryThunk::m_pManagedTarget
2361 // For managed-to-native calls, the rest of the work is done by the JIT. It will
2362 // erect InlinedCallFrame, flip GC mode, and use the specified calling convention
2363 // to call the target. For native-to-managed calls, this is an ordinary managed
2364 // CALLI and nothing special happens.
2365 pcsEmit->EmitCALLI(TOKEN_ILSTUB_TARGET_SIG, 0, m_iTargetStackDelta);
2368 void NDirectStubLinker::EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal)
2370 STANDARD_VM_CONTRACT;
2372 if (SF_IsForwardPInvokeStub(m_dwStubFlags) && !SF_IsForwardDelegateStub(m_dwStubFlags))
2374 // get the secret argument via intrinsic
2375 pslILEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2379 // no secret argument
2380 pslILEmit->EmitLoadNullPtr();
2383 pslILEmit->EmitLDLOC(dwPinnedLocal);
2385 pslILEmit->EmitCALL(METHOD__STUBHELPERS__LOG_PINNED_ARGUMENT, 2, 0);
2388 void NDirectStubLinker::GetCleanupFinallyOffsets(ILStubEHClause * pClause)
2393 PRECONDITION(CheckPointer(pClause));
2397 if (m_pCleanupFinallyEndLabel)
2399 _ASSERTE(m_pCleanupFinallyBeginLabel);
2400 _ASSERTE(m_pCleanupTryBeginLabel);
2401 _ASSERTE(m_pCleanupTryEndLabel);
2403 pClause->kind = ILStubEHClause::kFinally;
2404 pClause->dwTryBeginOffset = (DWORD)m_pCleanupTryBeginLabel->GetCodeOffset();
2405 pClause->cbTryLength = (DWORD)m_pCleanupTryEndLabel->GetCodeOffset() - pClause->dwTryBeginOffset;
2406 pClause->dwHandlerBeginOffset = (DWORD)m_pCleanupFinallyBeginLabel->GetCodeOffset();
2407 pClause->cbHandlerLength = (DWORD)m_pCleanupFinallyEndLabel->GetCodeOffset() - pClause->dwHandlerBeginOffset;
2411 void NDirectStubLinker::ClearCode()
2413 WRAPPER_NO_CONTRACT;
2414 ILStubLinker::ClearCode();
2416 m_pCleanupTryBeginLabel = 0;
2417 m_pCleanupTryEndLabel = 0;
2418 m_pCleanupFinallyBeginLabel = 0;
2419 m_pCleanupFinallyEndLabel = 0;
2422 #ifdef PROFILING_SUPPORTED
2423 DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2425 STANDARD_VM_CONTRACT;
2427 if (SF_IsForwardDelegateStub(dwStubFlags) || SF_IsCALLIStub(dwStubFlags))
2429 // secret argument does not contain MD nor UMEntryThunk
2430 pcsEmit->EmitLoadNullPtr();
2434 EmitLoadStubContext(pcsEmit, dwStubFlags);
2437 if (SF_IsForwardStub(dwStubFlags))
2439 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2443 // we use a null pThread to indicate reverse interop
2444 pcsEmit->EmitLDC(NULL);
2447 // In the unmanaged delegate case, we need the "this" object to retrieve the MD
2448 // in StubHelpers::ProfilerEnterCallback().
2449 if (SF_IsDelegateStub(dwStubFlags))
2451 if (SF_IsForwardStub(dwStubFlags))
2453 pcsEmit->EmitLoadThis();
2457 EmitLoadStubContext(pcsEmit, dwStubFlags); // load UMEntryThunk*
2458 pcsEmit->EmitLDC(offsetof(UMEntryThunk, m_pObjectHandle));
2460 pcsEmit->EmitLDIND_I(); // get OBJECTHANDLE
2461 pcsEmit->EmitLDIND_REF(); // get Delegate object
2466 pcsEmit->EmitLDC(NULL);
2468 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_BEGIN_TRANSITION_CALLBACK, 3, 1);
2470 // Store the MD for StubHelpers::ProfilerLeaveCallback().
2471 DWORD dwMethodDescLocalNum = pcsEmit->NewLocal(ELEMENT_TYPE_I);
2472 pcsEmit->EmitSTLOC(dwMethodDescLocalNum);
2473 return dwMethodDescLocalNum;
2476 void NDirectStubLinker::EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum)
2478 STANDARD_VM_CONTRACT;
2480 pcsEmit->EmitLDLOC(dwMethodDescLocalNum);
2481 if (SF_IsReverseStub(dwStubFlags))
2483 // we use a null pThread to indicate reverse interop
2484 pcsEmit->EmitLDC(NULL);
2488 pcsEmit->EmitLDLOC(GetThreadLocalNum());
2490 pcsEmit->EmitCALL(METHOD__STUBHELPERS__PROFILER_END_TRANSITION_CALLBACK, 2, 0);
2492 #endif // PROFILING_SUPPPORTED
2495 void NDirectStubLinker::EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags)
2497 STANDARD_VM_CONTRACT;
2499 pcsEmit->EmitLDLOC(dwLocalNum);
2501 if (SF_IsDelegateStub(dwStubFlags))
2503 pcsEmit->EmitLoadNullPtr();
2504 pcsEmit->EmitLoadThis();
2506 else if (SF_IsCALLIStub(dwStubFlags))
2508 pcsEmit->EmitLoadNullPtr();
2509 pcsEmit->EmitLDNULL();
2513 // P/Invoke, CLR->COM
2514 EmitLoadStubContext(pcsEmit, dwStubFlags);
2515 pcsEmit->EmitLDNULL();
2520 // StubHelpers.ValidateByref(byref, pMD, pThis)
2521 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_BYREF, 3, 0);
2525 // StubHelpers.ValidateObject(obj, pMD, pThis)
2526 pcsEmit->EmitCALL(METHOD__STUBHELPERS__VALIDATE_OBJECT, 3, 0);
2530 void NDirectStubLinker::EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2532 STANDARD_VM_CONTRACT;
2534 // generate validation callouts for pinned locals
2535 CQuickBytes qbLocalSig;
2536 DWORD cbSig = GetLocalSigSize();
2538 qbLocalSig.AllocThrows(cbSig);
2539 PCOR_SIGNATURE pSig = (PCOR_SIGNATURE)qbLocalSig.Ptr();
2541 GetLocalSig(pSig, cbSig);
2542 SigPointer ptr(pSig, cbSig);
2544 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
2547 IfFailThrow(ptr.GetData(&numLocals));
2549 for (ULONG i = 0; i < numLocals; i++)
2552 IfFailThrow(ptr.PeekByte(&modifier));
2553 if (modifier == ELEMENT_TYPE_PINNED)
2555 IfFailThrow(ptr.GetByte(NULL));
2556 IfFailThrow(ptr.PeekByte(&modifier));
2557 EmitValidateLocal(pcsEmit, i, (modifier == ELEMENT_TYPE_BYREF), dwStubFlags);
2560 IfFailThrow(ptr.SkipExactlyOne());
2563 #endif // VERIFY_HEAP
2565 // Loads the 'secret argument' passed to the stub.
2566 void NDirectStubLinker::EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags)
2568 STANDARD_VM_CONTRACT;
2570 CONSISTENCY_CHECK(!SF_IsForwardDelegateStub(dwStubFlags));
2571 CONSISTENCY_CHECK(!SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags));
2573 #ifdef FEATURE_COMINTEROP
2574 if (SF_IsWinRTDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags))
2576 // we have the delegate 'this' but we need the EEImpl/Instantiated 'Invoke' MD pointer
2577 // (Delegate.GetInvokeMethod does not return exact instantiated MD so we call our own helper)
2578 pcsEmit->EmitLoadThis();
2579 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_DELEGATE_INVOKE_METHOD, 1, 1);
2582 #endif // FEATURE_COMINTEROP
2584 // get the secret argument via intrinsic
2585 pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1);
2589 #ifdef MDA_SUPPORTED
2590 void NDirectStubLinker::EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags)
2592 STANDARD_VM_CONTRACT;
2594 ILCodeLabel *pSkipGcLabel = NULL;
2596 if (SF_IsForwardPInvokeStub(dwStubFlags) &&
2597 !SF_IsDelegateStub(dwStubFlags) &&
2598 !SF_IsCALLIStub(dwStubFlags))
2600 // don't call GC if this is a QCall
2601 EmitLoadStubContext(pcsEmit, dwStubFlags);
2602 pcsEmit->EmitCALL(METHOD__STUBHELPERS__IS_QCALL, 1, 1);
2604 pSkipGcLabel = pcsEmit->NewCodeLabel();
2605 pcsEmit->EmitBRTRUE(pSkipGcLabel);
2608 pcsEmit->EmitCALL(METHOD__STUBHELPERS__TRIGGER_GC_FOR_MDA, 0, 0);
2610 if (pSkipGcLabel != NULL)
2612 pcsEmit->EmitLabel(pSkipGcLabel);
2615 #endif // MDA_SUPPORTED
2617 #ifdef FEATURE_COMINTEROP
2619 class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing calls
2626 WRAPPER_NO_CONTRACT;
2629 void SetLastError(BOOL fSetLastError)
2631 LIMITED_METHOD_CONTRACT;
2633 CONSISTENCY_CHECK(!fSetLastError);
2636 void BeginEmit(DWORD dwStubFlags)
2638 LIMITED_METHOD_CONTRACT;
2640 CONSISTENCY_CHECK(SF_IsCOMStub(dwStubFlags));
2641 m_dwStubFlags = dwStubFlags;
2644 void MarshalReturn(MarshalInfo* pInfo, int argOffset)
2650 PRECONDITION(CheckPointer(pInfo));
2655 void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset)
2660 PRECONDITION(CheckPointer(pInfo));
2664 if (SF_IsCOMLateBoundStub(m_dwStubFlags) && pInfo->GetDispWrapperType() != 0)
2666 m_lateBoundFlags |= ComPlusCallInfo::kRequiresArgumentWrapping;
2670 void MarshalLCID(int argIdx)
2672 LIMITED_METHOD_CONTRACT;
2675 #ifdef FEATURE_COMINTEROP
2676 void MarshalHiddenLengthArgument(MarshalInfo *, BOOL)
2678 LIMITED_METHOD_CONTRACT;
2680 void MarshalFactoryReturn()
2682 LIMITED_METHOD_CONTRACT;
2685 #endif // FEATURE_COMINTEROP
2687 void EmitInvokeTarget(MethodDesc *pStubMD)
2689 LIMITED_METHOD_CONTRACT;
2690 UNREACHABLE_MSG("Should never come to DispatchStubState::EmitInvokeTarget");
2693 void FinishEmit(MethodDesc *pMD)
2695 STANDARD_VM_CONTRACT;
2697 // set flags directly on the interop MD
2698 _ASSERTE(pMD->IsComPlusCall());
2700 ((ComPlusCallMethodDesc *)pMD)->SetLateBoundFlags(m_lateBoundFlags);
2704 DWORD m_dwStubFlags;
2705 BYTE m_lateBoundFlags; // ComPlusCallMethodDesc::Flags
2708 #endif // FEATURE_COMINTEROP
2711 void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
2721 // initialize data members
2723 m_pModule = pModule;
2724 m_callConv = (CorPinvokeMap)0;
2725 SetBestFitMapping (TRUE);
2726 SetThrowOnUnmappableChar (FALSE);
2727 SetLinkFlags (nlfNone);
2728 SetCharSet (nltAnsi);
2731 // assembly/type level m_bestFit & m_bThrowOnUnmappableChar
2733 BOOL bThrowOnUnmappableChar;
2737 EEClass::GetBestFitMapping(pMT, &bBestFit, &bThrowOnUnmappableChar);
2741 ReadBestFitCustomAttribute(m_pModule->GetMDImport(), mdTypeDefNil, &bBestFit, &bThrowOnUnmappableChar);
2744 SetBestFitMapping (bBestFit);
2745 SetThrowOnUnmappableChar (bThrowOnUnmappableChar);
2748 void PInvokeStaticSigInfo::PreInit(MethodDesc* pMD)
2758 PreInit(pMD->GetModule(), pMD->GetMethodTable());
2759 SetIsStatic (pMD->IsStatic());
2760 m_sig = pMD->GetSignature();
2761 if (pMD->IsEEImpl())
2763 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
2764 SetIsDelegateInterop(TRUE);
2768 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
2769 MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError)
2779 DllImportInit(pMD, pLibName, pEntryPointName);
2785 PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOnError)
2793 PRECONDITION(CheckPointer(pMD));
2799 MethodTable * pMT = pMD->GetMethodTable();
2801 if (!pMT->IsDelegate())
2803 DllImportInit(pMD, NULL, NULL);
2807 // initialize data members to defaults
2810 // System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute
2813 CorPinvokeMap callConv = (CorPinvokeMap)0;
2815 HRESULT hRESULT = pMT->GetMDImport()->GetCustomAttributeByName(
2816 pMT->GetCl(), g_UnmanagedFunctionPointerAttribute, (const VOID **)(&pData), (ULONG *)&cData);
2817 IfFailThrow(hRESULT);
2820 CustomAttributeParser ca(pData, cData);
2823 args[0].InitEnum(SERIALIZATION_TYPE_I4, (ULONG)m_callConv);
2825 IfFailGo(ParseKnownCaArgs(ca, args, lengthof(args)));
2827 enum UnmanagedFunctionPointerNamedArgs
2831 MDA_ThrowOnUnmappableChar,
2837 CaNamedArg namedArgs[MDA_Last];
2838 namedArgs[MDA_CharSet].InitI4FieldEnum("CharSet", "System.Runtime.InteropServices.CharSet", (ULONG)GetCharSet());
2839 namedArgs[MDA_BestFitMapping].InitBoolField("BestFitMapping", (ULONG)GetBestFitMapping());
2840 namedArgs[MDA_ThrowOnUnmappableChar].InitBoolField("ThrowOnUnmappableChar", (ULONG)GetThrowOnUnmappableChar());
2841 namedArgs[MDA_SetLastError].InitBoolField("SetLastError", 0);
2842 namedArgs[MDA_PreserveSig].InitBoolField("PreserveSig", 0);
2844 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
2846 callConv = (CorPinvokeMap)(args[0].val.u4 << 8);
2847 CorNativeLinkType nlt = (CorNativeLinkType)0;
2849 // XXX Tue 07/19/2005
2850 // Keep in sync with the handling of CorPInvokeMap in
2851 // PInvokeStaticSigInfo::DllImportInit.
2852 switch( namedArgs[MDA_CharSet].val.u4 )
2856 nlt = nltAnsi; break;
2858 case nltAuto: // Since Win9x isn't supported anymore, nltAuto always represents unicode strings.
2859 nlt = nltUnicode; break;
2861 hr = E_FAIL; goto ErrExit;
2864 SetBestFitMapping (namedArgs[MDA_BestFitMapping].val.u1);
2865 SetThrowOnUnmappableChar (namedArgs[MDA_ThrowOnUnmappableChar].val.u1);
2866 if (namedArgs[MDA_SetLastError].val.u1)
2867 SetLinkFlags ((CorNativeLinkFlags)(nlfLastError | GetLinkFlags()));
2868 if (namedArgs[MDA_PreserveSig].val.u1)
2869 SetLinkFlags ((CorNativeLinkFlags)(nlfNoMangle | GetLinkFlags()));
2875 SetError(IDS_EE_NDIRECT_BADNATL);
2877 InitCallConv(callConv, pMD->IsVarArg());
2883 PInvokeStaticSigInfo::PInvokeStaticSigInfo(
2884 Signature sig, Module* pModule, ThrowOnError throwOnError)
2892 PRECONDITION(CheckPointer(pModule));
2896 PreInit(pModule, NULL);
2898 SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
2899 InitCallConv((CorPinvokeMap)0, FALSE);
2905 void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LPCUTF8 *ppEntryPointName)
2913 PRECONDITION(CheckPointer(pMD));
2915 // These preconditions to prevent multithreaded regression
2916 // where pMD->ndirect.m_szLibName was passed in directly, cleared
2917 // by this API, then accessed on another thread before being reset here.
2918 PRECONDITION(CheckPointer(ppLibName, NULL_OK) && (!ppLibName || *ppLibName == NULL));
2919 PRECONDITION(CheckPointer(ppEntryPointName, NULL_OK) && (!ppEntryPointName || *ppEntryPointName == NULL));
2923 // initialize data members to defaults
2926 // System.Runtime.InteropServices.DllImportAttribute
2927 IMDInternalImport *pInternalImport = pMD->GetMDImport();
2928 CorPinvokeMap mappingFlags = pmMaxValue;
2929 mdModuleRef modref = mdModuleRefNil;
2930 if (FAILED(pInternalImport->GetPinvokeMap(pMD->GetMemberDef(), (DWORD*)&mappingFlags, ppEntryPointName, &modref)))
2932 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
2933 // The guessing heuristic has been broken with NGen for a long time since we stopped loading
2934 // images at NGen time using full LoadLibrary. The DLL references are not resolved correctly
2935 // without full LoadLibrary.
2937 // Disable the heuristic consistently during NGen so that it does not kick in by accident.
2938 if (!IsCompilationProcess())
2939 BestGuessNDirectDefaults(pMD);
2941 InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
2945 // out parameter pEntryPointName
2946 if (ppEntryPointName && *ppEntryPointName == NULL)
2947 *ppEntryPointName = pMD->GetName();
2949 // out parameter pLibName
2950 if (ppLibName != NULL)
2952 if (FAILED(pInternalImport->GetModuleRefProps(modref, ppLibName)))
2954 SetError(IDS_CLASSLOAD_BADFORMAT);
2960 InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
2963 CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
2964 if (bestFitMask == pmBestFitEnabled)
2965 SetBestFitMapping (TRUE);
2966 else if (bestFitMask == pmBestFitDisabled)
2967 SetBestFitMapping (FALSE);
2969 // m_bThrowOnUnmappableChar
2970 CorPinvokeMap unmappableMask = (CorPinvokeMap)(mappingFlags & pmThrowOnUnmappableCharMask);
2971 if (unmappableMask == pmThrowOnUnmappableCharEnabled)
2972 SetThrowOnUnmappableChar (TRUE);
2973 else if (unmappableMask == pmThrowOnUnmappableCharDisabled)
2974 SetThrowOnUnmappableChar (FALSE);
2976 // inkFlags : CorPinvoke -> CorNativeLinkFlags
2977 if (mappingFlags & pmSupportsLastError)
2978 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
2979 if (mappingFlags & pmNoMangle)
2980 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfNoMangle));
2982 // XXX Tue 07/19/2005
2983 // Keep in sync with the handling of CorNativeLinkType in
2984 // PInvokeStaticSigInfo::PInvokeStaticSigInfo.
2986 // charset : CorPinvoke -> CorNativeLinkType
2987 CorPinvokeMap charSetMask = (CorPinvokeMap)(mappingFlags & (pmCharSetNotSpec | pmCharSetAnsi | pmCharSetUnicode | pmCharSetAuto));
2988 if (charSetMask == pmCharSetNotSpec || charSetMask == pmCharSetAnsi)
2990 SetCharSet (nltAnsi);
2992 else if (charSetMask == pmCharSetUnicode || charSetMask == pmCharSetAuto)
2994 // Since Win9x isn't supported anymore, pmCharSetAuto always represents unicode strings.
2995 SetCharSet (nltUnicode);
2999 SetError(IDS_EE_NDIRECT_BADNATL);
3004 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE) // IJW
3006 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3007 static BOOL HeuristicDoesThisLooksLikeAnApiCallHelper(LPBYTE pTarget)
3017 // This code is not that useful anymore since this functionality is already embedded in the VC linker.
3018 // The linker will emit the lasterror flag by default for functions residing in modules that are
3019 // a superset of the list below.
3020 // Look for bug VSWhidbey 241895.
3022 static struct SysDllInfo
3027 } gSysDllInfo[] = {{WINDOWS_KERNEL32_DLLNAME_W, 0, 0},
3029 {W("USER32"), 0, 0},
3030 {W("ADVAPI32"), 0, 0}
3034 for (int i = 0; i < sizeof(gSysDllInfo)/sizeof(*gSysDllInfo); i++)
3036 if (gSysDllInfo[i].pImageBase == 0)
3038 IMAGE_DOS_HEADER *pDos = (IMAGE_DOS_HEADER*)CLRGetModuleHandle(gSysDllInfo[i].pName);
3041 if (pDos->e_magic == VAL16(IMAGE_DOS_SIGNATURE))
3043 IMAGE_NT_HEADERS *pNT = (IMAGE_NT_HEADERS*) (((LPBYTE)pDos) + VAL32(pDos->e_lfanew));
3044 if (pNT->Signature == VAL32(IMAGE_NT_SIGNATURE) &&
3045 pNT->FileHeader.SizeOfOptionalHeader ==
3047 VAL16(sizeof(IMAGE_OPTIONAL_HEADER64))
3049 VAL16(sizeof(IMAGE_OPTIONAL_HEADER32))
3051 && pNT->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
3053 gSysDllInfo[i].dwImageSize = VAL32(pNT->OptionalHeader.SizeOfImage);
3057 gSysDllInfo[i].pImageBase = (LPBYTE)pDos;
3060 if (gSysDllInfo[i].pImageBase != 0 &&
3061 pTarget >= gSysDllInfo[i].pImageBase &&
3062 pTarget < gSysDllInfo[i].pImageBase + gSysDllInfo[i].dwImageSize)
3071 LPBYTE FollowIndirect(LPBYTE pTarget)
3078 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3086 AVInRuntimeImplOkayHolder AVOkay;
3089 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3091 pRet = **(LPBYTE**)(pTarget + 2);
3093 #elif defined(_TARGET_AMD64_)
3094 if (pTarget != NULL && !(pTarget[0] != 0xff || pTarget[1] != 0x25))
3096 INT64 rva = *(INT32*)(pTarget + 2);
3097 pRet = *(LPBYTE*)(pTarget + 6 + rva);
3105 EX_END_CATCH(SwallowAllExceptions);
3110 // This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
3111 BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget)
3121 if (pTarget == NULL)
3124 if (HeuristicDoesThisLooksLikeAnApiCallHelper(pTarget))
3127 LPBYTE pTarget2 = FollowIndirect(pTarget);
3130 // jmp [xxxx] - could be an import thunk
3131 return HeuristicDoesThisLooksLikeAnApiCallHelper( pTarget2 );
3137 BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
3147 static LPBYTE pGetLastError = NULL;
3150 // No need to use a holder here, since no cleanup is necessary.
3151 HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
3154 pGetLastError = (LPBYTE)GetProcAddress(hMod, "GetLastError");
3157 // This should never happen but better to be cautious.
3158 pGetLastError = (LPBYTE)-1;
3163 // We failed to get the module handle for kernel32.dll. This is almost impossible
3164 // however better to err on the side of caution.
3165 pGetLastError = (LPBYTE)-1;
3169 if (pTarget == pGetLastError)
3172 if (pTarget == NULL)
3175 LPBYTE pTarget2 = FollowIndirect(pTarget);
3178 // jmp [xxxx] - could be an import thunk
3179 return pTarget2 == pGetLastError;
3185 DWORD __stdcall FalseGetLastError()
3187 WRAPPER_NO_CONTRACT;
3189 return GetThread()->m_dwLastError;
3192 void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
3202 if (!pMD->IsNDirect())
3205 NDirectMethodDesc* pMDD = (NDirectMethodDesc*)pMD;
3207 if (!pMDD->IsEarlyBound())
3210 LPVOID pTarget = NULL;
3212 // NOTE: If we get inside this block, and this is a call to GetLastError,
3213 // then InitEarlyBoundNDirectTarget has not been run yet.
3214 if (pMDD->NDirectTargetIsImportThunk())
3216 // Get the unmanaged callsite.
3217 pTarget = (LPVOID)pMDD->GetModule()->GetInternalPInvokeTarget(pMDD->GetRVA());
3219 // If this is a call to GetLastError, then we haven't overwritten m_pNativeNDirectTarget yet.
3220 if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)pTarget))
3221 pTarget = (BYTE*) FalseGetLastError;
3225 pTarget = pMDD->GetNativeNDirectTarget();
3228 if (HeuristicDoesThisLooksLikeAnApiCall((LPBYTE) pTarget))
3229 SetLinkFlags ((CorNativeLinkFlags)(GetLinkFlags() | nlfLastError));
3232 #endif // FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
3235 void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
3245 // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
3246 if (callConv == pmCallConvWinapi)
3247 callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3249 CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
3250 BOOL fSuccess = MetaSig::GetUnmanagedCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv);
3254 SetError(IDS_EE_NDIRECT_BADNATL); //Bad metadata format
3257 // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
3258 // to do this before we check to make sure the PInvoke map calling convention and the
3259 // signature calling convention match for compatibility reasons.
3260 if (sigCallConv == pmCallConvWinapi)
3261 sigCallConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3263 if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
3264 SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
3266 if (callConv == 0 && sigCallConv == 0)
3267 m_callConv = bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
3268 else if (callConv != 0)
3269 m_callConv = callConv;
3271 m_callConv = sigCallConv;
3273 if (bIsVarArg && m_callConv != pmCallConvCdecl)
3274 SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
3277 void PInvokeStaticSigInfo::ReportErrors()
3288 COMPlusThrow(kTypeLoadException, m_error);
3292 //---------------------------------------------------------
3293 // Does a class or method have a NAT_L CustomAttribute?
3297 // FAILED = unknown because something failed.
3298 //---------------------------------------------------------
3300 HRESULT NDirect::HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs)
3308 PRECONDITION(CheckPointer(pInternalImport));
3309 PRECONDITION(TypeFromToken(token) == mdtMethodDef);
3313 // Check method flags first before trying to find the custom value
3314 if (!IsReallyMdPinvokeImpl(dwMemberAttrs))
3318 LPCSTR pszImportName;
3321 if (SUCCEEDED(pInternalImport->GetPinvokeMap(token, &mappingFlags, &pszImportName, &modref)))
3328 // Either MD or signature & module must be given.
3330 BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*/, Module *pModule /*= NULL*/)
3335 PRECONDITION(pMD != NULL || (pSig != NULL && pModule != NULL));
3339 // As a by-product, when returning FALSE we will also set the native stack size to the MD if it's
3340 // an NDirectMethodDesc. This number is needed to link the P/Invoke (it determines the @n entry
3341 // point name suffix and affects alignment thunk generation on the Mac). If this method returns
3342 // TRUE, the stack size will be set when building the marshaling IL stub.
3343 DWORD dwStackSize = 0;
3344 CorPinvokeMap callConv = (CorPinvokeMap)0;
3348 if (pMD->IsNDirect() || pMD->IsComPlusCall())
3350 // HRESULT swapping is handled by stub
3351 if ((pMD->GetImplAttrs() & miPreserveSig) == 0)
3355 // SetLastError is handled by stub
3356 PInvokeStaticSigInfo sigInfo(pMD);
3357 if (sigInfo.GetLinkFlags() & nlfLastError)
3360 // LCID argument is handled by stub
3361 if (GetLCIDParameterIndex(pMD) != -1)
3364 // making sure that cctor has run may be handled by stub
3365 if (pMD->IsNDirect() && ((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
3368 callConv = sigInfo.GetCallConv();
3373 PREFIX_ASSUME(pMD != NULL);
3375 pSig = pMD->GetSig();
3376 pModule = pMD->GetModule();
3379 // Check to make certain that the signature only contains types that marshal trivially
3380 SigPointer ptr(pSig);
3381 IfFailThrow(ptr.GetCallingConvInfo(NULL));
3383 IfFailThrow(ptr.GetData(&numArgs));
3384 numArgs++; // +1 for return type
3386 // We'll need to parse parameter native types
3387 mdParamDef *pParamTokenArray = (mdParamDef *)_alloca(numArgs * sizeof(mdParamDef));
3388 IMDInternalImport *pMDImport = pModule->GetMDImport();
3390 SigTypeContext emptyTypeContext;
3392 mdMethodDef methodToken = mdMethodDefNil;
3395 methodToken = pMD->GetMemberDef();
3397 CollateParamTokens(pMDImport, methodToken, numArgs - 1, pParamTokenArray);
3399 for (ULONG i = 0; i < numArgs; i++)
3401 SigPointer arg = ptr;
3402 CorElementType type;
3403 IfFailThrow(arg.PeekElemType(&type));
3407 case ELEMENT_TYPE_PTR:
3409 IfFailThrow(arg.GetElemType(NULL)); // skip ELEMENT_TYPE_PTR
3410 IfFailThrow(arg.PeekElemType(&type));
3412 if (type == ELEMENT_TYPE_VALUETYPE)
3414 if ((arg.HasCustomModifier(pModule,
3415 "Microsoft.VisualC.NeedsCopyConstructorModifier",
3416 ELEMENT_TYPE_CMOD_REQD)) ||
3417 (arg.HasCustomModifier(pModule,
3418 "System.Runtime.CompilerServices.IsCopyConstructed",
3419 ELEMENT_TYPE_CMOD_REQD)))
3424 if (i > 0) dwStackSize += sizeof(SLOT);
3428 case ELEMENT_TYPE_INTERNAL:
3430 // this check is not functional in DAC and provides no security against a malicious dump
3431 // the DAC is prepared to receive an invalid type handle
3432 #ifndef DACCESS_COMPILE
3433 if (pModule->IsSigInIL(arg.GetPtr()))
3434 THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module*)pModule);
3439 case ELEMENT_TYPE_VALUETYPE:
3441 TypeHandle hndArgType = arg.GetTypeHandleThrowing(pModule, &emptyTypeContext);
3443 // JIT can handle internal blittable value types
3444 if (!hndArgType.IsBlittable() && !hndArgType.IsEnum())
3449 // return value is fine as long as it can be normalized to an integer
3452 CorElementType normalizedType = hndArgType.GetInternalCorElementType();
3453 if (normalizedType == ELEMENT_TYPE_VALUETYPE)
3455 // it is a structure even after normalization
3461 dwStackSize += StackElemSize(hndArgType.GetSize());
3466 case ELEMENT_TYPE_BOOLEAN:
3467 case ELEMENT_TYPE_CHAR:
3469 // Bool requires marshaling
3470 // Char may require marshaling (MARSHAL_TYPE_ANSICHAR)
3476 if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
3478 if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
3482 // other non-primitive type - requires marshaling
3488 // check for explicit MarshalAs
3489 NativeTypeParamInfo paramInfo;
3491 if (pParamTokenArray[i] != mdParamDefNil)
3493 if (!ParseNativeTypeInfo(pParamTokenArray[i], pMDImport, ¶mInfo) ||
3494 paramInfo.m_NativeType != NATIVE_TYPE_DEFAULT)
3496 // Presence of MarshalAs does not necessitate marshaling (it could as well be the default
3497 // for the type), but it's a good enough heuristic. We definitely don't want to duplicate
3498 // the logic from code:MarshalInfo.MarshalInfo here.
3503 IfFailThrow(ptr.SkipExactlyOne());
3506 if (!FitsInU2(dwStackSize))
3509 // do not set the stack size for varargs - the number is call site specific
3510 if (pMD != NULL && !pMD->IsVarArg())
3512 if (pMD->IsNDirect())
3514 ((NDirectMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize), callConv);
3516 #ifdef FEATURE_COMINTEROP
3517 else if (pMD->IsComPlusCall())
3519 // calling convention is always stdcall
3520 ((ComPlusCallMethodDesc *)pMD)->SetStackArgumentSize(static_cast<WORD>(dwStackSize));
3522 #endif // FEATURE_COMINTEROP
3529 // factorization of CreateNDirectStubWorker
3530 static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig,
3532 CorNativeLinkType nlType,
3533 CorNativeLinkFlags nlFlags,
3534 UINT argidx, // this is used for reverse pinvoke hresult swapping
3540 UINT& nativeStackOffset,
3541 bool& fStubNeedsCOM,
3543 DEBUG_ARG(LPCUTF8 pDebugName)
3544 DEBUG_ARG(LPCUTF8 pDebugClassName)
3551 PRECONDITION(CheckPointer(params));
3552 PRECONDITION(CheckPointer(pss));
3553 PRECONDITION(CheckPointer(pMD, NULL_OK));
3557 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3559 MarshalInfo::MarshalScenario ms;
3560 #ifdef FEATURE_COMINTEROP
3561 if (SF_IsCOMStub(dwStubFlags))
3563 if (SF_IsWinRTStub(dwStubFlags))
3564 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3566 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
3569 #endif // FEATURE_COMINTEROP
3571 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
3574 #ifdef FEATURE_COMINTEROP
3575 if (SF_IsWinRTCtorStub(dwStubFlags))
3577 _ASSERTE(msig.GetReturnType() == ELEMENT_TYPE_VOID);
3578 _ASSERTE(SF_IsHRESULTSwapping(dwStubFlags));
3580 pss->MarshalFactoryReturn();
3581 nativeStackOffset += sizeof(LPVOID);
3582 if (SF_IsWinRTCompositionStub(dwStubFlags))
3584 nativeStackOffset += 2 * sizeof(LPVOID);
3588 #endif // FEATURE_COMINTEROP
3589 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
3591 MarshalInfo returnInfo(msig.GetModule(),
3592 msig.GetReturnProps(),
3593 msig.GetSigTypeContext(),
3600 msig.NumFixedArgs(),
3601 SF_IsBestFit(dwStubFlags),
3602 SF_IsThrowOnUnmappableChar(dwStubFlags),
3606 DEBUG_ARG(pDebugName)
3607 DEBUG_ARG(pDebugClassName)
3611 marshalType = returnInfo.GetMarshalType();
3613 fStubNeedsCOM |= returnInfo.MarshalerRequiresCOM();
3615 #ifdef FEATURE_COMINTEROP
3616 if (marshalType == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3618 // Hidden length arrays are only valid with HRESULT swapping
3619 if (!SF_IsHRESULTSwapping(dwStubFlags))
3621 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3624 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3625 returnInfo.SetHiddenLengthParamIndex(static_cast<UINT16>(nativeArgIndex));
3627 // Inject the hidden argument so that it winds up at the end of the method signature
3628 pss->MarshalHiddenLengthArgument(&returnInfo, TRUE);
3629 nativeStackOffset += returnInfo.GetHiddenLengthParamStackSize();
3631 if (SF_IsReverseStub(dwStubFlags))
3637 if (SF_IsCOMStub(dwStubFlags))
3639 if (marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS ||
3640 marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3641 marshalType == MarshalInfo::MARSHAL_TYPE_GUID ||
3642 marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL)
3644 #ifndef _TARGET_X86_
3645 // We cannot optimize marshalType to MARSHAL_TYPE_GENERIC_* because the JIT works with exact types
3646 // and would refuse to compile the stub if it implicitly converted between scalars and value types (also see
3647 // code:MarshalInfo.MarhalInfo where we do the optimization on x86). We want to throw only if the structure
3648 // is too big to be returned in registers.
3649 if (marshalType != MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS ||
3650 IsUnmanagedValueTypeReturnedByRef(returnInfo.GetNativeArgSize()))
3651 #endif // _TARGET_X86_
3653 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3655 // Note that this limitation is very likely not needed anymore and could be lifted if we care.
3656 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3660 pss->MarshalReturn(&returnInfo, argOffset);
3664 // We don't support native methods that return VARIANTs directly.
3665 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT)
3667 if (!SF_IsHRESULTSwapping(dwStubFlags) && !SF_IsCOMLateBoundStub(dwStubFlags))
3669 COMPlusThrow(kMarshalDirectiveException, IDS_EE_COM_UNSUPPORTED_SIG);
3673 pss->MarshalReturn(&returnInfo, argOffset);
3677 #endif // FEATURE_COMINTEROP
3679 if (marshalType > MarshalInfo::MARSHAL_TYPE_DOUBLE && IsUnsupportedValueTypeReturn(msig))
3681 if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
3682 || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
3683 || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
3684 #ifdef FEATURE_COMINTEROP
3685 || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
3686 #endif // FEATURE_COMINTEROP
3689 if (SF_IsHRESULTSwapping(dwStubFlags))
3691 // V1 restriction: we could implement this but it's late in the game to do so.
3692 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3695 else if (marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF)
3697 COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION);
3701 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
3705 #ifdef FEATURE_COMINTEROP
3706 if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
3708 // No support for returning variants. This is a V1 restriction, due to the late date,
3709 // don't want to add the special-case code to support this in light of low demand.
3710 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NOVARIANTRETURN);
3712 #endif // FEATURE_COMINTEROP
3714 pss->MarshalReturn(&returnInfo, argOffset);
3721 static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
3723 LIMITED_METHOD_CONTRACT;
3727 // -1 means that the argument is not on the stack
3728 return (stackSize >= sizeof(SLOT) ? (stackSize - sizeof(SLOT)) : (UINT)-1);
3730 #endif // _TARGET_X86_
3734 #ifdef FEATURE_COMINTEROP
3736 struct HiddenParameterInfo
3738 MarshalInfo *pManagedParam; // Managed parameter which required the hidden parameter
3739 int nativeIndex; // 0 based index into the native method signature where the hidden parameter should be injected
3742 // Get the indexes of any hidden length parameters to be marshaled for the method
3744 // At return, each value in the ppParamIndexes array is a 0 based index into the native method signature where
3745 // the length parameter for a hidden length array should be passed. The MarshalInfo objects will also be
3746 // updated such that they all have explicit marshaling information.
3748 // The caller is responsible for freeing the memory pointed to by ppParamIndexes
3749 void CheckForHiddenParameters(DWORD cParamMarshalInfo,
3750 __in_ecount(cParamMarshalInfo) MarshalInfo *pParamMarshalInfo,
3751 __out DWORD *pcHiddenNativeParameters,
3752 __out HiddenParameterInfo **ppHiddenNativeParameters)
3757 PRECONDITION(CheckPointer(pParamMarshalInfo));
3758 PRECONDITION(CheckPointer(pcHiddenNativeParameters));
3759 PRECONDITION(CheckPointer(ppHiddenNativeParameters));
3763 NewArrayHolder<HiddenParameterInfo> hiddenParamInfo(new HiddenParameterInfo[cParamMarshalInfo]);
3764 DWORD foundInfoCount = 0;
3766 for (DWORD iParam = 0; iParam < cParamMarshalInfo; ++iParam)
3768 // Look for hidden length arrays, which all require additional parameters to be added
3769 if (pParamMarshalInfo[iParam].GetMarshalType() == MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY)
3771 DWORD currentNativeIndex = iParam + foundInfoCount;
3773 // The location of the length parameter is implicitly just before the array pointer.
3774 // We'll give it our current index, and bumping the found count will push us back a slot.
3776 // We should be safe to cast here - giant signatures will fail to marashal later with IDS_EE_SIGTOOCOMPLEX
3777 pParamMarshalInfo[iParam].SetHiddenLengthParamIndex(static_cast<UINT16>(currentNativeIndex));
3779 hiddenParamInfo[foundInfoCount].nativeIndex = pParamMarshalInfo[iParam].HiddenLengthParamIndex();
3780 hiddenParamInfo[foundInfoCount].pManagedParam = &(pParamMarshalInfo[iParam]);
3785 *pcHiddenNativeParameters = foundInfoCount;
3786 *ppHiddenNativeParameters = hiddenParamInfo.Extract();
3789 bool IsHiddenParameter(int nativeArgIndex,
3790 DWORD cHiddenParameters,
3791 __in_ecount(cHiddenParameters) HiddenParameterInfo *pHiddenParameters,
3792 __out HiddenParameterInfo **ppHiddenParameterInfo)
3797 PRECONDITION(cHiddenParameters == 0 || CheckPointer(pHiddenParameters));
3798 PRECONDITION(CheckPointer(ppHiddenParameterInfo));
3802 *ppHiddenParameterInfo = NULL;
3804 for (DWORD i = 0; i < cHiddenParameters; ++i)
3806 _ASSERTE(pHiddenParameters[i].nativeIndex != -1);
3807 if (pHiddenParameters[i].nativeIndex == nativeArgIndex)
3809 *ppHiddenParameterInfo = &(pHiddenParameters[i]);
3817 #endif // FEATURE_COMINTEROP
3819 //---------------------------------------------------------
3820 // Creates a new stub for a N/Direct call. Return refcount is 1.
3821 // Note that this function may now throw if it fails to create
3823 //---------------------------------------------------------
3824 static void CreateNDirectStubWorker(StubState* pss,
3825 StubSigDesc* pSigDesc,
3826 CorNativeLinkType nlType,
3827 CorNativeLinkFlags nlFlags,
3828 CorPinvokeMap unmgdCallConv,
3831 mdParamDef* pParamTokenArray,
3839 PRECONDITION(CheckPointer(pss));
3840 PRECONDITION(CheckPointer(pSigDesc));
3841 PRECONDITION(CheckPointer(pMD, NULL_OK));
3842 PRECONDITION(!pMD || pMD->IsILStub() || (0 != pMD->GetMethodTable()->IsDelegate()) == SF_IsDelegateStub(dwStubFlags));
3846 SF_ConsistencyCheck(dwStubFlags);
3849 if (g_pConfig->ShouldBreakOnInteropStubSetup(pSigDesc->m_pDebugName))
3850 CONSISTENCY_CHECK_MSGF(false, ("BreakOnInteropStubSetup: '%s' ", pSigDesc->m_pDebugName));
3855 if (SF_IsCOMStub(dwStubFlags))
3857 _ASSERTE(0 == nlType);
3858 _ASSERTE(0 == nlFlags);
3859 _ASSERTE(0 == unmgdCallConv);
3863 _ASSERTE(nlType == nltAnsi || nlType == nltUnicode);
3865 Module *pModule = pSigDesc->m_pModule;
3868 // Set up signature walking objects.
3871 MetaSig msig(pSigDesc->m_sig,
3873 &pSigDesc->m_typeContext);
3875 if (SF_IsVarArgStub(dwStubFlags))
3876 msig.SetTreatAsVarArg();
3878 bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
3880 pss->SetLastError(nlFlags & nlfLastError);
3882 // This has been in the product since forward P/Invoke via delegates was
3883 // introduced. It's wrong, but please keep it for backward compatibility.
3884 if (SF_IsDelegateStub(dwStubFlags))
3885 pss->SetLastError(TRUE);
3887 pss->BeginEmit(dwStubFlags);
3891 // LCID is not supported on WinRT
3892 _ASSERTE(!SF_IsWinRTStub(dwStubFlags));
3894 // The code to handle the LCID will call MarshalLCID before calling MarshalArgument
3895 // on the argument the LCID should go after. So we just bump up the index here.
3899 int numArgs = msig.NumFixedArgs();
3901 // thiscall must have at least one parameter (the "this")
3902 if (fThisCall && numArgs == 0)
3903 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
3906 // Now, emit the IL.
3911 MarshalInfo::MarshalType marshalType = (MarshalInfo::MarshalType) 0xcccccccc;
3914 // Marshal the return value.
3917 UINT nativeStackSize = (SF_IsCOMStub(dwStubFlags) ? sizeof(SLOT) : 0);
3918 bool fHasCopyCtorArgs = false;
3919 bool fStubNeedsCOM = SF_IsCOMStub(dwStubFlags);
3921 // Normally we would like this to be false so that we use the correct signature
3922 // in the IL_STUB, (i.e if it returns a value class then the signature will use that)
3923 // When this bool is true we change the return type to void and explicitly add a
3924 // return buffer argument as the first argument.
3925 BOOL fMarshalReturnValueFirst = false;
3927 // We can only change fMarshalReturnValueFirst to true when we are NOT doing HRESULT-swapping!
3929 if (!SF_IsHRESULTSwapping(dwStubFlags))
3932 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
3933 // JIT32 has problems in generating code for pinvoke ILStubs which do a return in return buffer.
3934 // Therefore instead we change the signature of calli to return void and make the return buffer as first
3935 // argument. This matches the ABI i.e. return buffer is passed as first arg. So native target will get the
3936 // return buffer in correct register.
3937 // The return structure secret arg comes first, however byvalue return is processed at
3938 // the end because it could be the HRESULT-swapped argument which always comes last.
3939 fMarshalReturnValueFirst = HasRetBuffArg(&msig);
3944 if (fMarshalReturnValueFirst)
3946 marshalType = DoMarshalReturnValue(msig,
3959 DEBUG_ARG(pSigDesc->m_pDebugName)
3960 DEBUG_ARG(pSigDesc->m_pDebugClassName)
3963 if (marshalType == MarshalInfo::MARSHAL_TYPE_DATE ||
3964 marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY ||
3965 marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET ||
3966 marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF ||
3967 marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
3968 #ifdef FEATURE_COMINTEROP
3969 || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
3970 #endif // FEATURE_COMINTEROP
3973 // These are special non-blittable types returned by-ref in managed,
3974 // but marshaled as primitive values returned by-value in unmanaged.
3978 // This is an ordinary value type - see if it is returned by-ref.
3979 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
3980 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
3982 nativeStackSize += sizeof(LPVOID);
3988 // Marshal the arguments
3990 MarshalInfo::MarshalScenario ms;
3991 #ifdef FEATURE_COMINTEROP
3992 if (SF_IsCOMStub(dwStubFlags))
3994 if (SF_IsWinRTStub(dwStubFlags))
3995 ms = MarshalInfo::MARSHAL_SCENARIO_WINRT;
3997 ms = MarshalInfo::MARSHAL_SCENARIO_COMINTEROP;
4000 #endif // FEATURE_COMINTEROP
4002 ms = MarshalInfo::MARSHAL_SCENARIO_NDIRECT;
4005 // Build up marshaling information for each of the method's parameters
4006 SIZE_T cbParamMarshalInfo;
4007 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(MarshalInfo), numArgs, cbParamMarshalInfo))
4009 COMPlusThrowHR(COR_E_OVERFLOW);
4012 NewArrayHolder<BYTE> pbParamMarshalInfo(new BYTE[cbParamMarshalInfo]);
4013 MarshalInfo *pParamMarshalInfo = reinterpret_cast<MarshalInfo *>(pbParamMarshalInfo.GetValue());
4015 MetaSig paramInfoMSig(msig);
4016 for (int i = 0; i < numArgs; ++i)
4018 paramInfoMSig.NextArg();
4019 new(&(pParamMarshalInfo[i])) MarshalInfo(paramInfoMSig.GetModule(),
4020 paramInfoMSig.GetArgProps(),
4021 paramInfoMSig.GetSigTypeContext(),
4022 pParamTokenArray[i + 1],
4029 SF_IsBestFit(dwStubFlags),
4030 SF_IsThrowOnUnmappableChar(dwStubFlags),
4034 DEBUG_ARG(pSigDesc->m_pDebugName)
4035 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4039 #ifdef FEATURE_COMINTEROP
4040 // Check to see if we need to inject any additional hidden parameters
4041 DWORD cHiddenNativeParameters;
4042 NewArrayHolder<HiddenParameterInfo> pHiddenNativeParameters;
4043 CheckForHiddenParameters(numArgs, pParamMarshalInfo, &cHiddenNativeParameters, &pHiddenNativeParameters);
4045 // Hidden parameters and LCID do not mix
4046 _ASSERTE(!(cHiddenNativeParameters > 0 && iLCIDArg != -1));
4047 #endif // FEATURE_COMINTEROP
4049 // Marshal the parameters
4051 int nativeArgIndex = 0;
4052 while (argidx <= numArgs)
4054 #ifdef FEATURE_COMINTEROP
4055 HiddenParameterInfo *pHiddenParameter;
4056 // Check to see if we need to inject a hidden parameter
4057 if (IsHiddenParameter(nativeArgIndex, cHiddenNativeParameters, pHiddenNativeParameters, &pHiddenParameter))
4059 pss->MarshalHiddenLengthArgument(pHiddenParameter->pManagedParam, FALSE);
4060 nativeStackSize += pHiddenParameter->pManagedParam->GetHiddenLengthParamStackSize();
4062 if (SF_IsReverseStub(dwStubFlags))
4068 #endif // FEATURE_COMINTEROP
4071 // Check to see if this is the parameter after which we need to insert the LCID.
4073 if (argidx == iLCIDArg)
4075 pss->MarshalLCID(argidx);
4076 nativeStackSize += sizeof(LPVOID);
4078 if (SF_IsReverseStub(dwStubFlags))
4084 MarshalInfo &info = pParamMarshalInfo[argidx - 1];
4086 #ifdef FEATURE_COMINTEROP
4087 // For the hidden-length array, length parameters must occur before the parameter containing the array pointer
4088 _ASSERTE(info.GetMarshalType() != MarshalInfo::MARSHAL_TYPE_HIDDENLENGTHARRAY || nativeArgIndex > info.HiddenLengthParamIndex());
4089 #endif // FEATURE_COMINTEROP
4091 pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall));
4092 nativeStackSize += info.GetNativeArgSize();
4094 fStubNeedsCOM |= info.MarshalerRequiresCOM();
4096 if (fThisCall && argidx == 1)
4098 // make sure that the first parameter is enregisterable
4099 if (info.GetNativeArgSize() > sizeof(SLOT))
4100 COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL);
4110 // Check to see if this is the parameter after which we need to insert the LCID.
4111 if (argidx == iLCIDArg)
4113 pss->MarshalLCID(argidx);
4114 nativeStackSize += sizeof(LPVOID);
4116 if (SF_IsReverseStub(dwStubFlags))
4120 if (!fMarshalReturnValueFirst)
4122 // This could be a HRESULT-swapped argument so it must come last.
4123 marshalType = DoMarshalReturnValue(msig,
4136 DEBUG_ARG(pSigDesc->m_pDebugName)
4137 DEBUG_ARG(pSigDesc->m_pDebugClassName)
4140 // If the return value is a SafeHandle or CriticalHandle, mark the stub method.
4141 // Interop methods that use this stub will have an implicit reliability contract
4142 // (see code:TAStackCrawlCallBack).
4143 if (!SF_IsHRESULTSwapping(dwStubFlags))
4145 if (marshalType == MarshalInfo::MARSHAL_TYPE_SAFEHANDLE ||
4146 marshalType == MarshalInfo::MARSHAL_TYPE_CRITICALHANDLE)
4148 if (pMD->IsDynamicMethod())
4149 pMD->AsDynamicMethodDesc()->SetUnbreakable(true);
4154 if (SF_IsHRESULTSwapping(dwStubFlags))
4156 if (msig.GetReturnType() != ELEMENT_TYPE_VOID)
4157 nativeStackSize += sizeof(LPVOID);
4160 if (pMD->IsDynamicMethod())
4162 // Set the native stack size to the IL stub MD. It is needed for alignment
4163 // thunk generation on the Mac and stdcall name decoration on Windows.
4164 // We do not store it directly in the interop MethodDesc here because due
4165 // to sharing we come here only for the first call with given signature and
4166 // the target MD may even be NULL.
4171 _ASSERTE(nativeStackSize >= sizeof(SLOT));
4172 nativeStackSize -= sizeof(SLOT);
4174 #else // _TARGET_X86_
4176 // The algorithm to compute nativeStackSize on the fly is x86-specific.
4177 // Recompute the correct size for other platforms from the stub signature.
4179 if (SF_IsForwardStub(dwStubFlags))
4181 // It would be nice to compute the correct value for forward stubs too.
4182 // The value is only used in MarshalNative::NumParamBytes right now,
4183 // and changing what MarshalNative::NumParamBytes returns is
4184 // a potential breaking change.
4188 // native stack size is updated in code:ILStubState.SwapStubSignatures
4190 #endif // _TARGET_X86_
4192 if (!FitsInU2(nativeStackSize))
4193 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
4195 DynamicMethodDesc *pDMD = pMD->AsDynamicMethodDesc();
4197 pDMD->SetNativeStackArgSize(static_cast<WORD>(nativeStackSize));
4198 pDMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
4199 pDMD->SetStubNeedsCOMStarted(fStubNeedsCOM);
4202 // FinishEmit needs to know the native stack arg size so we call it after the number
4203 // has been set in the stub MD (code:DynamicMethodDesc.SetNativeStackArgSize)
4204 pss->FinishEmit(pMD);
4207 class NDirectStubHashBlob : public ILStubHashBlobBase
4212 WORD m_unmgdCallConv;
4213 BYTE m_nlType; // C_ASSERTS are in NDirect::CreateHashBlob
4220 BYTE m_rgbSigAndParamData[1];
4221 // (dwParamAttr, cbNativeType) // length: number of parameters
4222 // NativeTypeBlob // length: number of parameters
4223 // BYTE m_rgbSigData[]; // length: determined by sig walk
4226 // For better performance and less memory fragmentation,
4227 // I'm using structure here to avoid allocating 3 different arrays.
4232 PCCOR_SIGNATURE pvNativeType;
4235 ILStubHashBlob* NDirect::CreateHashBlob(NDirectStubParameters* pParams)
4237 STANDARD_VM_CONTRACT;
4239 NDirectStubHashBlob* pBlob;
4241 IMDInternalImport* pInternalImport = pParams->m_pModule->GetMDImport();
4243 CQuickBytes paramInfoBytes;
4244 paramInfoBytes.AllocThrows(sizeof(ParamInfo)*pParams->m_nParamTokens);
4245 ParamInfo *paramInfos = (ParamInfo *)paramInfoBytes.Ptr();
4246 ::ZeroMemory(paramInfos, sizeof(ParamInfo) * pParams->m_nParamTokens);
4248 size_t cbNativeTypeTotal = 0;
4251 // Collect information for function parameters
4253 for (int idx = 0; idx < pParams->m_nParamTokens; idx++)
4255 mdParamDef token = pParams->m_pParamTokenArray[idx];
4256 if (TypeFromToken(token) == mdtParamDef && mdParamDefNil != token)
4258 USHORT usSequence_Ignore; // We don't need usSequence in the hash as the param array is already sorted
4259 LPCSTR szParamName_Ignore;
4260 IfFailThrow(pInternalImport->GetParamDefProps(token, &usSequence_Ignore, ¶mInfos[idx].dwParamAttr, &szParamName_Ignore));
4262 if (paramInfos[idx].dwParamAttr & pdHasFieldMarshal)
4264 IfFailThrow(pInternalImport->GetFieldMarshal(token, ¶mInfos[idx].pvNativeType, ¶mInfos[idx].cbNativeType));
4265 cbNativeTypeTotal += paramInfos[idx].cbNativeType;
4270 SigPointer sigPtr = pParams->m_sig.CreateSigPointer();
4272 // note that ConvertToInternalSignature also resolves generics so different instantiations will get different
4273 // hash blobs for methods that have generic parameters in their signature
4274 SigBuilder sigBuilder;
4275 sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE);
4278 PVOID pSig = sigBuilder.GetSignature(&cbSig);
4281 // Build hash blob for IL stub sharing
4283 S_SIZE_T cbSizeOfBlob = S_SIZE_T(offsetof(NDirectStubHashBlob, m_rgbSigAndParamData)) +
4284 S_SIZE_T(sizeof(ULONG)) * S_SIZE_T(pParams->m_nParamTokens) + // Parameter attributes
4285 S_SIZE_T(sizeof(DWORD)) * S_SIZE_T(pParams->m_nParamTokens) + // Native type blob size
4286 S_SIZE_T(cbNativeTypeTotal) + // Native type blob data
4287 S_SIZE_T(cbSig); // Signature
4289 if (cbSizeOfBlob.IsOverflow())
4290 COMPlusThrowHR(COR_E_OVERFLOW);
4292 static_assert_no_msg(nltMaxValue <= 0xFF);
4293 static_assert_no_msg(nlfMaxValue <= 0xFF);
4294 static_assert_no_msg(pmMaxValue <= 0xFFFF);
4296 NewArrayHolder<BYTE> pBytes = new BYTE[cbSizeOfBlob.Value()];
4297 // zero out the hash bytes to ensure all bit fields are deterministically set
4298 ZeroMemory(pBytes, cbSizeOfBlob.Value());
4299 pBlob = (NDirectStubHashBlob*)(BYTE*)pBytes;
4301 pBlob->m_pModule = NULL;
4303 if (SF_IsNGENedStub(pParams->m_dwStubFlags))
4305 // don't share across modules if we are ngening the stub
4306 pBlob->m_pModule = pParams->m_pModule;
4309 pBlob->m_cbSizeOfBlob = cbSizeOfBlob.Value();
4310 pBlob->m_unmgdCallConv = static_cast<WORD>(pParams->m_unmgdCallConv);
4311 pBlob->m_nlType = static_cast<BYTE>(pParams->m_nlType);
4312 pBlob->m_nlFlags = static_cast<BYTE>(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub
4313 pBlob->m_iLCIDArg = pParams->m_iLCIDArg;
4315 pBlob->m_StubFlags = pParams->m_dwStubFlags;
4316 pBlob->m_nParams = pParams->m_nParamTokens;
4318 BYTE* pBlobParams = &pBlob->m_rgbSigAndParamData[0];
4321 // Write (dwParamAttr, cbNativeType) for parameters
4323 // Note that these need to be aligned and it is why they are written before the byte blobs
4324 // I'm putting asserts here so that it will assert even in non-IA64 platforms to catch bugs
4326 _ASSERTE((DWORD_PTR)pBlobParams % sizeof(DWORD) == 0);
4327 _ASSERTE(sizeof(DWORD) == sizeof(ULONG));
4329 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4331 // We only care about In/Out/HasFieldMarshal
4332 // Other attr are about optional/default values which are not used in marshalling,
4333 // but only used in compilers
4334 *((DWORD *)pBlobParams) = paramInfos[i].dwParamAttr & (pdIn | pdOut | pdHasFieldMarshal);
4335 pBlobParams += sizeof(DWORD);
4337 *((ULONG *)pBlobParams) = paramInfos[i].cbNativeType;
4338 pBlobParams += sizeof(ULONG);
4342 // Write native type blob for parameters
4344 for (int i = 0; i < pParams->m_nParamTokens; ++i)
4346 memcpy(pBlobParams, paramInfos[i].pvNativeType, paramInfos[i].cbNativeType);
4347 pBlobParams += paramInfos[i].cbNativeType;
4353 memcpy(pBlobParams, pSig, cbSig);
4355 // Verify that we indeed have reached the end
4356 _ASSERTE(pBlobParams + cbSig == (BYTE *)pBlob + cbSizeOfBlob.Value());
4358 pBytes.SuppressRelease();
4359 return (ILStubHashBlob*)pBlob;
4363 ILStubCache* NDirect::GetILStubCache(NDirectStubParameters* pParams)
4373 // Use the m_pLoaderModule instead of m_pModule
4374 // They could be different for methods on generic types.
4375 return pParams->m_pLoaderModule->GetILStubCache();
4379 MethodDesc* NDirect::GetStubMethodDesc(
4380 MethodDesc *pTargetMD,
4381 NDirectStubParameters* pParams,
4382 ILStubHashBlob* pHashParams,
4383 AllocMemTracker* pamTracker,
4384 bool& bILStubCreator,
4385 MethodDesc* pLastMD)
4387 CONTRACT(MethodDesc*)
4391 PRECONDITION(CheckPointer(pParams));
4392 PRECONDITION(!pParams->m_sig.IsEmpty());
4393 PRECONDITION(CheckPointer(pParams->m_pModule));
4394 PRECONDITION(CheckPointer(pTargetMD, NULL_OK));
4395 POSTCONDITION(CheckPointer(RETVAL));
4401 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4403 pMD = pCache->GetStubMethodDesc(pTargetMD,
4405 pParams->m_dwStubFlags,
4407 pParams->m_sig.GetRawSig(),
4408 pParams->m_sig.GetRawSigLen(),
4418 void NDirect::RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams)
4424 PRECONDITION(CheckPointer(pParams));
4425 PRECONDITION(CheckPointer(pHashParams));
4426 PRECONDITION(!pParams->m_sig.IsEmpty());
4427 PRECONDITION(CheckPointer(pParams->m_pModule));
4431 LOG((LF_STUBS, LL_INFO1000, "Exception happened when generating IL of stub clr!CreateInteropILStub StubMD: %p, HashBlob: %p \n", pParams, pHashParams));
4433 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4435 pCache->DeleteEntry(pHashParams);
4439 void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD)
4445 PRECONDITION(CheckPointer(pParams));
4446 PRECONDITION(!pParams->m_sig.IsEmpty());
4447 PRECONDITION(CheckPointer(pParams->m_pModule));
4451 ILStubCache* pCache = NDirect::GetILStubCache(pParams);
4453 pCache->AddMethodDescChunkWithLockTaken(pMD);
4457 // Additional factorization of CreateNDirectStub. This hoists all the metadata accesses
4458 // into one location so that we can leave CreateNDirectStubWorker to just generate the
4459 // IL. This allows us to cache a stub based on the inputs to CreateNDirectStubWorker
4460 // instead of having to generate the IL first before doing the caching.
4462 void CreateNDirectStubAccessMetadata(StubSigDesc* pSigDesc, // IN
4463 CorPinvokeMap unmgdCallConv, // IN
4464 DWORD* pdwStubFlags, // IN/OUT
4465 int* piLCIDArg, // OUT
4466 int* pNumArgs // OUT
4469 STANDARD_VM_CONTRACT;
4471 if (SF_IsCOMStub(*pdwStubFlags))
4473 _ASSERTE(0 == unmgdCallConv);
4477 if (unmgdCallConv != pmCallConvStdcall &&
4478 unmgdCallConv != pmCallConvCdecl &&
4479 unmgdCallConv != pmCallConvThiscall)
4481 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
4485 #ifdef FEATURE_COMINTEROP
4486 if (SF_IsDelegateStub(*pdwStubFlags))
4488 _ASSERTE(!SF_IsWinRTStub(*pdwStubFlags));
4489 if (pSigDesc->m_pMD->GetMethodTable()->IsProjectedFromWinRT())
4491 // We do not allow P/Invoking via WinRT delegates to better segregate WinRT
4492 // from classic interop scenarios.
4493 COMPlusThrow(kMarshalDirectiveException, IDS_EE_DELEGATEPINVOKE_WINRT);
4496 #endif // FEATURE_COMINTEROP
4498 MetaSig msig(pSigDesc->m_sig,
4499 pSigDesc->m_pModule,
4500 &pSigDesc->m_typeContext);
4502 if (SF_IsVarArgStub(*pdwStubFlags))
4503 msig.SetTreatAsVarArg();
4505 (*pNumArgs) = msig.NumFixedArgs();
4507 IMDInternalImport* pInternalImport = pSigDesc->m_pModule->GetMDImport();
4509 _ASSERTE(!SF_IsHRESULTSwapping(*pdwStubFlags));
4511 mdMethodDef md = pSigDesc->m_tkMethodDef;
4512 if (md != mdMethodDefNil)
4514 DWORD dwDescrOffset;
4516 IfFailThrow(pInternalImport->GetMethodImplProps(
4521 #ifdef FEATURE_COMINTEROP
4522 if (SF_IsWinRTStub(*pdwStubFlags))
4524 // All WinRT methods do HRESULT swapping
4525 if (IsMiPreserveSig(dwImplFlags))
4527 COMPlusThrow(kMarshalDirectiveException, IDS_EE_PRESERVESIG_WINRT);
4530 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4533 #endif // FEATURE_COMINTEROP
4534 if (SF_IsReverseStub(*pdwStubFlags))
4536 // only COM-to-CLR call supports hresult swapping in the reverse direction
4537 if (SF_IsCOMStub(*pdwStubFlags) && !IsMiPreserveSig(dwImplFlags))
4539 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4544 // fwd pinvoke, fwd com interop support hresult swapping.
4545 // delegate to an unmanaged method does not.
4546 if (!IsMiPreserveSig(dwImplFlags) && !SF_IsDelegateStub(*pdwStubFlags))
4548 (*pdwStubFlags) |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
4553 if (pSigDesc->m_pMD != NULL)
4555 (*piLCIDArg) = GetLCIDParameterIndex(pSigDesc->m_pMD);
4562 // Check to see if we need to do LCID conversion.
4563 if ((*piLCIDArg) != -1 && (*piLCIDArg) > (*pNumArgs))
4565 COMPlusThrow(kIndexOutOfRangeException, IDS_EE_INVALIDLCIDPARAM);
4568 if (SF_IsCOMStub(*pdwStubFlags) && !SF_IsWinRTStaticStub(*pdwStubFlags))
4570 CONSISTENCY_CHECK(msig.HasThis());
4574 if (msig.HasThis() && !SF_IsDelegateStub(*pdwStubFlags))
4576 COMPlusThrow(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC);
4581 void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError /*= TRUE*/)
4583 if (pNMD->IsSynchronized() && throwOnError)
4584 COMPlusThrow(kTypeLoadException, IDS_EE_NOSYNCHRONIZED);
4586 WORD ndirectflags = 0;
4587 if (pNMD->MethodDesc::IsVarArg())
4588 ndirectflags |= NDirectMethodDesc::kVarArgs;
4590 LPCUTF8 szLibName = NULL, szEntryPointName = NULL;
4591 new (pSigInfo) PInvokeStaticSigInfo(pNMD, &szLibName, &szEntryPointName,
4592 (throwOnError ? PInvokeStaticSigInfo::THROW_ON_ERROR : PInvokeStaticSigInfo::NO_THROW_ON_ERROR));
4594 if (pSigInfo->GetCharSet() == nltAnsi)
4595 ndirectflags |= NDirectMethodDesc::kNativeAnsi;
4597 CorNativeLinkFlags linkflags = pSigInfo->GetLinkFlags();
4598 if (linkflags & nlfLastError)
4599 ndirectflags |= NDirectMethodDesc::kLastError;
4600 if (linkflags & nlfNoMangle)
4601 ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
4603 CorPinvokeMap callConv = pSigInfo->GetCallConv();
4604 if (callConv == pmCallConvStdcall)
4605 ndirectflags |= NDirectMethodDesc::kStdCall;
4606 if (callConv == pmCallConvThiscall)
4607 ndirectflags |= NDirectMethodDesc::kThisCall;
4609 if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
4611 ndirectflags |= NDirectMethodDesc::kIsQCall;
4615 EnsureWritablePages(&pNMD->ndirect);
4616 pNMD->ndirect.m_pszLibName = szLibName;
4617 pNMD->ndirect.m_pszEntrypointName = szEntryPointName;
4621 if (ndirectflags & NDirectMethodDesc::kStdCall)
4623 // Compute the kStdCallWithRetBuf flag which is needed at link time for entry point mangling.
4625 ArgIterator argit(&msig);
4626 if (argit.HasRetBuffArg())
4628 MethodTable *pRetMT = msig.GetRetTypeHandleThrowing().AsMethodTable();
4629 if (IsUnmanagedValueTypeReturnedByRef(pRetMT->GetNativeSize()))
4631 ndirectflags |= NDirectMethodDesc::kStdCallWithRetBuf;
4635 #endif // _TARGET_X86_
4637 // Call this exactly ONCE per thread. Do not publish incomplete prestub flags
4638 // or you will introduce a race condition.
4639 pNMD->InterlockedSetNDirectFlags(ndirectflags);
4642 #ifdef FEATURE_COMINTEROP
4643 // Find the MethodDesc of the predefined IL stub method by either
4644 // 1) looking at redirected adapter interfaces, OR
4645 // 2) looking at special attributes for the specific interop scenario (specified by dwStubFlags).
4646 // Currently only ManagedToNativeComInteropStubAttribute is supported.
4647 // It returns NULL if no such attribute(s) can be found.
4648 // But if the attribute is found and is invalid, or something went wrong in the looking up
4649 // process, an exception will be thrown. If everything goes well, you'll get the MethodDesc
4650 // of the stub method
4651 HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD)
4658 PRECONDITION(CheckPointer(pTargetMD));
4659 PRECONDITION(CheckPointer(ppRetStubMD));
4660 PRECONDITION(*ppRetStubMD == NULL);
4666 MethodTable *pTargetMT = pTargetMD->GetMethodTable();
4668 // Check if this is a redirected interface - we have static stubs in mscorlib for those.
4669 if (SF_IsForwardCOMStub(dwStubFlags) && pTargetMT->IsInterface())
4672 // Redirect generic redirected interfaces to the corresponding adapter methods in mscorlib
4673 if (pTargetMT->HasInstantiation())
4675 MethodDesc *pAdapterMD = WinRTInterfaceRedirector::GetStubMethodForRedirectedInterfaceMethod(pTargetMD, TypeHandle::Interop_ManagedToNative);
4676 if (pAdapterMD != NULL)
4678 *ppRetStubMD = pAdapterMD;
4685 // Find out if we have the attribute
4690 // Support v-table forward classic COM interop calls only
4691 if (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags) && !SF_IsWinRTStub(dwStubFlags))
4693 if (pTargetMT->HasInstantiation())
4695 // ManagedToNativeComInteropStubAttribute is not supported with generics
4699 if (pTargetMD->IsFCall())
4701 // ManagedToNativeComInteropStubAttribute is not supported on FCalls (i.e. methods on legacy
4702 // interfaces forwarded to CustomMarshalers.dll such as IEnumerable::GetEnumerator)
4705 _ASSERTE(pTargetMD->IsComPlusCall());
4707 if (pTargetMD->IsInterface())
4709 _ASSERTE(!pTargetMD->GetAssembly()->IsWinMD());
4710 hr = pTargetMD->GetMDImport()->GetCustomAttributeByName(
4711 pTargetMD->GetMemberDef(),
4712 FORWARD_INTEROP_STUB_METHOD_TYPE,
4718 // GetCustomAttributeByName returns S_FALSE when it cannot find the attribute but nothing fails...
4719 // Translate that to E_FAIL
4720 else if (hr == S_FALSE)
4725 // We are dealing with the class, use the interface MD instead
4726 // After second thought I believe we don't need to check the class MD.
4727 // We can think stubs as part of public interface, and if the interface is public,
4728 // the stubs should also be accessible
4729 MethodDesc *pInterfaceMD = pTargetMD->GetInterfaceMD();
4732 hr = FindPredefinedILStubMethod(pInterfaceMD, dwStubFlags, ppRetStubMD);
4743 // Parse the attribute
4745 CustomAttributeParser parser(pBytes, cbBytes);
4746 IfFailRet(parser.SkipProlog());
4750 IfFailRet(parser.GetNonEmptyString(&pTypeName, &cbTypeName));
4752 LPCUTF8 pMethodName;
4754 IfFailRet(parser.GetNonEmptyString(&pMethodName, &cbMethodName));
4756 StackSString typeName(SString::Utf8, pTypeName, cbTypeName);
4757 StackSString methodName(SString::Utf8, pMethodName, cbMethodName);
4760 // Retrieve the type
4762 TypeHandle stubClassType;
4763 stubClassType = TypeName::GetTypeUsingCASearchRules(typeName.GetUnicode(), pTargetMT->GetAssembly());
4765 MethodTable *pStubClassMT = stubClassType.AsMethodTable();
4767 StackSString stubClassName;
4768 pStubClassMT->_GetFullyQualifiedNameForClassNestedAware(stubClassName);
4770 StackSString targetInterfaceName;
4771 pTargetMT->_GetFullyQualifiedNameForClassNestedAware(targetInterfaceName);
4773 // Restrict to same assembly only to reduce test cost
4774 if (stubClassType.GetAssembly() != pTargetMT->GetAssembly())
4778 IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY,
4779 stubClassName.GetUnicode(),
4780 targetInterfaceName.GetUnicode()
4784 if (stubClassType.HasInstantiation())
4788 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_GENERIC,
4789 stubClassName.GetUnicode()
4793 if (stubClassType.IsInterface())
4797 IDS_EE_INTEROP_STUB_CA_STUB_CLASS_MUST_NOT_BE_INTERFACE,
4798 stubClassName.GetUnicode()
4803 // Locate the MethodDesc for the stub method
4805 MethodDesc *pStubMD = NULL;
4808 PCCOR_SIGNATURE pTargetSig = NULL;
4809 DWORD pcTargetSig = 0;
4811 SigTypeContext typeContext; // NO generics supported
4813 pTargetMD->GetSig(&pTargetSig, &pcTargetSig);
4815 MetaSig msig(pTargetSig,
4817 pTargetMD->GetModule(),
4819 _ASSERTE(msig.HasThis());
4821 SigBuilder stubSigBuilder;
4824 // Append calling Convention, NumOfArgs + 1,
4826 stubSigBuilder.AppendByte(msig.GetCallingConvention() & ~IMAGE_CEE_CS_CALLCONV_HASTHIS);
4827 stubSigBuilder.AppendData(msig.NumFixedArgs() + 1);
4830 // Append return type
4832 SigPointer pReturn = msig.GetReturnProps();
4833 LPBYTE pReturnTypeBegin = (LPBYTE)pReturn.GetPtr();
4834 IfFailThrow(pReturn.SkipExactlyOne());
4835 LPBYTE pReturnTypeEnd = (LPBYTE)pReturn.GetPtr();
4837 stubSigBuilder.AppendBlob(pReturnTypeBegin, pReturnTypeEnd - pReturnTypeBegin);
4842 stubSigBuilder.AppendElementType(ELEMENT_TYPE_CLASS);
4843 stubSigBuilder.AppendToken(pTargetMT->GetCl());
4846 // Copy rest of the arguments
4848 if (msig.NextArg() != ELEMENT_TYPE_END)
4850 SigPointer pFirstArg = msig.GetArgProps();
4851 LPBYTE pArgBegin = (LPBYTE) pFirstArg.GetPtr();
4852 LPBYTE pArgEnd = (LPBYTE) pTargetSig + pcTargetSig;
4854 stubSigBuilder.AppendBlob(pArgBegin, pArgEnd - pArgBegin);
4858 // Allocate new memory and copy over
4860 DWORD pcStubSig = 0;
4861 PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE) stubSigBuilder.GetSignature(&pcStubSig);
4864 // Find method using name + signature
4866 StackScratchBuffer buffer;
4867 LPCUTF8 szMethodNameUTF8 = methodName.GetUTF8(buffer);
4868 pStubMD = MemberLoader::FindMethod(stubClassType.GetMethodTable(),
4872 pTargetMT->GetModule());
4874 if (pStubMD == NULL)
4883 pTargetMD->GetMDImport(),
4886 // Unfortunately the PrettyPrintSig doesn't print 'static' when the function is static
4887 // so we need to append 'static' here. No need to localize
4888 SString signature(SString::Utf8, (LPCUTF8)"static ");
4889 signature.AppendUTF8((LPCUTF8) qbSig.Ptr());
4892 kMissingMethodException,
4893 IDS_EE_INTEROP_STUB_CA_STUB_METHOD_MISSING,
4894 signature.GetUnicode(),
4895 stubClassName.GetUnicode()
4902 // Check the Stub MD
4905 // Verify that the target interop method can call the stub method
4907 _ASSERTE(pTargetMD != NULL);
4909 StaticAccessCheckContext accessContext(pTargetMD, pTargetMT);
4911 if (!ClassLoader::CanAccess(
4914 stubClassType.GetAssembly(),
4915 pStubMD->GetAttrs(),
4919 StackSString interopMethodName(SString::Utf8, pTargetMD->GetName());
4922 kMethodAccessException,
4923 IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD,
4924 interopMethodName.GetUnicode(),
4925 methodName.GetUnicode()
4929 // The FindMethod call will make sure that it is static by matching signature.
4930 // So there is no need to check and throw
4931 _ASSERTE(pStubMD->IsStatic());
4933 *ppRetStubMD = pStubMD;
4937 #endif // FEATURE_COMINTEROP
4939 MethodDesc* CreateInteropILStub(
4941 StubSigDesc* pSigDesc,
4942 CorNativeLinkType nlType,
4943 CorNativeLinkFlags nlFlags,
4944 CorPinvokeMap unmgdCallConv,
4945 DWORD dwStubFlags, // NDirectStubFlags
4947 mdParamDef* pParamTokenArray,
4951 CONTRACT(MethodDesc*)
4955 PRECONDITION(CheckPointer(pSigDesc));
4956 POSTCONDITION(CheckPointer(RETVAL));
4961 ///////////////////////////////
4963 // MethodDesc creation
4965 ///////////////////////////////
4967 MethodDesc* pStubMD = NULL;
4969 Module* pModule = pSigDesc->m_pModule;
4970 Module* pLoaderModule = pSigDesc->m_pLoaderModule;
4971 MethodDesc* pTargetMD = pSigDesc->m_pMD;
4973 // pTargetMD may be null in the case of calli pinvoke
4974 // and vararg pinvoke.
4977 #ifdef FEATURE_COMINTEROP
4979 // Try to locate predefined IL stub either defined in user code or hardcoded in CLR
4980 // If there is one, use the pointed method as the stub.
4981 // Skip pTargetMD == NULL case for reverse interop calls
4983 if (pTargetMD && SUCCEEDED(FindPredefinedILStubMethod(pTargetMD, dwStubFlags, &pStubMD)))
4985 #ifndef CROSSGEN_COMPILE
4986 // We are about to execute method in pStubMD which could be in another module.
4987 // Call EnsureActive before make the call
4988 // This cannot be done during NGEN/PEVerify (in PASSIVE_DOMAIN) so I've moved it here
4989 pStubMD->EnsureActive();
4991 if (pStubMD->IsPreImplemented())
4992 RestoreNGENedStub(pStubMD);
4997 #endif // FEATURE_COMINTEROP
4999 // Otherwise, fall back to generating IL stub on-the-fly
5000 NDirectStubParameters params(pSigDesc->m_sig,
5001 &pSigDesc->m_typeContext,
5013 // The following two ILStubCreatorHelperHolder are to recover the status when an
5014 // exception happen during the generation of the IL stubs. We need to free the
5015 // memory allocated and restore the ILStubCache.
5017 // The following block is logically divided into two phases. The first phase is
5018 // CreateOrGet IL Stub phase which we take a domain level lock. The second phase
5019 // is IL generation phase which we take a MethodDesc level lock. Taking two locks
5020 // is mainly designed for performance.
5022 // ilStubCreatorHelper contains an instance of AllocMemTracker which tracks the
5023 // allocated memory during the creation of MethodDesc so that we are able to remove
5024 // them when releasing the ILStubCreatorHelperHolder or destructing ILStubCreatorHelper
5026 // When removing IL Stub from Cache, we have a constraint that only the thread which
5027 // creates the stub can remove it. Otherwise, any thread hits cache and gets the stub will
5028 // remove it from cache if OOM occurs
5031 ILStubCreatorHelper ilStubCreatorHelper(pTargetMD, ¶ms);
5033 // take the domain level lock
5034 ListLockHolder pILStubLock(pLoaderModule->GetDomain()->GetILStubGenLock());
5037 // The holder will free the allocated MethodDesc and restore the ILStubCache
5038 // if exception happen.
5039 ILStubCreatorHelperHolder pCreateOrGetStubHolder(&ilStubCreatorHelper);
5040 pStubMD = pCreateOrGetStubHolder->GetStubMD();
5042 ///////////////////////////////
5046 ///////////////////////////////
5049 // take the MethodDesc level locker
5050 ListLockEntryHolder pEntry(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5052 ListLockEntryLockHolder pEntryLock(pEntry, FALSE);
5054 // We can release the holder for the first phase now
5055 pCreateOrGetStubHolder.SuppressRelease();
5058 // The holder will free the allocated MethodDesc and restore the ILStubCache
5059 // if exception happen. The reason to get the holder again is to
5060 ILStubCreatorHelperHolder pGenILHolder(&ilStubCreatorHelper);
5062 if (!pEntryLock.DeadlockAwareAcquire())
5064 // the IL generation is not recursive!
5065 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5068 if (SF_IsSharedStub(params.m_dwStubFlags))
5070 // Assure that pStubMD we have now has not been destroyed by other threads
5071 pGenILHolder->GetStubMethodDesc();
5073 while (pStubMD != pGenILHolder->GetStubMD())
5075 pStubMD = pGenILHolder->GetStubMD();
5077 pEntry.Assign(ListLockEntry::Find(pILStubLock, pStubMD, "il stub gen lock"));
5078 pEntryLock.Assign(pEntry, FALSE);
5080 if (!pEntryLock.DeadlockAwareAcquire())
5082 // the IL generation is not recursive!
5083 UNREACHABLE_MSG("unexpected deadlock in IL stub generation!");
5086 pGenILHolder->GetStubMethodDesc();
5092 // We have the entry lock now, we can release the global lock
5093 pILStubLock.Release();
5095 if (pEntry->m_hrResultCode != S_FALSE)
5097 // We came in to generate the IL but someone
5098 // beat us so there's nothing to do
5102 ILStubResolver* pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver();
5104 CONSISTENCY_CHECK((NULL == pResolver->GetStubMethodDesc()) || (pStubMD == pResolver->GetStubMethodDesc()));
5106 if (pResolver->IsILGenerated())
5108 // this stub already has its IL generated
5113 // Check that the stub signature and MethodDesc are compatible. The JIT
5114 // interface functions depend on this.
5118 SigPointer ptr = pSigDesc->m_sig.CreateSigPointer();
5121 IfFailThrow(ptr.GetCallingConvInfo(&callConvInfo));
5123 BOOL fSigIsStatic = !(callConvInfo & IMAGE_CEE_CS_CALLCONV_HASTHIS);
5125 // CreateNDirectStubWorker will throw an exception for these cases.
5126 BOOL fCanHaveThis = SF_IsDelegateStub(dwStubFlags) || SF_IsCOMStub(dwStubFlags);
5128 if (fSigIsStatic || fCanHaveThis)
5130 CONSISTENCY_CHECK(pStubMD->IsStatic() == (DWORD)fSigIsStatic);
5135 ILStubGenHolder sgh(pResolver);
5137 pResolver->SetStubMethodDesc(pStubMD);
5138 pResolver->SetStubTargetMethodDesc(pTargetMD);
5140 CreateNDirectStubWorker(pss,
5150 pResolver->SetTokenLookupMap(pss->GetTokenLookupMap());
5152 pResolver->SetStubTargetMethodSig(
5153 pss->GetStubTargetMethodSig(),
5154 pss->GetStubTargetMethodSigLength());
5156 // we successfully generated the IL stub
5157 sgh.SuppressRelease();
5160 pEntry->m_hrResultCode = S_OK;
5164 // Link the MethodDesc onto the method table with the lock taken
5165 NDirect::AddMethodDescChunkWithLockTaken(¶ms, pStubMD);
5167 pGenILHolder.SuppressRelease();
5171 ilStubCreatorHelper.SuppressRelease();
5174 #if defined(_TARGET_X86_)
5175 if (SF_IsForwardStub(dwStubFlags) && pTargetMD != NULL && !pTargetMD->IsVarArg())
5177 // copy the stack arg byte count from the stub MD to the target MD - this number is computed
5178 // during stub generation and is copied to all target MDs that share the stub
5179 // (we don't set it for varargs - the number is call site specific)
5180 // also copy the "takes parameters with copy constructors" flag which is needed to generate
5181 // appropriate intercept stub
5183 WORD cbStackArgSize = pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize();
5184 BOOL fHasCopyCtorArgs = pStubMD->AsDynamicMethodDesc()->HasCopyCtorArgs();
5186 if (pTargetMD->IsNDirect())
5188 NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
5190 pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
5191 pTargetNMD->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5193 #ifdef FEATURE_COMINTEROP
5196 if (SF_IsCOMStub(dwStubFlags))
5198 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pTargetMD);
5200 if (pComInfo != NULL)
5202 pComInfo->SetStackArgumentSize(cbStackArgSize);
5203 pComInfo->SetHasCopyCtorArgs(fHasCopyCtorArgs);
5207 #endif // FEATURE_COMINTEROP
5209 #endif // defined(_TARGET_X86_)
5214 MethodDesc* NDirect::CreateCLRToNativeILStub(
5215 StubSigDesc* pSigDesc,
5216 CorNativeLinkType nlType,
5217 CorNativeLinkFlags nlFlags,
5218 CorPinvokeMap unmgdCallConv,
5219 DWORD dwStubFlags) // NDirectStubFlags
5221 CONTRACT(MethodDesc*)
5225 PRECONDITION(CheckPointer(pSigDesc));
5226 POSTCONDITION(CheckPointer(RETVAL));
5232 int numParamTokens = 0;
5233 mdParamDef* pParamTokenArray = NULL;
5235 CreateNDirectStubAccessMetadata(pSigDesc,
5241 Module *pModule = pSigDesc->m_pModule;
5242 numParamTokens = numArgs + 1;
5243 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5244 CollateParamTokens(pModule->GetMDImport(), pSigDesc->m_tkMethodDef, numArgs, pParamTokenArray);
5246 // for interop vectors that have declarative security, we need
5247 // to update the stub flags to ensure a unique stub hash
5248 // is generated based on the marshalling signature AND
5249 // any declarative security.
5250 // IMPORTANT: This will only inject the security callouts for
5251 // interop functionality which has a non-null target MethodDesc.
5252 // Currently, this is known to exclude things like native
5253 // function ptrs. It is assumed that if the target is not
5254 // attribute'able for metadata, then it cannot have declarative
5255 // security - and that the target is not attributable if it was
5256 // not passed to this function.
5257 MethodDesc *pMD = pSigDesc->m_pMD;
5258 if (pMD != NULL && SF_IsForwardStub(dwStubFlags))
5260 // In an AppX process there is only one fully trusted AppDomain, so there is never any need to insert
5261 // a security callout on the stubs.
5262 if (!AppX::IsAppXProcess())
5264 #ifdef FEATURE_COMINTEROP
5265 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5267 // To preserve Whidbey behavior, we only enforce the implicit demand for
5268 // unmanaged code permission.
5269 MethodTable* pMT = ComPlusCallInfo::FromMethodDesc(pMD)->m_pInterfaceMT;
5270 if (pMT->ClassRequiresUnmanagedCodeCheck() &&
5271 !pMD->HasSuppressUnmanagedCodeAccessAttr())
5273 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5277 #endif // FEATURE_COMPINTEROP
5278 if (pMD->IsInterceptedForDeclSecurity())
5280 dwStubFlags |= NDIRECTSTUB_FL_HASDECLARATIVESECURITY;
5285 NewHolder<ILStubState> pStubState;
5287 #ifdef FEATURE_COMINTEROP
5288 if (SF_IsCOMStub(dwStubFlags))
5290 if (SF_IsReverseStub(dwStubFlags))
5292 pStubState = new COMToCLR_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5296 pStubState = new CLRToCOM_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, iLCIDArg, pMD);
5302 pStubState = new PInvoke_ILStubState(pModule, pSigDesc->m_sig, &pSigDesc->m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, pMD);
5305 MethodDesc* pStubMD;
5306 pStubMD = CreateInteropILStub(
5322 #ifdef FEATURE_COMINTEROP
5323 MethodDesc* NDirect::CreateFieldAccessILStub(
5324 PCCOR_SIGNATURE szMetaSig,
5325 DWORD cbMetaSigSize,
5328 DWORD dwStubFlags, // NDirectStubFlags
5331 CONTRACT(MethodDesc*)
5335 PRECONDITION(CheckPointer(szMetaSig));
5336 PRECONDITION(CheckPointer(pModule));
5337 PRECONDITION(CheckPointer(pFD, NULL_OK));
5338 PRECONDITION(SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags));
5339 POSTCONDITION(CheckPointer(RETVAL));
5343 int numArgs = (SF_IsFieldSetterStub(dwStubFlags) ? 1 : 0);
5344 int numParamTokens = numArgs + 1;
5346 // make sure we capture marshaling metadata
5347 mdParamDef* pParamTokenArray = (mdParamDef *)_alloca(numParamTokens * sizeof(mdParamDef));
5348 pParamTokenArray[0] = mdParamDefNil;
5349 pParamTokenArray[numArgs] = (mdParamDef)fd;
5351 // fields are never preserve-sig
5352 dwStubFlags |= NDIRECTSTUB_FL_DOHRESULTSWAPPING;
5354 // convert field signature to getter/setter signature
5355 SigBuilder sigBuilder;
5357 sigBuilder.AppendData(IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS);
5358 sigBuilder.AppendData(numArgs);
5360 if (SF_IsFieldSetterStub(dwStubFlags))
5362 // managed setter returns void
5363 sigBuilder.AppendElementType(ELEMENT_TYPE_VOID);
5366 CONSISTENCY_CHECK(*szMetaSig == IMAGE_CEE_CS_CALLCONV_FIELD);
5368 sigBuilder.AppendBlob((const PVOID)(szMetaSig + 1), cbMetaSigSize - 1);
5369 szMetaSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbMetaSigSize);
5371 StubSigDesc sigDesc(NULL, Signature(szMetaSig, cbMetaSigSize), pModule);
5374 sigDesc.m_pDebugName = pFD->GetDebugName();
5375 sigDesc.m_pDebugClassName = pFD->GetEnclosingMethodTable()->GetDebugClassName();
5378 Signature signature(szMetaSig, cbMetaSigSize);
5379 NewHolder<ILStubState> pStubState = new COMToCLRFieldAccess_ILStubState(pModule, signature, &sigDesc.m_typeContext, dwStubFlags, pFD);
5381 MethodDesc* pStubMD;
5382 pStubMD = CreateInteropILStub(
5385 (CorNativeLinkType)0,
5386 (CorNativeLinkFlags)0,
5395 #endif // FEATURE_COMINTEROP
5397 MethodDesc* NDirect::CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
5401 STANDARD_VM_CONTRACT;
5403 StubSigDesc sigDesc(pMD, pSigInfo);
5405 if (SF_IsWinRTDelegateStub(dwStubFlags))
5407 _ASSERTE(pMD->IsEEImpl());
5409 return CreateCLRToNativeILStub(&sigDesc,
5410 (CorNativeLinkType)0,
5411 (CorNativeLinkFlags)0,
5413 (pSigInfo->GetStubFlags() | dwStubFlags) & ~NDIRECTSTUB_FL_DELEGATE);
5417 return CreateCLRToNativeILStub(&sigDesc,
5418 pSigInfo->GetCharSet(),
5419 pSigInfo->GetLinkFlags(),
5420 pSigInfo->GetCallConv(),
5421 pSigInfo->GetStubFlags() | dwStubFlags);
5425 MethodDesc* NDirect::GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags)
5427 STANDARD_VM_CONTRACT;
5429 MethodDesc* pStubMD = NULL;
5431 if (!pNMD->IsVarArgs() || SF_IsForNumParamBytes(dwStubFlags))
5433 if (pNMD->IsClassConstructorTriggeredByILStub())
5435 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
5438 pStubMD = CreateCLRToNativeILStub(
5440 dwStubFlags & ~NDIRECTSTUB_FL_FOR_NUMPARAMBYTES,
5447 MethodDesc* GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
5449 STANDARD_VM_CONTRACT;
5451 BOOL fGcMdaEnabled = FALSE;
5452 #ifdef MDA_SUPPORTED
5453 if (MDA_GET_ASSISTANT(GcManagedToUnmanaged) || MDA_GET_ASSISTANT(GcUnmanagedToManaged))
5455 // We never generate checks for these MDAs to NGEN'ed stubs so if they are
5456 // enabled, a new stub must be generated (the perf impact is huge anyway).
5457 fGcMdaEnabled = TRUE;
5459 #endif // MDA_SUPPORTED
5461 #ifdef FEATURE_COMINTEROP
5462 if (SF_IsReverseCOMStub(dwStubFlags))
5467 // reverse COM stubs live in a hash table
5468 StubMethodHashTable *pHash = pMD->GetLoaderModule()->GetStubMethodHashTable();
5469 return (pHash == NULL ? NULL : pHash->FindMethodDesc(pMD));
5472 #endif // FEATURE_COMINTEROP
5473 if (pMD->IsNDirect())
5475 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5476 return ((fGcMdaEnabled && !pNMD->IsQCall()) ? NULL : pNMD->ndirect.m_pStubMD.GetValueMaybeNull());
5478 #ifdef FEATURE_COMINTEROP
5479 else if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5481 #ifdef MDA_SUPPORTED
5482 if (MDA_GET_ASSISTANT(RaceOnRCWCleanup))
5484 // we never generate this callout to NGEN'ed stubs
5487 #endif // MDA_SUPPORTED
5489 if (NDirect::IsHostHookEnabled())
5491 MethodTable *pMT = pMD->GetMethodTable();
5492 if (pMT->IsProjectedFromWinRT() || pMT->IsWinRTRedirectedInterface(TypeHandle::Interop_ManagedToNative))
5494 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5495 // must be rejected if we are hosted.
5503 ComPlusCallInfo *pComInfo = ComPlusCallInfo::FromMethodDesc(pMD);
5504 return (pComInfo == NULL ? NULL : pComInfo->m_pStubMD.GetValueMaybeNull());
5506 #endif // FEATURE_COMINTEROP
5507 else if (pMD->IsEEImpl())
5512 DelegateEEClass *pClass = (DelegateEEClass *)pMD->GetClass();
5513 if (SF_IsReverseStub(dwStubFlags))
5515 return pClass->m_pReverseStubMD;
5519 #ifdef FEATURE_COMINTEROP
5520 if (SF_IsWinRTDelegateStub(dwStubFlags))
5522 if (NDirect::IsHostHookEnabled() && pMD->GetMethodTable()->IsProjectedFromWinRT())
5524 // WinRT NGENed stubs are optimized for the non-hosted scenario and
5525 // must be rejected if we are hosted.
5529 return pClass->m_pComPlusCallInfo->m_pStubMD.GetValueMaybeNull();
5532 #endif // FEATURE_COMINTEROP
5534 return pClass->m_pForwardStubMD;
5538 else if (pMD->IsIL())
5540 // these are currently only created at runtime, not at NGEN time
5545 UNREACHABLE_MSG("unexpected type of MethodDesc");
5549 #ifndef CROSSGEN_COMPILE
5551 PCODE NDirect::GetStubForILStub(MethodDesc* pManagedMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5557 PRECONDITION(CheckPointer(pManagedMD));
5558 POSTCONDITION(RETVAL != NULL);
5562 // pStubMD, if provided, must be preimplemented.
5563 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5565 if (NULL == *ppStubMD)
5567 PInvokeStaticSigInfo sigInfo(pManagedMD);
5568 *ppStubMD = NDirect::CreateCLRToNativeILStub(&sigInfo, dwStubFlags, pManagedMD);
5571 RETURN JitILStub(*ppStubMD);
5574 PCODE NDirect::GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags)
5576 STANDARD_VM_CONTRACT;
5580 // pStubMD, if provided, must be preimplemented.
5581 CONSISTENCY_CHECK( (*ppStubMD == NULL) || (*ppStubMD)->IsPreImplemented() );
5583 if (NULL == *ppStubMD)
5585 PInvokeStaticSigInfo sigInfo;
5586 NDirect::PopulateNDirectMethodDesc(pNMD, &sigInfo, /* throwOnError = */ !SF_IsForNumParamBytes(dwStubFlags));
5588 *ppStubMD = NDirect::GetILStubMethodDesc(pNMD, &sigInfo, dwStubFlags);
5591 if (SF_IsForNumParamBytes(dwStubFlags))
5596 pStub = JitILStub(*ppStubMD);
5600 CONSISTENCY_CHECK(pNMD->IsVarArgs());
5603 // varargs goes through vararg NDirect stub
5605 pStub = TheVarargNDirectStub(pNMD->HasRetBuffArg());
5608 #ifdef FEATURE_MIXEDMODE // IJW
5609 if (pNMD->IsEarlyBound())
5611 pNMD->InitEarlyBoundNDirectTarget();
5620 // NOTE: there is a race in updating this MethodDesc. We depend on all
5621 // threads getting back the same DynamicMethodDesc for a particular
5622 // NDirectMethodDesc, in that case, the locking around the actual JIT
5623 // operation will prevent the code from being jitted more than once.
5624 // By the time we get here, all threads get the same address of code
5625 // back from the JIT operation and they all just fill in the same value
5628 // In the NGEN case, all threads will get the same preimplemented code
5629 // address much like the JIT case.
5635 PCODE JitILStub(MethodDesc* pStubMD)
5637 STANDARD_VM_CONTRACT;
5639 PCODE pCode = pStubMD->GetNativeCode();
5643 ///////////////////////////////
5647 ///////////////////////////////
5650 if (pStubMD->IsDynamicMethod())
5653 // A dynamically generated IL stub
5656 CORJIT_FLAGS jitFlags = pStubMD->AsDynamicMethodDesc()->GetILStubResolver()->GetJitFlags();
5657 pCode = pStubMD->MakeJitWorker(NULL, jitFlags);
5659 _ASSERTE(pCode == pStubMD->GetNativeCode());
5664 // A static IL stub that is pointing to a static method in user assembly
5665 // Compile it and return the native code
5668 // This returns the stable entry point
5669 pCode = pStubMD->DoPrestub(NULL);
5671 _ASSERTE(pCode == pStubMD->GetStableEntryPoint());
5675 if (!pStubMD->IsDynamicMethod())
5677 // We need an entry point that can be called multiple times
5678 pCode = pStubMD->GetMultiCallableAddrOfCode();
5684 MethodDesc* RestoreNGENedStub(MethodDesc* pStubMD)
5689 PRECONDITION(CheckPointer(pStubMD));
5693 #ifdef FEATURE_PREJIT
5694 pStubMD->CheckRestore();
5696 PCODE pCode = pStubMD->GetPreImplementedCode();
5699 TADDR pFixupList = pStubMD->GetFixupList();
5700 if (pFixupList != NULL)
5702 Module* pZapModule = pStubMD->GetZapModule();
5703 _ASSERTE(pZapModule != NULL);
5704 if (!pZapModule->FixupDelayList(pFixupList))
5706 _ASSERTE(!"FixupDelayList failed");
5707 ThrowHR(COR_E_BADIMAGEFORMAT);
5711 #if defined(HAVE_GCCOVER)
5712 if (GCStress<cfg_instr_ngen>::IsEnabled())
5713 SetupGcCoverage(pStubMD, (BYTE*) pCode);
5714 #endif // HAVE_GCCOVER
5719 // We only pass a non-NULL pStubMD to GetStubForILStub() below if pStubMD is preimplemeneted.
5722 #endif // FEATURE_PREJIT
5727 PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags, MethodDesc **ppStubMD)
5733 PRECONDITION(CheckPointer(pMD));
5734 PRECONDITION(pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsGenericComPlusCall() || pMD->IsEEImpl() || pMD->IsIL());
5739 MethodDesc* pStubMD = NULL;
5741 pStubMD = GetStubMethodDescFromInteropMethodDesc(pMD, dwStubFlags);
5742 if (pStubMD != NULL)
5744 pStubMD = RestoreNGENedStub(pStubMD);
5747 if ((NULL == pStubMD) && (SF_IsNGENedStub(dwStubFlags)))
5749 // Return NULL -- the caller asked only for an ngened stub and
5750 // one does not exist, so don't do any more work.
5751 CONSISTENCY_CHECK(pStub == NULL);
5754 if (pMD->IsNDirect())
5756 NDirectMethodDesc* pNMD = (NDirectMethodDesc*)pMD;
5757 pStub = NDirect::GetStubForILStub(pNMD, &pStubMD, dwStubFlags);
5759 #ifdef FEATURE_COMINTEROP
5761 if (pMD->IsComPlusCall() || pMD->IsGenericComPlusCall())
5763 pStub = ComPlusCall::GetStubForILStub(pMD, &pStubMD);
5765 #endif // FEATURE_COMINTEROP
5767 if (pMD->IsEEImpl())
5769 CONSISTENCY_CHECK(pMD->GetMethodTable()->IsDelegate());
5770 EEImplMethodDesc* pDelegateMD = (EEImplMethodDesc*)pMD;
5771 pStub = COMDelegate::GetStubForILStub(pDelegateMD, &pStubMD, dwStubFlags);
5776 CONSISTENCY_CHECK(SF_IsReverseStub(dwStubFlags));
5777 pStub = NDirect::GetStubForILStub(pMD, &pStubMD, dwStubFlags);
5781 UNREACHABLE_MSG("unexpected MethodDesc type");
5784 if (pStubMD != NULL && pStubMD->IsILStub() && pStubMD->AsDynamicMethodDesc()->IsStubNeedsCOMStarted())
5786 // the stub uses COM so make sure that it is started
5790 if (ppStubMD != NULL)
5791 *EnsureWritablePages(ppStubMD) = pStubMD;
5796 #ifdef FEATURE_COMINTEROP
5797 void CreateCLRToDispatchCOMStub(
5799 DWORD dwStubFlags) // NDirectStubFlags
5805 PRECONDITION(CheckPointer(pMD));
5809 _ASSERTE(SF_IsCOMLateBoundStub(dwStubFlags) || SF_IsCOMEventCallStub(dwStubFlags));
5811 // If we are dealing with a COM event call, then we need to initialize the
5812 // COM event call information.
5813 if (SF_IsCOMEventCallStub(dwStubFlags))
5815 _ASSERTE(pMD->IsComPlusCall()); // no generic COM eventing
5816 ((ComPlusCallMethodDesc *)pMD)->InitComEventCallInfo();
5819 // Get the call signature information
5820 StubSigDesc sigDesc(pMD);
5824 int numParamTokens = 0;
5825 mdParamDef* pParamTokenArray = NULL;
5827 CreateNDirectStubAccessMetadata(&sigDesc,
5833 numParamTokens = numArgs + 1;
5834 pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef));
5835 CollateParamTokens(sigDesc.m_pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray);
5837 DispatchStubState MyStubState;
5839 CreateNDirectStubWorker(&MyStubState,
5841 (CorNativeLinkType)0,
5842 (CorNativeLinkFlags)0,
5844 dwStubFlags | NDIRECTSTUB_FL_COM,
5849 _ASSERTE(pMD->IsComPlusCall()); // no generic disp-calls
5850 ((ComPlusCallMethodDesc *)pMD)->InitRetThunk();
5854 #endif // FEATURE_COMINTEROP
5857 LPVOID NDirect::NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod)
5859 // GetProcAddress cannot be called while preemptive GC is disabled.
5860 // It requires the OS to take the loader lock.
5864 PRECONDITION(CheckPointer(pMD));
5865 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5869 g_IBCLogger.LogNDirectCodeAccess(pMD);
5871 #ifdef MDA_SUPPORTED
5872 MDA_TRIGGER_ASSISTANT(PInvokeLog, LogPInvoke(pMD, hMod));
5875 RETURN pMD->FindEntryPoint(hMod);
5878 VOID NDirectMethodDesc::SetNDirectTarget(LPVOID pTarget)
5886 PRECONDITION(IsNDirect());
5887 PRECONDITION(pTarget != NULL);
5891 Stub *pInterceptStub = NULL;
5895 // Host hooks are not supported for Mac CoreCLR.
5896 if (NDirect::IsHostHookEnabled())
5899 // we will call CallNeedsHostHook on every invocation for back compat
5902 fHook = CallNeedsHostHook((size_t)pTarget);
5906 if (g_pConfig->ShouldGenerateStubForHost())
5916 #ifdef MDA_SUPPORTED
5917 if (!IsQCall() && MDA_GET_ASSISTANT(PInvokeStackImbalance))
5919 pInterceptStub = GenerateStubForMDA(pTarget, pInterceptStub, fHook);
5921 #endif // MDA_SUPPORTED
5923 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
5926 pInterceptStub = GenerateStubForHost(pTarget, pInterceptStub);
5928 #endif // FEATURE_INCLUDE_ALL_INTERFACES
5930 #endif // _TARGET_X86_
5933 NDirectWriteableData* pWriteableData = GetWriteableData();
5934 EnsureWritablePages(pWriteableData);
5935 g_IBCLogger.LogNDirectCodeAccess(this);
5937 if (pInterceptStub != NULL WIN64_ONLY(|| fHook))
5939 ndirect.m_pNativeNDirectTarget = pTarget;
5941 #if defined(_TARGET_X86_)
5942 pTarget = (PVOID)pInterceptStub->GetEntryPoint();
5944 LPVOID oldTarget = GetNDirectImportThunkGlue()->GetEntrypoint();
5945 if (FastInterlockCompareExchangePointer(&pWriteableData->m_pNDirectTarget, pTarget,
5946 oldTarget) != oldTarget)
5948 pInterceptStub->DecRef();
5951 _ASSERTE(pInterceptStub == NULL); // we don't intercept for anything else than host on !_TARGET_X86_
5952 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
5953 pWriteableData->m_pNDirectTarget = (LPVOID)GetEEFuncEntryPoint(PInvokeStubForHost);
5954 #endif // FEATURE_INCLUDE_ALL_INTERFACES
5959 pWriteableData->m_pNDirectTarget = pTarget;
5964 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
5965 BOOL NDirect::IsHostHookEnabled()
5967 WRAPPER_NO_CONTRACT;
5969 // WARNING: The non-debug portion of this logic is inlined into UMThunkStubAMD64!
5971 return CLRTaskHosted() INDEBUG(|| g_pConfig->ShouldGenerateStubForHost());
5974 EXTERN_C BOOL CallNeedsHostHook(size_t target)
5977 IHostTaskManager *pManager = CorHost2::GetHostTaskManager();
5981 BEGIN_SO_TOLERANT_CODE_CALLING_HOST(GetThread());
5982 hr = pManager->CallNeedsHostHook(target,&fHook);
5983 END_SO_TOLERANT_CODE_CALLING_HOST;
5984 _ASSERTE (hr == S_OK);
5989 if (g_pConfig->ShouldGenerateStubForHost())
5997 #endif // FEATURE_INCLUDE_ALL_INTERFACES
5999 #if defined(_TARGET_X86_) && defined(MDA_SUPPORTED)
6000 EXTERN_C VOID __stdcall PInvokeStackImbalanceWorker(StackImbalanceCookie *pSICookie, DWORD dwPostESP)
6002 STATIC_CONTRACT_THROWS;
6003 STATIC_CONTRACT_GC_TRIGGERS;
6004 STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive
6006 // make sure we restore the original Win32 last error before leaving this function - we are
6007 // called right after returning from the P/Invoke target and the error has not been saved yet
6008 BEGIN_PRESERVE_LAST_ERROR;
6010 MdaPInvokeStackImbalance* pProbe = MDA_GET_ASSISTANT(PInvokeStackImbalance);
6012 // This MDA must be active if we generated a call to PInvokeStackImbalanceHelper
6015 pProbe->CheckStack(pSICookie, dwPostESP);
6017 END_PRESERVE_LAST_ERROR;
6019 #endif // _TARGET_X86_ && MDA_SUPPORTED
6022 // Preserving good error info from DllImport-driven LoadLibrary is tricky because we keep loading from different places
6023 // if earlier loads fail and those later loads obliterate error codes.
6025 // This tracker object will keep track of the error code in accordance to priority:
6027 // low-priority: unknown error code (should never happen)
6028 // medium-priority: dll not found
6029 // high-priority: dll found but error during loading
6031 // We will overwrite the previous load's error code only if the new error code is higher priority.
6034 class LoadLibErrorTracker
6037 static const DWORD const_priorityNotFound = 10;
6038 static const DWORD const_priorityAccessDenied = 20;
6039 static const DWORD const_priorityCouldNotLoad = 99999;
6041 LoadLibErrorTracker()
6043 LIMITED_METHOD_CONTRACT;
6045 m_priorityOfLastError = 0;
6048 VOID TrackErrorCode(DWORD dwLastError)
6050 LIMITED_METHOD_CONTRACT;
6054 switch (dwLastError)
6056 case ERROR_FILE_NOT_FOUND:
6057 case ERROR_PATH_NOT_FOUND:
6058 case ERROR_MOD_NOT_FOUND:
6059 case ERROR_DLL_NOT_FOUND:
6060 priority = const_priorityNotFound;
6063 // If we can't access a location, we can't know if the dll's there or if it's good.
6064 // Still, this is probably more unusual (and thus of more interest) than a dll-not-found
6065 // so give it an intermediate priority.
6066 case ERROR_ACCESS_DENIED:
6067 priority = const_priorityAccessDenied;
6069 // Assume all others are "dll found but couldn't load."
6071 priority = const_priorityCouldNotLoad;
6075 UpdateHR(priority, HRESULT_FROM_WIN32(dwLastError));
6078 // Sets the error code to HRESULT as could not load DLL
6079 void TrackHR_CouldNotLoad(HRESULT hr)
6081 UpdateHR(const_priorityCouldNotLoad, hr);
6089 void DECLSPEC_NORETURN Throw(SString &libraryNameOrPath)
6091 STANDARD_VM_CONTRACT;
6093 HRESULT theHRESULT = GetHR();
6094 if (theHRESULT == HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT))
6096 COMPlusThrow(kBadImageFormatException);
6101 GetHRMsg(theHRESULT, hrString);
6102 COMPlusThrow(kDllNotFoundException, IDS_EE_NDIRECT_LOADLIB, libraryNameOrPath.GetUnicode(), hrString);
6109 void UpdateHR(DWORD priority, HRESULT hr)
6111 if (priority > m_priorityOfLastError)
6114 m_priorityOfLastError = priority;
6119 DWORD m_priorityOfLastError;
6120 }; // class LoadLibErrorTracker
6122 // Local helper function for the LoadLibraryModule function below
6123 static HMODULE LocalLoadLibraryHelper( LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker )
6125 STANDARD_VM_CONTRACT;
6127 HMODULE hmod = NULL;
6131 if ((flags & 0xFFFFFF00) != 0
6134 hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFFFFFF00);
6140 DWORD dwLastError = GetLastError();
6141 if (dwLastError != ERROR_INVALID_PARAMETER)
6143 pErrorTracker->TrackErrorCode(dwLastError);
6148 hmod = CLRLoadLibraryEx(name, NULL, flags & 0xFF);
6150 #else // !FEATURE_PAL
6151 hmod = CLRLoadLibrary(name);
6152 #endif // !FEATURE_PAL
6156 pErrorTracker->TrackErrorCode(GetLastError());
6162 // Local helper function for the LoadLibraryFromPath function below
6163 static HMODULE LocalLoadLibraryDirectHelper(LPCWSTR name, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6165 STANDARD_VM_CONTRACT;
6168 return LocalLoadLibraryHelper(name, flags, pErrorTracker);
6169 #else // !FEATURE_PAL
6170 // Load the library directly, and don't register it yet with PAL. The system library handle is required here, not the PAL
6171 // handle. The system library handle is registered with PAL to get a PAL handle in LoadLibraryModuleViaHost().
6172 HMODULE hmod = PAL_LoadLibraryDirect(name);
6176 pErrorTracker->TrackErrorCode(GetLastError());
6180 #endif // !FEATURE_PAL
6185 #define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
6186 #define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
6190 HMODULE NDirect::LoadLibraryFromPath(LPCWSTR libraryPath)
6192 STANDARD_VM_CONTRACT;
6194 LoadLibErrorTracker errorTracker;
6195 const HMODULE systemModuleHandle =
6196 LocalLoadLibraryDirectHelper(libraryPath, GetLoadWithAlteredSearchPathFlag(), &errorTracker);
6197 if (systemModuleHandle == nullptr)
6199 SString libraryPathSString(libraryPath);
6200 errorTracker.Throw(libraryPathSString);
6202 return systemModuleHandle;
6205 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6207 HMODULE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName)
6209 STANDARD_VM_CONTRACT;
6210 //Dynamic Pinvoke Support:
6211 //Check if we need to provide the host a chance to provide the unmanaged dll
6213 #ifndef PLATFORM_UNIX
6214 // Prevent Overriding of Windows API sets.
6215 // This is replicating quick check from the OS implementation of api sets.
6216 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6223 CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext();
6224 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6226 PEFile *pManifestFile = pAssembly->GetManifestFile();
6227 PTR_ICLRPrivBinder pBindingContext = pManifestFile->GetBindingContext();
6229 //Step 0: Check if the assembly was bound using TPA.
6230 // The Binding Context can be null or an overridden TPA context
6231 if (pBindingContext == NULL)
6233 pBindingContext = nullptr;
6235 // If the assembly does not have a binder associated with it explicitly, then check if it is
6236 // a dynamic assembly, or not, since they can have a fallback load context associated with them.
6237 if (pManifestFile->IsDynamic())
6239 pBindingContext = pManifestFile->GetFallbackLoadContextBinder();
6243 // If we do not have any binder associated, then return to the default resolution mechanism.
6244 if (pBindingContext == nullptr)
6249 UINT_PTR assemblyBinderID = 0;
6250 IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID));
6252 ICLRPrivBinder *pCurrentBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
6254 // For assemblies bound via TPA binder, we should use the standard mechanism to make the pinvoke call.
6255 if (AreSameBinderInstance(pCurrentBinder, pTPABinder))
6260 #ifdef FEATURE_COMINTEROP
6261 CLRPrivBinderWinRT *pWinRTBinder = pDomain->GetWinRtBinder();
6262 if (AreSameBinderInstance(pCurrentBinder, pWinRTBinder))
6264 // We could be here when a non-WinRT assembly load is triggerred by a winmd (e.g. System.Runtime being loaded due to
6265 // types being referenced from Windows.Foundation.Winmd) or when dealing with a winmd (which is bound using WinRT binder).
6267 // For this, we should use the standard mechanism to make pinvoke call as well.
6270 #endif // FEATURE_COMINTEROP
6272 //Step 1: If the assembly was not bound using TPA,
6273 // Call System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll to give
6274 // The custom assembly context a chance to load the unmanaged dll.
6278 STRINGREF pUnmanagedDllName;
6279 pUnmanagedDllName = StringObject::NewString(wszLibName);
6281 GCPROTECT_BEGIN(pUnmanagedDllName);
6283 // Get the pointer to the managed assembly load context
6284 INT_PTR ptrManagedAssemblyLoadContext = ((CLRPrivBinderAssemblyLoadContext *)pCurrentBinder)->GetManagedAssemblyLoadContext();
6286 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.ResolveUnamanagedDll method.
6287 PREPARE_NONVIRTUAL_CALLSITE(METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUNMANAGEDDLL);
6288 DECLARE_ARGHOLDER_ARRAY(args, 2);
6289 args[ARGNUM_0] = STRINGREF_TO_ARGHOLDER(pUnmanagedDllName);
6290 args[ARGNUM_1] = PTR_TO_ARGHOLDER(ptrManagedAssemblyLoadContext);
6293 CALL_MANAGED_METHOD(hmod,LPVOID,args);
6298 if (hmod != nullptr)
6300 // Register the system library handle with PAL and get a PAL library handle
6301 hmod = PAL_RegisterLibraryDirect(hmod, wszLibName);
6303 #endif // FEATURE_PAL
6305 return (HMODULE)hmod;
6307 #endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6309 // Try to load the module alongside the assembly where the PInvoke was declared.
6310 HMODULE NDirect::LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6312 STANDARD_VM_CONTRACT;
6314 HMODULE hmod = NULL;
6316 SString path = pAssembly->GetManifestFile()->GetPath();
6318 SString::Iterator lastPathSeparatorIter = path.End();
6319 if (PEAssembly::FindLastPathSeparator(path, lastPathSeparatorIter))
6321 lastPathSeparatorIter++;
6322 path.Truncate(lastPathSeparatorIter);
6324 path.Append(libName);
6325 hmod = LocalLoadLibraryHelper(path, flags, pErrorTracker);
6331 // Try to load the module from the native DLL search directories
6332 HMODULE NDirect::LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker)
6334 STANDARD_VM_CONTRACT;
6336 HMODULE hmod = NULL;
6338 if (pDomain->HasNativeDllSearchDirectories())
6340 AppDomain::PathIterator pathIter = pDomain->IterateNativeDllSearchDirectories();
6341 while (hmod == NULL && pathIter.Next())
6343 SString qualifiedPath(*(pathIter.GetPath()));
6344 qualifiedPath.Append(libName);
6345 if (!Path::IsRelative(qualifiedPath))
6347 hmod = LocalLoadLibraryHelper(qualifiedPath, flags, pErrorTracker);
6355 HINSTANCE NDirect::LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker)
6360 PRECONDITION( CheckPointer( pMD ) );
6364 LPCUTF8 name = pMD->GetLibName();
6365 if ( !name || !*name )
6368 ModuleHandleHolder hmod;
6370 DWORD loadWithAlteredPathFlags = GetLoadWithAlteredSearchPathFlag();
6372 PREFIX_ASSUME( name != NULL );
6373 MAKE_WIDEPTR_FROMUTF8( wszLibName, name );
6375 AppDomain* pDomain = GetAppDomain();
6377 #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
6378 // AssemblyLoadContext is not supported in AppX mode and thus,
6379 // we should not perform PInvoke resolution via it when operating in
6381 if (!AppX::IsAppXProcess())
6383 hmod = LoadLibraryModuleViaHost(pMD, pDomain, wszLibName);
6385 #endif //FEATURE_HOST_ASSEMBLY_RESOLVER
6390 hmod = pDomain->FindUnmanagedImageInCache(wszLibName);
6395 return hmod.Extract();
6400 // In the PAL version of CoreCLR, the CLR module itself exports the functionality
6401 // that the Windows version obtains from kernel32 and friends. In order to avoid
6402 // picking up the wrong instance, we perform this redirection first.
6403 // This is also true for CoreSystem builds, where mscorlib p/invokes are forwarded through coreclr
6404 // itself so we can control CoreSystem library/API name re-mapping from one central location.
6405 if (SString::_wcsicmp(wszLibName, MAIN_CLR_MODULE_NAME_W) == 0)
6406 hmod = GetCLRModule();
6407 #endif // FEATURE_PAL
6409 #if !defined(PLATFORM_UNIX)
6412 // Try to go straight to System32 for Windows API sets. This is replicating quick check from
6413 // the OS implementation of api sets.
6414 if (SString::_wcsnicmp(wszLibName, W("api-"), 4) == 0 || SString::_wcsnicmp(wszLibName, W("ext-"), 4) == 0)
6416 hmod = LocalLoadLibraryHelper(wszLibName, LOAD_LIBRARY_SEARCH_SYSTEM32, pErrorTracker);
6419 #endif // FEATURE_CORESYSTEM && !FEATURE_PAL
6423 // NATIVE_DLL_SEARCH_DIRECTORIES set by host is considered well known path
6424 hmod = LoadFromNativeDllSearchDirectories(pDomain, wszLibName, loadWithAlteredPathFlags, pErrorTracker);
6427 DWORD dllImportSearchPathFlag = 0;
6428 BOOL searchAssemblyDirectory = TRUE;
6429 bool libNameIsRelativePath = Path::IsRelative(wszLibName);
6432 // First checks if the method has DefaultDllImportSearchPathsAttribute. If method has the attribute
6433 // then dllImportSearchPathFlag is set to its value.
6434 // Otherwise checks if the assembly has the attribute.
6435 // If assembly has the attribute then flag ise set to its value.
6436 BOOL attributeIsFound = FALSE;
6438 if (pMD->HasDefaultDllImportSearchPathsAttribute())
6440 dllImportSearchPathFlag = pMD->DefaultDllImportSearchPathsAttributeCachedValue();
6441 searchAssemblyDirectory = pMD->DllImportSearchAssemblyDirectory();
6442 attributeIsFound = TRUE;
6446 Module * pModule = pMD->GetModule();
6448 if(pModule->HasDefaultDllImportSearchPathsAttribute())
6450 dllImportSearchPathFlag = pModule->DefaultDllImportSearchPathsAttributeCachedValue();
6451 searchAssemblyDirectory = pModule->DllImportSearchAssemblyDirectory();
6452 attributeIsFound = TRUE;
6457 if (!libNameIsRelativePath)
6459 DWORD flags = loadWithAlteredPathFlags;
6460 if ((dllImportSearchPathFlag & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) != 0)
6462 // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR is the only flag affecting absolute path. Don't OR the flags
6463 // unconditionally as all absolute path P/Invokes could then lose LOAD_WITH_ALTERED_SEARCH_PATH.
6464 flags |= dllImportSearchPathFlag;
6467 hmod = LocalLoadLibraryHelper(wszLibName, flags, pErrorTracker);
6469 else if (searchAssemblyDirectory)
6471 Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
6472 hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, wszLibName, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6477 // This call searches the application directory instead of the location for the library.
6480 hmod = LocalLoadLibraryHelper(wszLibName, dllImportSearchPathFlag, pErrorTracker);
6483 // This may be an assembly name
6486 // Format is "fileName, assemblyDisplayName"
6487 MAKE_UTF8PTR_FROMWIDE(szLibName, wszLibName);
6488 char *szComma = strchr(szLibName, ',');
6492 while (COMCharacter::nativeIsWhiteSpace(*(++szComma)));
6495 if (SUCCEEDED(spec.Init(szComma)))
6497 // Need to perform case insensitive hashing.
6500 UTF8_TO_LOWER_CASE(szLibName, qbLC);
6501 szLibName = (LPUTF8) qbLC.Ptr();
6504 Assembly *pAssembly = spec.LoadAssembly(FILE_LOADED);
6505 Module *pModule = pAssembly->FindModuleByName(szLibName);
6507 hmod = LocalLoadLibraryHelper(pModule->GetPath(), loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6515 // P/Invokes are often declared with variations on the actual library name.
6516 // For example, it's common to leave off the extension/suffix of the library
6517 // even if it has one, or to leave off a prefix like "lib" even if it has one
6518 // (both of these are typically done to smooth over cross-platform differences).
6519 // We try to dlopen with such variations on the original.
6520 const char* const prefixSuffixCombinations[] =
6522 "%s%s%s", // prefix+name+suffix
6523 "%.0s%s%s", // name+suffix
6524 "%s%s%.0s", // prefix+name
6527 const int NUMBER_OF_LIB_NAME_VARIATIONS = COUNTOF(prefixSuffixCombinations);
6529 // Try to load from places we tried above, but this time with variations on the
6530 // name including the prefix, suffix, and both.
6531 for (int i = 0; i < NUMBER_OF_LIB_NAME_VARIATIONS; i++)
6533 SString currLibNameVariation;
6534 currLibNameVariation.Printf(prefixSuffixCombinations[i], PAL_SHLIB_PREFIX, name, PAL_SHLIB_SUFFIX);
6536 if (libNameIsRelativePath && searchAssemblyDirectory)
6538 Assembly *pAssembly = pMD->GetMethodTable()->GetAssembly();
6539 hmod = LoadFromPInvokeAssemblyDirectory(pAssembly, currLibNameVariation, loadWithAlteredPathFlags | dllImportSearchPathFlag, pErrorTracker);
6544 hmod = LoadFromNativeDllSearchDirectories(pDomain, currLibNameVariation, loadWithAlteredPathFlags, pErrorTracker);
6548 hmod = LocalLoadLibraryHelper(currLibNameVariation, dllImportSearchPathFlag, pErrorTracker);
6553 #endif // FEATURE_PAL
6555 // After all this, if we have a handle add it to the cache.
6558 pDomain->AddUnmanagedImageToCache(wszLibName, hmod);
6561 return hmod.Extract();
6564 //---------------------------------------------------------
6565 // Loads the DLL and finds the procaddress for an N/Direct call.
6566 //---------------------------------------------------------
6568 VOID NDirect::NDirectLink(NDirectMethodDesc *pMD)
6573 PRECONDITION(CheckPointer(pMD));
6578 // On the phone, we only allow platform assemblies to define pinvokes
6579 // unless the host has asked us otherwise.
6582 if (pMD->IsClassConstructorTriggeredAtLinkTime())
6584 pMD->GetMethodTable()->CheckRunClassInitThrowing();
6589 LPVOID pvTarget = pMD->ndirect.m_pNativeNDirectTarget;
6591 // Do not repeat the lookup if the QCall was hardbound during ngen
6592 if (pvTarget == NULL)
6594 pvTarget = ECall::GetQCallImpl(pMD);
6598 _ASSERTE(pvTarget == ECall::GetQCallImpl(pMD));
6601 pMD->SetNDirectTarget(pvTarget);
6605 // Loading unmanaged dlls can trigger dllmains which certainly count as code execution!
6606 pMD->EnsureActive();
6608 LoadLibErrorTracker errorTracker;
6610 BOOL fSuccess = FALSE;
6611 HINSTANCE hmod = LoadLibraryModule( pMD, &errorTracker );
6614 LPVOID pvTarget = NDirectGetEntryPoint(pMD, hmod);
6618 #ifdef MDA_SUPPORTED
6619 MdaInvalidOverlappedToPinvoke *pOverlapCheck = MDA_GET_ASSISTANT(InvalidOverlappedToPinvoke);
6620 if (pOverlapCheck && pOverlapCheck->ShouldHook(pMD))
6622 LPVOID pNewTarget = pOverlapCheck->Register(hmod,pvTarget);
6625 pvTarget = pNewTarget;
6629 pMD->SetNDirectTarget(pvTarget);
6636 if (pMD->GetLibName() == NULL)
6637 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS_NONAME);
6639 StackSString ssLibName(SString::Utf8, pMD->GetLibName());
6643 errorTracker.Throw(ssLibName);
6646 WCHAR wszEPName[50];
6647 if(WszMultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pMD->GetEntrypointName(), -1, wszEPName, sizeof(wszEPName)/sizeof(WCHAR)) == 0)
6649 wszEPName[0] = W('?');
6650 wszEPName[1] = W('\0');
6653 COMPlusThrow(kEntryPointNotFoundException, IDS_EE_NDIRECT_GETPROCADDRESS, ssLibName.GetUnicode(), wszEPName);
6658 //---------------------------------------------------------
6660 //---------------------------------------------------------
6661 /*static*/ void NDirect::Init()
6668 INJECT_FAULT(COMPlusThrowOM());
6675 //==========================================================================
6676 // This function is reached only via NDirectImportThunk. It's purpose
6677 // is to ensure that the target DLL is fully loaded and ready to run.
6679 // FUN FACTS: Though this function is actually entered in unmanaged mode,
6680 // it can reenter managed mode and throw a COM+ exception if the DLL linking
6682 //==========================================================================
6685 EXTERN_C LPVOID STDCALL NDirectImportWorker(NDirectMethodDesc* pMD)
6689 BEGIN_PRESERVE_LAST_ERROR;
6700 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
6701 // this function is called by CLR to native assembly stubs which are called by
6702 // managed code as a result, we need an unwind and continue handler to translate
6703 // any of our internal exceptions into managed exceptions.
6704 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
6706 #ifdef FEATURE_MIXEDMODE // IJW
6707 if (pMD->IsEarlyBound())
6709 if (!pMD->IsZapped())
6711 // we need the MD to be populated in case we decide to build an intercept
6712 // stub to wrap the target in InitEarlyBoundNDirectTarget
6713 PInvokeStaticSigInfo sigInfo;
6714 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
6717 pMD->InitEarlyBoundNDirectTarget();
6720 #endif // FEATURE_MIXEDMODE
6723 // Otherwise we're in an inlined pinvoke late bound MD
6725 INDEBUG(Thread *pThread = GetThread());
6727 _ASSERTE(pThread->GetFrame()->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr());
6729 CONSISTENCY_CHECK(pMD->IsNDirect());
6731 // With IL stubs, we don't have to do anything but ensure the DLL is loaded.
6734 if (!pMD->GetModule()->GetSecurityDescriptor()->CanCallUnmanagedCode())
6735 Security::ThrowSecurityException(g_SecurityPermissionClassName, SPFLAGSUNMANAGEDCODE);
6737 if (!pMD->IsZapped())
6739 PInvokeStaticSigInfo sigInfo;
6740 NDirect::PopulateNDirectMethodDesc(pMD, &sigInfo);
6744 // must have been populated at NGEN time
6745 _ASSERTE(pMD->GetLibName() != NULL);
6748 pMD->CheckRestore();
6750 NDirect::NDirectLink(pMD);
6754 ret = pMD->GetNDirectTarget();
6756 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
6757 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
6759 END_PRESERVE_LAST_ERROR;
6764 //===========================================================================
6765 // Support for Pinvoke Calli instruction
6767 //===========================================================================
6769 EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock * pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD)
6771 BEGIN_PRESERVE_LAST_ERROR;
6773 STATIC_CONTRACT_THROWS;
6774 STATIC_CONTRACT_GC_TRIGGERS;
6775 STATIC_CONTRACT_MODE_COOPERATIVE;
6776 STATIC_CONTRACT_ENTRY_POINT;
6778 MAKE_CURRENT_THREAD_AVAILABLE();
6781 Thread::ObjectRefFlush(CURRENT_THREAD);
6784 FrameWithCookie<PrestubMethodFrame> frame(pTransitionBlock, pMD);
6785 PrestubMethodFrame * pFrame = &frame;
6787 pFrame->Push(CURRENT_THREAD);
6789 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
6790 _ASSERTE(pMD == pFrame->GetFunction());
6792 GetILStubForCalli(pVASigCookie, pMD);
6794 pFrame->Pop(CURRENT_THREAD);
6796 END_PRESERVE_LAST_ERROR;
6799 EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget)
6801 BEGIN_PRESERVE_LAST_ERROR;
6803 STATIC_CONTRACT_THROWS;
6804 STATIC_CONTRACT_GC_TRIGGERS;
6805 STATIC_CONTRACT_MODE_COOPERATIVE;
6806 STATIC_CONTRACT_ENTRY_POINT;
6808 MAKE_CURRENT_THREAD_AVAILABLE();
6811 Thread::ObjectRefFlush(CURRENT_THREAD);
6814 FrameWithCookie<PInvokeCalliFrame> frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget);
6815 PInvokeCalliFrame * pFrame = &frame;
6817 pFrame->Push(CURRENT_THREAD);
6819 _ASSERTE(pVASigCookie == pFrame->GetVASigCookie());
6821 GetILStubForCalli(pVASigCookie, NULL);
6823 pFrame->Pop(CURRENT_THREAD);
6825 END_PRESERVE_LAST_ERROR;
6828 PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
6836 PRECONDITION(CheckPointer(pVASigCookie));
6837 PRECONDITION(CheckPointer(pMD, NULL_OK));
6838 POSTCONDITION(RETVAL != NULL);
6842 PCODE pTempILStub = NULL;
6844 INSTALL_MANAGED_EXCEPTION_DISPATCHER;
6845 // this function is called by CLR to native assembly stubs which are called by
6846 // managed code as a result, we need an unwind and continue handler to translate
6847 // any of our internal exceptions into managed exceptions.
6848 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
6850 // Force a GC if the stress level is high enough
6851 GCStress<cfg_any>::MaybeTrigger();
6855 Signature signature = pVASigCookie->signature;
6856 CorPinvokeMap unmgdCallConv = pmNoMangle;
6858 DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
6860 // The MethodDesc pointer may in fact be the unmanaged target, see PInvokeStubs.asm.
6861 if (pMD == NULL || (UINT_PTR)pMD & 0x1)
6864 dwStubFlags |= NDIRECTSTUB_FL_UNMANAGED_CALLI;
6866 // need to convert the CALLI signature to stub signature with managed calling convention
6867 switch (MetaSig::GetCallingConvention(pVASigCookie->pModule, pVASigCookie->signature))
6869 case IMAGE_CEE_CS_CALLCONV_C:
6870 unmgdCallConv = pmCallConvCdecl;
6872 case IMAGE_CEE_CS_CALLCONV_STDCALL:
6873 unmgdCallConv = pmCallConvStdcall;
6875 case IMAGE_CEE_CS_CALLCONV_THISCALL:
6876 unmgdCallConv = pmCallConvThiscall;
6878 case IMAGE_CEE_CS_CALLCONV_FASTCALL:
6879 unmgdCallConv = pmCallConvFastcall;
6882 COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
6885 LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
6886 PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
6887 CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
6889 // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT
6890 *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK;
6891 *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT;
6893 signature = Signature(new_sig, signature.GetRawSigLen());
6897 _ASSERTE(pMD->IsNDirect());
6898 dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
6900 // vararg P/Invoke must be cdecl
6901 unmgdCallConv = pmCallConvCdecl;
6903 if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
6905 dwStubFlags |= NDIRECTSTUB_FL_TRIGGERCCTOR;
6910 CorNativeLinkFlags nlFlags;
6911 CorNativeLinkType nlType;
6915 PInvokeStaticSigInfo sigInfo(pMD);
6917 md = pMD->GetMemberDef();
6918 nlFlags = sigInfo.GetLinkFlags();
6919 nlType = sigInfo.GetCharSet();
6923 md = mdMethodDefNil;
6928 StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule);
6930 MethodDesc* pStubMD = NDirect::CreateCLRToNativeILStub(&sigDesc,
6936 pTempILStub = JitILStub(pStubMD);
6938 InterlockedCompareExchangeT<PCODE>(&pVASigCookie->pNDirectILStub,
6942 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
6943 UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
6945 RETURN pVASigCookie->pNDirectILStub;
6948 #endif // CROSSGEN_COMPILE
6950 #endif // #ifndef DACCESS_COMPILE
6953 // Truncates a SString by first converting it to unicode and truncate it
6954 // if it is larger than size. "..." will be appened if it is truncated.
6956 void TruncateUnicodeString(SString &string, COUNT_T bufSize)
6959 if ((string.GetCount() + 1) * sizeof(WCHAR) > bufSize)
6961 _ASSERTE(bufSize / sizeof(WCHAR) > 4);
6962 string.Truncate(string.Begin() + bufSize / sizeof(WCHAR) - 4);
6963 string.Append(W("..."));