diff options
Diffstat (limited to 'src/vm/dllimport.h')
-rw-r--r-- | src/vm/dllimport.h | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/src/vm/dllimport.h b/src/vm/dllimport.h new file mode 100644 index 0000000000..b393bf6cdd --- /dev/null +++ b/src/vm/dllimport.h @@ -0,0 +1,791 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: DllImport.h +// + +// + + +#ifndef __dllimport_h__ +#define __dllimport_h__ + +#include "util.hpp" + +class ILStubHashBlob; +class NDirectStubParameters; +struct PInvokeStaticSigInfo; +class LoadLibErrorTracker; + +// This structure groups together data that describe the signature for which a marshaling stub is being generated. +struct StubSigDesc +{ +public: + StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo = NULL); + StubSigDesc(MethodDesc *pMD, Signature sig, Module *m_pModule); + + MethodDesc *m_pMD; + Signature m_sig; + Module *m_pModule; + Module *m_pLoaderModule; + mdMethodDef m_tkMethodDef; + SigTypeContext m_typeContext; + +#ifdef _DEBUG + LPCUTF8 m_pDebugName; + LPCUTF8 m_pDebugClassName; + + void InitDebugNames() + { + LIMITED_METHOD_CONTRACT; + + if (m_pMD != NULL) + { + m_pDebugName = m_pMD->m_pszDebugMethodName; + m_pDebugClassName = m_pMD->m_pszDebugClassName; + } + else + { + m_pDebugName = NULL; + m_pDebugClassName = NULL; + } + } +#endif // _DEBUG +}; + +//======================================================================= +// Collects code and data pertaining to the NDirect interface. +//======================================================================= +class NDirect +{ + friend class NDirectMethodDesc; + +public: + //--------------------------------------------------------- + // One-time init + //--------------------------------------------------------- + static void Init(); + + //--------------------------------------------------------- + // Does a class or method have a NAT_L CustomAttribute? + // + // S_OK = yes + // S_FALSE = no + // FAILED = unknown because something failed. + //--------------------------------------------------------- + static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs); + + static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod); + static HMODULE LoadLibraryFromPath(LPCWSTR libraryPath); + static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker); + +#ifndef FEATURE_CORECLR + static VOID CheckUnificationList(NDirectMethodDesc * pMD, DWORD * pDllImportSearchPathFlag, BOOL * pSearchAssemblyDirectory); +#endif // !FEATURE_CORECLR + + static VOID NDirectLink(NDirectMethodDesc *pMD); + + // Either MD or signature & module must be given. + static BOOL MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig = NULL, Module *pModule = NULL); + static void PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError = TRUE); + + static MethodDesc* CreateCLRToNativeILStub( + StubSigDesc* pSigDesc, + CorNativeLinkType nlType, + CorNativeLinkFlags nlFlags, + CorPinvokeMap unmgdCallConv, + DWORD dwStubFlags); // NDirectStubFlags + +#ifdef FEATURE_COMINTEROP + static MethodDesc* CreateFieldAccessILStub( + PCCOR_SIGNATURE szMetaSig, + DWORD cbMetaSigSize, + Module* pModule, + mdFieldDef fd, + DWORD dwStubFlags, // NDirectStubFlags + FieldDesc* pFD); +#endif // FEATURE_COMINTEROP + + static MethodDesc* CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo, + DWORD dwStubFlags, + MethodDesc* pMD); + + static MethodDesc* GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwNGenStubFlags); + static MethodDesc* GetStubMethodDesc(MethodDesc *pTargetMD, NDirectStubParameters* pParams, ILStubHashBlob* pHashParams, AllocMemTracker* pamTracker, bool& bILStubCreator, MethodDesc* pLastMD); + static void AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD); + static void RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams); + static ILStubHashBlob* CreateHashBlob(NDirectStubParameters* pParams); + static PCODE GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags); + static PCODE GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD, DWORD dwStubFlags); + + inline static ILStubCache* GetILStubCache(NDirectStubParameters* pParams); + +#if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR) + static Stub* GetStubForCopyCtor(); +#endif // _TARGET_X86_ && !FEATURE_CORECLR + + static BOOL IsHostHookEnabled(); + + static Stub *GenerateStubForHost(Module *pModule, CorUnmanagedCallingConvention callConv, WORD wArgSize); + +private: + NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class + +#ifdef FEATURE_CORECLR + static HMODULE LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); +#endif + static HMODULE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker); + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + static HMODULE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName); +#endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + +#if !defined(FEATURE_CORESYSTEM) + static HINSTANCE CheckForWellKnownModules(LPCWSTR wszLibName, LoadLibErrorTracker *pErrorTracker); + static PtrHashMap *s_pWellKnownNativeModules; + + // Indicates if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623 + static bool s_fSecureLoadLibrarySupported; + +public: + static bool SecureLoadLibrarySupported() + { + LIMITED_METHOD_CONTRACT; + return s_fSecureLoadLibrarySupported; + } +#endif // !FEATURE_CORESYSTEM +}; + +//---------------------------------------------------------------- +// Flags passed to CreateNDirectStub that control stub generation +//---------------------------------------------------------------- +enum NDirectStubFlags +{ + NDIRECTSTUB_FL_CONVSIGASVARARG = 0x00000001, + NDIRECTSTUB_FL_BESTFIT = 0x00000002, + NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR = 0x00000004, + NDIRECTSTUB_FL_NGENEDSTUB = 0x00000008, + NDIRECTSTUB_FL_DELEGATE = 0x00000010, + NDIRECTSTUB_FL_DOHRESULTSWAPPING = 0x00000020, + NDIRECTSTUB_FL_REVERSE_INTEROP = 0x00000040, +#ifdef FEATURE_COMINTEROP + NDIRECTSTUB_FL_COM = 0x00000080, +#endif // FEATURE_COMINTEROP + NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING = 0x00000100, + NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL = 0x00000200, + NDIRECTSTUB_FL_HASDECLARATIVESECURITY = 0x00000400, + NDIRECTSTUB_FL_UNMANAGED_CALLI = 0x00000800, + NDIRECTSTUB_FL_TRIGGERCCTOR = 0x00001000, +#ifdef FEATURE_COMINTEROP + NDIRECTSTUB_FL_FIELDGETTER = 0x00002000, // COM->CLR field getter + NDIRECTSTUB_FL_FIELDSETTER = 0x00004000, // COM->CLR field setter + NDIRECTSTUB_FL_WINRT = 0x00008000, + NDIRECTSTUB_FL_WINRTDELEGATE = 0x00010000, + NDIRECTSTUB_FL_WINRTSHAREDGENERIC = 0x00020000, // stub for methods on shared generic interfaces (only used in the forward direction) + NDIRECTSTUB_FL_WINRTCTOR = 0x00080000, + NDIRECTSTUB_FL_WINRTCOMPOSITION = 0x00100000, // set along with WINRTCTOR + NDIRECTSTUB_FL_WINRTSTATIC = 0x00200000, + + NDIRECTSTUB_FL_WINRTHASREDIRECTION = 0x00800000, // the stub may tail-call to a static stub in mscorlib, not shareable +#endif // FEATURE_COMINTEROP + + // internal flags -- these won't ever show up in an NDirectStubHashBlob + NDIRECTSTUB_FL_FOR_NUMPARAMBYTES = 0x10000000, // do just enough to return the right value from Marshal.NumParamBytes + +#ifdef FEATURE_COMINTEROP + NDIRECTSTUB_FL_COMLATEBOUND = 0x20000000, // we use a generic stub for late bound calls + NDIRECTSTUB_FL_COMEVENTCALL = 0x40000000, // we use a generic stub for event calls +#endif // FEATURE_COMINTEROP + + // Note: The upper half of the range is reserved for ILStubTypes enum + NDIRECTSTUB_FL_MASK = 0x7FFFFFFF, + NDIRECTSTUB_FL_INVALID = 0x80000000, +}; + +enum ILStubTypes +{ + ILSTUB_INVALID = 0x80000000, +#ifdef FEATURE_ARRAYSTUB_AS_IL + ILSTUB_ARRAYOP_GET = 0x80000001, + ILSTUB_ARRAYOP_SET = 0x80000002, + ILSTUB_ARRAYOP_ADDRESS = 0x80000004, +#endif +#ifdef FEATURE_STUBS_AS_IL + ILSTUB_MULTICASTDELEGATE_INVOKE = 0x80000010, + ILSTUB_UNBOXINGILSTUB = 0x80000020, + ILSTUB_INSTANTIATINGSTUB = 0x80000040, + ILSTUB_SECUREDELEGATE_INVOKE = 0x80000080, +#endif +}; + +#ifdef FEATURE_COMINTEROP +#define COM_ONLY(x) (x) +#else // FEATURE_COMINTEROP +#define COM_ONLY(x) false +#endif // FEATURE_COMINTEROP + +inline bool SF_IsVarArgStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)); } +inline bool SF_IsBestFit (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_BESTFIT)); } +inline bool SF_IsThrowOnUnmappableChar (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR)); } +inline bool SF_IsNGENedStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)); } +inline bool SF_IsDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DELEGATE)); } +inline bool SF_IsHRESULTSwapping (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DOHRESULTSWAPPING)); } +inline bool SF_IsReverseStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)); } +inline bool SF_IsNGENedStubForProfiling(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING)); } +inline bool SF_IsDebuggableStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL)); } +inline bool SF_IsStubWithDemand (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_HASDECLARATIVESECURITY)); } +inline bool SF_IsCALLIStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)); } +inline bool SF_IsStubWithCctorTrigger (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_TRIGGERCCTOR)); } +inline bool SF_IsForNumParamBytes (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FOR_NUMPARAMBYTES)); } + +#ifdef FEATURE_ARRAYSTUB_AS_IL +inline bool SF_IsArrayOpStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return ((dwStubFlags == ILSTUB_ARRAYOP_GET) || + (dwStubFlags == ILSTUB_ARRAYOP_SET) || + (dwStubFlags == ILSTUB_ARRAYOP_ADDRESS)); } +#endif + +#ifdef FEATURE_STUBS_AS_IL +inline bool SF_IsSecureDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_SECUREDELEGATE_INVOKE); } +inline bool SF_IsMulticastDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_MULTICASTDELEGATE_INVOKE); } +inline bool SF_IsUnboxingILStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_UNBOXINGILSTUB); } +inline bool SF_IsInstantiatingStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_INSTANTIATINGSTUB); } +#endif + +inline bool SF_IsCOMStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COM)); } +inline bool SF_IsWinRTStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRT)); } +inline bool SF_IsCOMLateBoundStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMLATEBOUND)); } +inline bool SF_IsCOMEventCallStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMEVENTCALL)); } +inline bool SF_IsFieldGetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDGETTER)); } +inline bool SF_IsFieldSetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDSETTER)); } +inline bool SF_IsWinRTDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTDELEGATE)); } +inline bool SF_IsWinRTCtorStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCTOR)); } +inline bool SF_IsWinRTCompositionStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCOMPOSITION)); } +inline bool SF_IsWinRTStaticStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSTATIC)); } +inline bool SF_IsWinRTSharedGenericStub(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSHAREDGENERIC)); } +inline bool SF_IsWinRTHasRedirection (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTHASREDIRECTION)); } + +inline bool SF_IsSharedStub(DWORD dwStubFlags) +{ + WRAPPER_NO_CONTRACT; + + if (SF_IsWinRTHasRedirection(dwStubFlags)) + { + // tail-call to a target-specific mscorlib routine is burned into the stub + return false; + } + + return !SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags); +} + +inline bool SF_IsForwardStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return !SF_IsReverseStub(dwStubFlags); } + +inline bool SF_IsForwardPInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } +inline bool SF_IsReversePInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } + +inline bool SF_IsForwardCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } +inline bool SF_IsReverseCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } + +inline bool SF_IsForwardDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } +inline bool SF_IsReverseDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } + +#undef COM_ONLY + +inline void SF_ConsistencyCheck(DWORD dwStubFlags) +{ + LIMITED_METHOD_CONTRACT; + + // Late bound and event calls imply COM + CONSISTENCY_CHECK(!(SF_IsCOMLateBoundStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags))); + CONSISTENCY_CHECK(!(SF_IsCOMEventCallStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags))); + + // Field accessors imply reverse COM + CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags))); + CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags))); + + // Field accessors are always HRESULT swapping + CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags))); + CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags))); + + // Reverse and CALLI stubs don't have demands + CONSISTENCY_CHECK(!(SF_IsReverseStub(dwStubFlags) && SF_IsStubWithDemand(dwStubFlags))); + CONSISTENCY_CHECK(!(SF_IsCALLIStub(dwStubFlags) && SF_IsStubWithDemand(dwStubFlags))); + + // Delegate stubs are not COM + CONSISTENCY_CHECK(!(SF_IsDelegateStub(dwStubFlags) && SF_IsCOMStub(dwStubFlags))); +} + +enum ETW_IL_STUB_FLAGS +{ + ETW_IL_STUB_FLAGS_REVERSE_INTEROP = 0x00000001, + ETW_IL_STUB_FLAGS_COM_INTEROP = 0x00000002, + ETW_IL_STUB_FLAGS_NGENED_STUB = 0x00000004, + ETW_IL_STUB_FLAGS_DELEGATE = 0x00000008, + ETW_IL_STUB_FLAGS_VARARG = 0x00000010, + ETW_IL_STUB_FLAGS_UNMANAGED_CALLI = 0x00000020 +}; + +//--------------------------------------------------------- +// PInvoke has three flavors: DllImport M->U, Delegate M->U and Delegate U->M +// Each flavor uses rougly the same mechanism to marshal and place the call and so +// each flavor supports roughly the same switches. Those switches which can be +// statically determined via CAs (DllImport, UnmanagedFunctionPointer, +// BestFitMappingAttribute, etc) or via MetaSig are parsed and unified by this +// class. There are two flavors of constructor, one for NDirectMethodDescs and one +// for Delegates. +//--------------------------------------------------------- +struct PInvokeStaticSigInfo +{ +public: + enum ThrowOnError { THROW_ON_ERROR = TRUE, NO_THROW_ON_ERROR = FALSE }; + +public: + PInvokeStaticSigInfo() { LIMITED_METHOD_CONTRACT; } + + PInvokeStaticSigInfo(Signature sig, Module* pModule, ThrowOnError throwOnError = THROW_ON_ERROR); + + PInvokeStaticSigInfo(MethodDesc* pMdDelegate, ThrowOnError throwOnError = THROW_ON_ERROR); + + PInvokeStaticSigInfo(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError = THROW_ON_ERROR); + +public: + void ReportErrors(); + +private: + void InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg); + void DllImportInit(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName); + void PreInit(Module* pModule, MethodTable *pClass); + void PreInit(MethodDesc* pMD); + void SetError(WORD error) { if (!m_error) m_error = error; } +#ifdef FEATURE_MIXEDMODE + void BestGuessNDirectDefaults(MethodDesc* pMD); +#endif + +public: + DWORD GetStubFlags() + { + WRAPPER_NO_CONTRACT; + return (GetThrowOnUnmappableChar() ? NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR : 0) | + (GetBestFitMapping() ? NDIRECTSTUB_FL_BESTFIT : 0) | + (IsDelegateInterop() ? NDIRECTSTUB_FL_DELEGATE : 0); + } + Module* GetModule() { LIMITED_METHOD_CONTRACT; return m_pModule; } + BOOL IsStatic() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_STATIC; } + void SetIsStatic (BOOL isStatic) + { + LIMITED_METHOD_CONTRACT; + if (isStatic) + m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_STATIC; + else + m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_STATIC; + } + BOOL GetThrowOnUnmappableChar() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; } + void SetThrowOnUnmappableChar (BOOL throwOnUnmappableChar) + { + LIMITED_METHOD_CONTRACT; + if (throwOnUnmappableChar) + m_wFlags |= PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; + else + m_wFlags &= ~PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; + } + BOOL GetBestFitMapping() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_BEST_FIT; } + void SetBestFitMapping (BOOL bestFit) + { + LIMITED_METHOD_CONTRACT; + if (bestFit) + m_wFlags |= PINVOKE_STATIC_SIGINFO_BEST_FIT; + else + m_wFlags &= ~PINVOKE_STATIC_SIGINFO_BEST_FIT; + } + BOOL IsDelegateInterop() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; } + void SetIsDelegateInterop (BOOL delegateInterop) + { + LIMITED_METHOD_CONTRACT; + if (delegateInterop) + m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; + else + m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; + } + CorPinvokeMap GetCallConv() { LIMITED_METHOD_CONTRACT; return m_callConv; } + Signature GetSignature() { LIMITED_METHOD_CONTRACT; return m_sig; } + +private: + Module* m_pModule; + Signature m_sig; + CorPinvokeMap m_callConv; + WORD m_error; + + enum + { + PINVOKE_STATIC_SIGINFO_IS_STATIC = 0x0001, + PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR = 0x0002, + PINVOKE_STATIC_SIGINFO_BEST_FIT = 0x0004, + + COR_NATIVE_LINK_TYPE_MASK = 0x0038, // 0000 0000 0011 1000 <--- These 3 1's make the link type mask + + COR_NATIVE_LINK_FLAGS_MASK = 0x00C0, //0000 0000 1100 0000 <---- These 2 bits make up the link flags + + PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP = 0x0100, + + }; + #define COR_NATIVE_LINK_TYPE_SHIFT 3 // Keep in synch with above mask + #define COR_NATIVE_LINK_FLAGS_SHIFT 6 // Keep in synch with above mask + WORD m_wFlags; + + public: + CorNativeLinkType GetCharSet() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkType)((m_wFlags & COR_NATIVE_LINK_TYPE_MASK) >> COR_NATIVE_LINK_TYPE_SHIFT); } + CorNativeLinkFlags GetLinkFlags() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkFlags)((m_wFlags & COR_NATIVE_LINK_FLAGS_MASK) >> COR_NATIVE_LINK_FLAGS_SHIFT); } + void SetCharSet(CorNativeLinkType linktype) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE( linktype == (linktype & (COR_NATIVE_LINK_TYPE_MASK >> COR_NATIVE_LINK_TYPE_SHIFT))); + // Clear out the old value first + m_wFlags &= (~COR_NATIVE_LINK_TYPE_MASK); + // Then set the given value + m_wFlags |= (linktype << COR_NATIVE_LINK_TYPE_SHIFT); + } + void SetLinkFlags(CorNativeLinkFlags linkflags) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE( linkflags == (linkflags & (COR_NATIVE_LINK_FLAGS_MASK >> COR_NATIVE_LINK_FLAGS_SHIFT))); + // Clear out the old value first + m_wFlags &= (~COR_NATIVE_LINK_FLAGS_MASK); + // Then set the given value + m_wFlags |= (linkflags << COR_NATIVE_LINK_FLAGS_SHIFT); + } +}; + + +#include "stubgen.h" + +class NDirectStubLinker : public ILStubLinker +{ +public: + NDirectStubLinker( + DWORD dwStubFlags, + Module* pModule, + const Signature &signature, + SigTypeContext *pTypeContext, + MethodDesc* pTargetMD, + int iLCIDParamIdx, + BOOL fTargetHasThis, + BOOL fStubHasThis); + + void SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg); + + void Begin(DWORD dwStubFlags); + void End(DWORD dwStubFlags); + void DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD); + void EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal); + void LoadCleanupWorkList(ILCodeStream* pcsEmit); +#ifdef PROFILING_SUPPORTED + DWORD EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags); + void EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum); +#endif +#ifdef VERIFY_HEAP + void EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags); + void EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags); +#endif // VERIFY_HEAP + void EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags); +#ifdef MDA_SUPPORTED + void EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags); +#endif // MDA_SUPPORTED + void GenerateInteropParamException(ILCodeStream* pcsEmit); + void NeedsCleanupList(); + +#ifdef FEATURE_COMINTEROP + DWORD GetTargetInterfacePointerLocalNum(); + DWORD GetTargetEntryPointLocalNum(); + void EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags); +#endif // FEATURE_COMINTEROP + DWORD GetCleanupWorkListLocalNum(); + DWORD GetThreadLocalNum(); + DWORD GetReturnValueLocalNum(); + void SetCleanupNeeded(); + void SetExceptionCleanupNeeded(); + BOOL IsCleanupWorkListSetup(); + void GetCleanupFinallyOffsets(ILStubEHClause * pClause); + void AdjustTargetStackDeltaForReverseInteropHRESULTSwapping(); + void AdjustTargetStackDeltaForExtraParam(); +#if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR) + DWORD CreateCopyCtorCookie(ILCodeStream* pcsEmit); +#endif // _TARGET_X86_ && !FEATURE_CORECLR + + void SetInteropParamExceptionInfo(UINT resID, UINT paramIdx); + bool HasInteropParamExceptionInfo(); + + void ClearCode(); + + enum + { + CLEANUP_INDEX_ARG0_MARSHAL = 0x00000000, // cleanup index of the first argument (marshal and retval unmarshal stream) + CLEANUP_INDEX_RETVAL_UNMARSHAL = 0x3fffffff, // cleanup index of the return value (retval unmarshal stream) + CLEANUP_INDEX_ARG0_UNMARSHAL = 0x40000000, // cleanup index of the first argument (unmarshal stream) + CLEANUP_INDEX_ALL_DONE = 0x7ffffffe // everything was successfully marshaled and unmarshaled, no exception thrown + }; + + enum ArgCleanupBranchKind + { + BranchIfMarshaled, + BranchIfNotMarshaled + }; + + void EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx); + void EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel); + + int GetLCIDParamIdx(); + + ILCodeStream* GetSetupCodeStream(); + ILCodeStream* GetMarshalCodeStream(); + ILCodeStream* GetUnmarshalCodeStream(); + ILCodeStream* GetReturnUnmarshalCodeStream(); + ILCodeStream* GetDispatchCodeStream(); + ILCodeStream* GetCleanupCodeStream(); + ILCodeStream* GetExceptionCleanupCodeStream(); + +protected: + BOOL IsCleanupNeeded(); + BOOL IsExceptionCleanupNeeded(); + void InitCleanupCode(); + void InitExceptionCleanupCode(); + +#if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR) + BOOL IsCopyCtorStubNeeded(); +#endif // _TARGET_X86_ && !FEATURE_CORECLR + + + ILCodeStream* m_pcsSetup; + ILCodeStream* m_pcsMarshal; + ILCodeStream* m_pcsDispatch; + ILCodeStream* m_pcsRetUnmarshal; + ILCodeStream* m_pcsUnmarshal; + ILCodeStream* m_pcsExceptionCleanup; + ILCodeStream* m_pcsCleanup; + + + ILCodeLabel* m_pCleanupTryBeginLabel; + ILCodeLabel* m_pCleanupTryEndLabel; + ILCodeLabel* m_pCleanupFinallyBeginLabel; + ILCodeLabel* m_pCleanupFinallyEndLabel; + ILCodeLabel* m_pSkipExceptionCleanupLabel; + +#ifdef FEATURE_COMINTEROP + DWORD m_dwTargetInterfacePointerLocalNum; + DWORD m_dwTargetEntryPointLocalNum; + DWORD m_dwWinRTFactoryObjectLocalNum; +#endif // FEATURE_COMINTEROP + + BOOL m_fHasCleanupCode; + BOOL m_fHasExceptionCleanupCode; + BOOL m_fCleanupWorkListIsSetup; + DWORD m_dwThreadLocalNum; // managed-to-native only + DWORD m_dwArgMarshalIndexLocalNum; + DWORD m_dwCleanupWorkListLocalNum; + DWORD m_dwRetValLocalNum; + +#if defined(_TARGET_X86_) && !defined(FEATURE_CORECLR) + DWORD m_dwFirstCopyCtorCookieLocalNum; // list head passed to SetCopyCtorCookieChain + DWORD m_dwLastCopyCtorCookieLocalNum; // used for chaining the cookies into a linked list +#endif // _TARGET_X86_ && !FEATURE_CORECLR + + UINT m_ErrorResID; + UINT m_ErrorParamIdx; + int m_iLCIDParamIdx; + + DWORD m_dwStubFlags; +}; + +#ifndef _TARGET_X86_ +// The one static host for stub used on !_TARGET_X86_ +EXTERN_C void PInvokeStubForHost(void); +#endif + +#ifdef FEATURE_MIXEDMODE // IJW +// This attempts to guess whether a target is an API call that uses SetLastError to communicate errors. +BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget); +BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget); +DWORD __stdcall FalseGetLastError(); +#endif // FEATURE_MIXEDMODE + +class NDirectStubParameters +{ +public: + + NDirectStubParameters(Signature sig, + SigTypeContext* pTypeContext, + Module* pModule, + Module* pLoaderModule, + CorNativeLinkType nlType, + CorNativeLinkFlags nlFlags, + CorPinvokeMap unmgdCallConv, + DWORD dwStubFlags, // NDirectStubFlags + int nParamTokens, + mdParamDef* pParamTokenArray, + int iLCIDArg + ) : + m_sig(sig), + m_pTypeContext(pTypeContext), + m_pModule(pModule), + m_pLoaderModule(pLoaderModule), + m_pParamTokenArray(pParamTokenArray), + m_unmgdCallConv(unmgdCallConv), + m_nlType(nlType), + m_nlFlags(nlFlags), + m_dwStubFlags(dwStubFlags), + m_iLCIDArg(iLCIDArg), + m_nParamTokens(nParamTokens) + { + LIMITED_METHOD_CONTRACT; + } + + Signature m_sig; + SigTypeContext* m_pTypeContext; + Module* m_pModule; + Module* m_pLoaderModule; + mdParamDef* m_pParamTokenArray; + CorPinvokeMap m_unmgdCallConv; + CorNativeLinkType m_nlType; + CorNativeLinkFlags m_nlFlags; + DWORD m_dwStubFlags; + int m_iLCIDArg; + int m_nParamTokens; +}; + +PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD); + +MethodDesc *GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags); +PCODE JitILStub(MethodDesc* pStubMD); +MethodDesc *RestoreNGENedStub(MethodDesc* pStubMD); +PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags = 0, MethodDesc **ppStubMD = NULL); + +#ifdef FEATURE_COMINTEROP +// Resolve and return the predefined IL stub method +HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD); +#endif // FEATURE_COMINTEROP + +EXTERN_C BOOL CallNeedsHostHook(size_t target); + +#ifndef FEATURE_INCLUDE_ALL_INTERFACES +// +// Inlinable implementation allows compiler to strip all code related to host hook +// +inline BOOL NDirect::IsHostHookEnabled() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CallNeedsHostHook(size_t target) +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} +#endif + +// +// Limit length of string field in IL stub ETW events so that the whole +// IL stub ETW events won't exceed 64KB +// +#define ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE (1024) +#define ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE (1024*32) + +class SString; + +// +// Truncates a SString by first converting it to unicode and truncate it +// if it is larger than size. "..." will be appened if it is truncated. +// +void TruncateUnicodeString(SString &string, COUNT_T bufSize); + +//======================================================================= +// ILStubCreatorHelper +// The class is used as a helper class in CreateInteropILStub. It mainly +// puts two methods NDirect::GetStubMethodDesc and NDirect::RemoveILStubCacheEntry +// into a holder. See CreateInteropILStub for more information +//======================================================================= +class ILStubCreatorHelper +{ +public: + ILStubCreatorHelper(MethodDesc *pTargetMD, + NDirectStubParameters* pParams + ) : + m_pTargetMD(pTargetMD), + m_pParams(pParams), + m_pStubMD(NULL), + m_bILStubCreator(false) + { + STANDARD_VM_CONTRACT; + m_pHashParams = NDirect::CreateHashBlob(m_pParams); + } + + ~ILStubCreatorHelper() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + RemoveILStubCacheEntry(); + } + + inline void GetStubMethodDesc() + { + WRAPPER_NO_CONTRACT; + + m_pStubMD = NDirect::GetStubMethodDesc(m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD); + } + + inline void RemoveILStubCacheEntry() + { + WRAPPER_NO_CONTRACT; + + if (m_bILStubCreator) + { + NDirect::RemoveILStubCacheEntry(m_pParams, m_pHashParams); + m_bILStubCreator = false; + } + } + + inline MethodDesc* GetStubMD() + { + LIMITED_METHOD_CONTRACT; + return m_pStubMD; + } + + inline void SuppressRelease() + { + WRAPPER_NO_CONTRACT; + m_bILStubCreator = false; + m_amTracker.SuppressRelease(); + } + + DEBUG_NOINLINE static void HolderEnter(ILStubCreatorHelper *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->GetStubMethodDesc(); + } + + DEBUG_NOINLINE static void HolderLeave(ILStubCreatorHelper *pThis) + { + WRAPPER_NO_CONTRACT; + ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT; + pThis->RemoveILStubCacheEntry(); + } + +private: + MethodDesc* m_pTargetMD; + NDirectStubParameters* m_pParams; + NewArrayHolder<ILStubHashBlob> m_pHashParams; + AllocMemTracker* m_pAmTracker; + MethodDesc* m_pStubMD; + AllocMemTracker m_amTracker; + bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache +}; //ILStubCreatorHelper + +typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder; + +#endif // __dllimport_h__ |