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.
4//
5// File: DllImport.h
6//
7
8#ifndef __dllimport_h__
9#define __dllimport_h__
10
11#include "util.hpp"
12
13class ILStubHashBlob;
14class NDirectStubParameters;
15struct PInvokeStaticSigInfo;
16class LoadLibErrorTracker;
17
18// This structure groups together data that describe the signature for which a marshaling stub is being generated.
19struct StubSigDesc
20{
21public:
22 StubSigDesc(MethodDesc *pMD, PInvokeStaticSigInfo* pSigInfo = NULL);
23 StubSigDesc(MethodDesc *pMD, Signature sig, Module *m_pModule);
24
25 MethodDesc *m_pMD;
26 Signature m_sig;
27 Module *m_pModule;
28 Module *m_pLoaderModule;
29 mdMethodDef m_tkMethodDef;
30 SigTypeContext m_typeContext;
31
32#ifdef _DEBUG
33 LPCUTF8 m_pDebugName;
34 LPCUTF8 m_pDebugClassName;
35
36 void InitDebugNames()
37 {
38 LIMITED_METHOD_CONTRACT;
39
40 if (m_pMD != NULL)
41 {
42 m_pDebugName = m_pMD->m_pszDebugMethodName;
43 m_pDebugClassName = m_pMD->m_pszDebugClassName;
44 }
45 else
46 {
47 m_pDebugName = NULL;
48 m_pDebugClassName = NULL;
49 }
50 }
51#endif // _DEBUG
52};
53
54//=======================================================================
55// Collects code and data pertaining to the NDirect interface.
56//=======================================================================
57class NDirect
58{
59 friend class NDirectMethodDesc;
60
61public:
62 //---------------------------------------------------------
63 // One-time init
64 //---------------------------------------------------------
65 static void Init();
66
67 //---------------------------------------------------------
68 // Does a class or method have a NAT_L CustomAttribute?
69 //
70 // S_OK = yes
71 // S_FALSE = no
72 // FAILED = unknown because something failed.
73 //---------------------------------------------------------
74 static HRESULT HasNAT_LAttribute(IMDInternalImport *pInternalImport, mdToken token, DWORD dwMemberAttrs);
75
76 static LPVOID NDirectGetEntryPoint(NDirectMethodDesc *pMD, HINSTANCE hMod);
77 static NATIVE_LIBRARY_HANDLE LoadLibraryFromPath(LPCWSTR libraryPath, BOOL throwOnError);
78 static NATIVE_LIBRARY_HANDLE LoadLibraryByName(LPCWSTR name, Assembly *callingAssembly,
79 BOOL hasDllImportSearchPathFlag, DWORD dllImportSearchPathFlag,
80 BOOL throwOnError);
81 static HINSTANCE LoadLibraryModule(NDirectMethodDesc * pMD, LoadLibErrorTracker *pErrorTracker);
82 static void FreeNativeLibrary(NATIVE_LIBRARY_HANDLE handle);
83 static INT_PTR GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR symbolName, BOOL throwOnError);
84
85 static VOID NDirectLink(NDirectMethodDesc *pMD);
86
87 // Either MD or signature & module must be given.
88 static BOOL MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig = NULL, Module *pModule = NULL);
89 static void PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, BOOL throwOnError = TRUE);
90
91 static MethodDesc* CreateCLRToNativeILStub(
92 StubSigDesc* pSigDesc,
93 CorNativeLinkType nlType,
94 CorNativeLinkFlags nlFlags,
95 CorPinvokeMap unmgdCallConv,
96 DWORD dwStubFlags); // NDirectStubFlags
97
98#ifdef FEATURE_COMINTEROP
99 static MethodDesc* CreateFieldAccessILStub(
100 PCCOR_SIGNATURE szMetaSig,
101 DWORD cbMetaSigSize,
102 Module* pModule,
103 mdFieldDef fd,
104 DWORD dwStubFlags, // NDirectStubFlags
105 FieldDesc* pFD);
106#endif // FEATURE_COMINTEROP
107
108 static MethodDesc* CreateCLRToNativeILStub(PInvokeStaticSigInfo* pSigInfo,
109 DWORD dwStubFlags,
110 MethodDesc* pMD);
111
112 static MethodDesc* GetILStubMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwNGenStubFlags);
113 static MethodDesc* GetStubMethodDesc(MethodDesc *pTargetMD, NDirectStubParameters* pParams, ILStubHashBlob* pHashParams, AllocMemTracker* pamTracker, bool& bILStubCreator, MethodDesc* pLastMD);
114 static void AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, MethodDesc *pMD);
115 static void RemoveILStubCacheEntry(NDirectStubParameters* pParams, ILStubHashBlob* pHashParams);
116 static ILStubHashBlob* CreateHashBlob(NDirectStubParameters* pParams);
117 static PCODE GetStubForILStub(NDirectMethodDesc* pNMD, MethodDesc** ppStubMD, DWORD dwStubFlags);
118 static PCODE GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD, DWORD dwStubFlags);
119
120 inline static ILStubCache* GetILStubCache(NDirectStubParameters* pParams);
121
122private:
123 NDirect() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class
124
125 static NATIVE_LIBRARY_HANDLE LoadFromNativeDllSearchDirectories(AppDomain* pDomain, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
126 static NATIVE_LIBRARY_HANDLE LoadFromPInvokeAssemblyDirectory(Assembly *pAssembly, LPCWSTR libName, DWORD flags, LoadLibErrorTracker *pErrorTracker);
127 static NATIVE_LIBRARY_HANDLE LoadLibraryModuleViaHost(NDirectMethodDesc * pMD, AppDomain* pDomain, const wchar_t* wszLibName);
128 static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(NDirectMethodDesc * pMD, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
129 static NATIVE_LIBRARY_HANDLE LoadLibraryModuleBySearch(Assembly *callingAssembly, BOOL searchAssemblyDirectory, DWORD dllImportSearchPathFlag, LoadLibErrorTracker * pErrorTracker, const wchar_t* wszLibName);
130
131#if !defined(FEATURE_PAL)
132 // Indicates if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
133 static bool s_fSecureLoadLibrarySupported;
134
135public:
136 static bool SecureLoadLibrarySupported()
137 {
138 LIMITED_METHOD_CONTRACT;
139 return s_fSecureLoadLibrarySupported;
140 }
141#endif // !FEATURE_PAL
142};
143
144//----------------------------------------------------------------
145// Flags passed to CreateNDirectStub that control stub generation
146//----------------------------------------------------------------
147enum NDirectStubFlags
148{
149 NDIRECTSTUB_FL_CONVSIGASVARARG = 0x00000001,
150 NDIRECTSTUB_FL_BESTFIT = 0x00000002,
151 NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR = 0x00000004,
152 NDIRECTSTUB_FL_NGENEDSTUB = 0x00000008,
153 NDIRECTSTUB_FL_DELEGATE = 0x00000010,
154 NDIRECTSTUB_FL_DOHRESULTSWAPPING = 0x00000020,
155 NDIRECTSTUB_FL_REVERSE_INTEROP = 0x00000040,
156#ifdef FEATURE_COMINTEROP
157 NDIRECTSTUB_FL_COM = 0x00000080,
158#endif // FEATURE_COMINTEROP
159 NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING = 0x00000100,
160 NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL = 0x00000200,
161 // unused = 0x00000400,
162 NDIRECTSTUB_FL_UNMANAGED_CALLI = 0x00000800,
163 NDIRECTSTUB_FL_TRIGGERCCTOR = 0x00001000,
164#ifdef FEATURE_COMINTEROP
165 NDIRECTSTUB_FL_FIELDGETTER = 0x00002000, // COM->CLR field getter
166 NDIRECTSTUB_FL_FIELDSETTER = 0x00004000, // COM->CLR field setter
167 NDIRECTSTUB_FL_WINRT = 0x00008000,
168 NDIRECTSTUB_FL_WINRTDELEGATE = 0x00010000,
169 NDIRECTSTUB_FL_WINRTSHAREDGENERIC = 0x00020000, // stub for methods on shared generic interfaces (only used in the forward direction)
170 NDIRECTSTUB_FL_WINRTCTOR = 0x00080000,
171 NDIRECTSTUB_FL_WINRTCOMPOSITION = 0x00100000, // set along with WINRTCTOR
172 NDIRECTSTUB_FL_WINRTSTATIC = 0x00200000,
173
174 NDIRECTSTUB_FL_WINRTHASREDIRECTION = 0x00800000, // the stub may tail-call to a static stub in mscorlib, not shareable
175#endif // FEATURE_COMINTEROP
176
177 // internal flags -- these won't ever show up in an NDirectStubHashBlob
178 NDIRECTSTUB_FL_FOR_NUMPARAMBYTES = 0x10000000, // do just enough to return the right value from Marshal.NumParamBytes
179
180#ifdef FEATURE_COMINTEROP
181 NDIRECTSTUB_FL_COMLATEBOUND = 0x20000000, // we use a generic stub for late bound calls
182 NDIRECTSTUB_FL_COMEVENTCALL = 0x40000000, // we use a generic stub for event calls
183#endif // FEATURE_COMINTEROP
184
185 // Note: The upper half of the range is reserved for ILStubTypes enum
186 NDIRECTSTUB_FL_MASK = 0x7FFFFFFF,
187 NDIRECTSTUB_FL_INVALID = 0x80000000,
188};
189
190enum ILStubTypes
191{
192 ILSTUB_INVALID = 0x80000000,
193#ifdef FEATURE_ARRAYSTUB_AS_IL
194 ILSTUB_ARRAYOP_GET = 0x80000001,
195 ILSTUB_ARRAYOP_SET = 0x80000002,
196 ILSTUB_ARRAYOP_ADDRESS = 0x80000004,
197#endif
198#ifdef FEATURE_MULTICASTSTUB_AS_IL
199 ILSTUB_MULTICASTDELEGATE_INVOKE = 0x80000010,
200#endif
201#ifdef FEATURE_STUBS_AS_IL
202 ILSTUB_UNBOXINGILSTUB = 0x80000020,
203 ILSTUB_INSTANTIATINGSTUB = 0x80000040,
204 ILSTUB_SECUREDELEGATE_INVOKE = 0x80000080,
205#endif
206};
207
208#ifdef FEATURE_COMINTEROP
209#define COM_ONLY(x) (x)
210#else // FEATURE_COMINTEROP
211#define COM_ONLY(x) false
212#endif // FEATURE_COMINTEROP
213
214inline bool SF_IsVarArgStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)); }
215inline bool SF_IsBestFit (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_BESTFIT)); }
216inline bool SF_IsThrowOnUnmappableChar (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR)); }
217inline bool SF_IsNGENedStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)); }
218inline bool SF_IsDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DELEGATE)); }
219inline bool SF_IsHRESULTSwapping (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DOHRESULTSWAPPING)); }
220inline bool SF_IsReverseStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)); }
221inline bool SF_IsNGENedStubForProfiling(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING)); }
222inline bool SF_IsDebuggableStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL)); }
223inline bool SF_IsCALLIStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)); }
224inline bool SF_IsStubWithCctorTrigger (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_TRIGGERCCTOR)); }
225inline bool SF_IsForNumParamBytes (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FOR_NUMPARAMBYTES)); }
226
227#ifdef FEATURE_ARRAYSTUB_AS_IL
228inline bool SF_IsArrayOpStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return ((dwStubFlags == ILSTUB_ARRAYOP_GET) ||
229 (dwStubFlags == ILSTUB_ARRAYOP_SET) ||
230 (dwStubFlags == ILSTUB_ARRAYOP_ADDRESS)); }
231#endif
232
233#ifdef FEATURE_MULTICASTSTUB_AS_IL
234inline bool SF_IsMulticastDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_MULTICASTDELEGATE_INVOKE); }
235#endif
236
237#ifdef FEATURE_STUBS_AS_IL
238inline bool SF_IsSecureDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_SECUREDELEGATE_INVOKE); }
239inline bool SF_IsUnboxingILStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_UNBOXINGILSTUB); }
240inline bool SF_IsInstantiatingStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_INSTANTIATINGSTUB); }
241#endif
242
243inline bool SF_IsCOMStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COM)); }
244inline bool SF_IsWinRTStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRT)); }
245inline bool SF_IsCOMLateBoundStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMLATEBOUND)); }
246inline bool SF_IsCOMEventCallStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMEVENTCALL)); }
247inline bool SF_IsFieldGetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDGETTER)); }
248inline bool SF_IsFieldSetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDSETTER)); }
249inline bool SF_IsWinRTDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTDELEGATE)); }
250inline bool SF_IsWinRTCtorStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCTOR)); }
251inline bool SF_IsWinRTCompositionStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCOMPOSITION)); }
252inline bool SF_IsWinRTStaticStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSTATIC)); }
253inline bool SF_IsWinRTSharedGenericStub(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSHAREDGENERIC)); }
254inline bool SF_IsWinRTHasRedirection (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTHASREDIRECTION)); }
255
256inline bool SF_IsSharedStub(DWORD dwStubFlags)
257{
258 WRAPPER_NO_CONTRACT;
259
260 if (SF_IsWinRTHasRedirection(dwStubFlags))
261 {
262 // tail-call to a target-specific mscorlib routine is burned into the stub
263 return false;
264 }
265
266 return !SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags);
267}
268
269inline bool SF_IsForwardStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return !SF_IsReverseStub(dwStubFlags); }
270
271inline bool SF_IsForwardPInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
272inline bool SF_IsReversePInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }
273
274inline bool SF_IsForwardCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
275inline bool SF_IsReverseCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }
276
277inline bool SF_IsForwardDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); }
278inline bool SF_IsReverseDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); }
279
280#undef COM_ONLY
281
282inline void SF_ConsistencyCheck(DWORD dwStubFlags)
283{
284 LIMITED_METHOD_CONTRACT;
285
286 // Late bound and event calls imply COM
287 CONSISTENCY_CHECK(!(SF_IsCOMLateBoundStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags)));
288 CONSISTENCY_CHECK(!(SF_IsCOMEventCallStub(dwStubFlags) && !SF_IsCOMStub(dwStubFlags)));
289
290 // Field accessors imply reverse COM
291 CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags)));
292 CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsReverseCOMStub(dwStubFlags)));
293
294 // Field accessors are always HRESULT swapping
295 CONSISTENCY_CHECK(!(SF_IsFieldGetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags)));
296 CONSISTENCY_CHECK(!(SF_IsFieldSetterStub(dwStubFlags) && !SF_IsHRESULTSwapping(dwStubFlags)));
297
298 // Delegate stubs are not COM
299 CONSISTENCY_CHECK(!(SF_IsDelegateStub(dwStubFlags) && SF_IsCOMStub(dwStubFlags)));
300}
301
302enum ETW_IL_STUB_FLAGS
303{
304 ETW_IL_STUB_FLAGS_REVERSE_INTEROP = 0x00000001,
305 ETW_IL_STUB_FLAGS_COM_INTEROP = 0x00000002,
306 ETW_IL_STUB_FLAGS_NGENED_STUB = 0x00000004,
307 ETW_IL_STUB_FLAGS_DELEGATE = 0x00000008,
308 ETW_IL_STUB_FLAGS_VARARG = 0x00000010,
309 ETW_IL_STUB_FLAGS_UNMANAGED_CALLI = 0x00000020
310};
311
312//---------------------------------------------------------
313// PInvoke has three flavors: DllImport M->U, Delegate M->U and Delegate U->M
314// Each flavor uses rougly the same mechanism to marshal and place the call and so
315// each flavor supports roughly the same switches. Those switches which can be
316// statically determined via CAs (DllImport, UnmanagedFunctionPointer,
317// BestFitMappingAttribute, etc) or via MetaSig are parsed and unified by this
318// class. There are two flavors of constructor, one for NDirectMethodDescs and one
319// for Delegates.
320//---------------------------------------------------------
321struct PInvokeStaticSigInfo
322{
323public:
324 enum ThrowOnError { THROW_ON_ERROR = TRUE, NO_THROW_ON_ERROR = FALSE };
325
326public:
327 PInvokeStaticSigInfo() { LIMITED_METHOD_CONTRACT; }
328
329 PInvokeStaticSigInfo(Signature sig, Module* pModule, ThrowOnError throwOnError = THROW_ON_ERROR);
330
331 PInvokeStaticSigInfo(MethodDesc* pMdDelegate, ThrowOnError throwOnError = THROW_ON_ERROR);
332
333 PInvokeStaticSigInfo(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName, ThrowOnError throwOnError = THROW_ON_ERROR);
334
335public:
336 void ReportErrors();
337
338private:
339 void InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg);
340 void DllImportInit(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName);
341 void PreInit(Module* pModule, MethodTable *pClass);
342 void PreInit(MethodDesc* pMD);
343 void SetError(WORD error) { if (!m_error) m_error = error; }
344 void BestGuessNDirectDefaults(MethodDesc* pMD);
345
346public:
347 DWORD GetStubFlags()
348 {
349 WRAPPER_NO_CONTRACT;
350 return (GetThrowOnUnmappableChar() ? NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR : 0) |
351 (GetBestFitMapping() ? NDIRECTSTUB_FL_BESTFIT : 0) |
352 (IsDelegateInterop() ? NDIRECTSTUB_FL_DELEGATE : 0);
353 }
354 Module* GetModule() { LIMITED_METHOD_CONTRACT; return m_pModule; }
355 BOOL IsStatic() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_STATIC; }
356 void SetIsStatic (BOOL isStatic)
357 {
358 LIMITED_METHOD_CONTRACT;
359 if (isStatic)
360 m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_STATIC;
361 else
362 m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_STATIC;
363 }
364 BOOL GetThrowOnUnmappableChar() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR; }
365 void SetThrowOnUnmappableChar (BOOL throwOnUnmappableChar)
366 {
367 LIMITED_METHOD_CONTRACT;
368 if (throwOnUnmappableChar)
369 m_wFlags |= PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR;
370 else
371 m_wFlags &= ~PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR;
372 }
373 BOOL GetBestFitMapping() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_BEST_FIT; }
374 void SetBestFitMapping (BOOL bestFit)
375 {
376 LIMITED_METHOD_CONTRACT;
377 if (bestFit)
378 m_wFlags |= PINVOKE_STATIC_SIGINFO_BEST_FIT;
379 else
380 m_wFlags &= ~PINVOKE_STATIC_SIGINFO_BEST_FIT;
381 }
382 BOOL IsDelegateInterop() { LIMITED_METHOD_CONTRACT; return m_wFlags & PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP; }
383 void SetIsDelegateInterop (BOOL delegateInterop)
384 {
385 LIMITED_METHOD_CONTRACT;
386 if (delegateInterop)
387 m_wFlags |= PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP;
388 else
389 m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP;
390 }
391 CorPinvokeMap GetCallConv() { LIMITED_METHOD_CONTRACT; return m_callConv; }
392 Signature GetSignature() { LIMITED_METHOD_CONTRACT; return m_sig; }
393
394private:
395 Module* m_pModule;
396 Signature m_sig;
397 CorPinvokeMap m_callConv;
398 WORD m_error;
399
400 enum
401 {
402 PINVOKE_STATIC_SIGINFO_IS_STATIC = 0x0001,
403 PINVOKE_STATIC_SIGINFO_THROW_ON_UNMAPPABLE_CHAR = 0x0002,
404 PINVOKE_STATIC_SIGINFO_BEST_FIT = 0x0004,
405
406 COR_NATIVE_LINK_TYPE_MASK = 0x0038, // 0000 0000 0011 1000 <--- These 3 1's make the link type mask
407
408 COR_NATIVE_LINK_FLAGS_MASK = 0x00C0, //0000 0000 1100 0000 <---- These 2 bits make up the link flags
409
410 PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP = 0x0100,
411
412 };
413 #define COR_NATIVE_LINK_TYPE_SHIFT 3 // Keep in synch with above mask
414 #define COR_NATIVE_LINK_FLAGS_SHIFT 6 // Keep in synch with above mask
415 WORD m_wFlags;
416
417 public:
418 CorNativeLinkType GetCharSet() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkType)((m_wFlags & COR_NATIVE_LINK_TYPE_MASK) >> COR_NATIVE_LINK_TYPE_SHIFT); }
419 CorNativeLinkFlags GetLinkFlags() { LIMITED_METHOD_CONTRACT; return (CorNativeLinkFlags)((m_wFlags & COR_NATIVE_LINK_FLAGS_MASK) >> COR_NATIVE_LINK_FLAGS_SHIFT); }
420 void SetCharSet(CorNativeLinkType linktype)
421 {
422 LIMITED_METHOD_CONTRACT;
423 _ASSERTE( linktype == (linktype & (COR_NATIVE_LINK_TYPE_MASK >> COR_NATIVE_LINK_TYPE_SHIFT)));
424 // Clear out the old value first
425 m_wFlags &= (~COR_NATIVE_LINK_TYPE_MASK);
426 // Then set the given value
427 m_wFlags |= (linktype << COR_NATIVE_LINK_TYPE_SHIFT);
428 }
429 void SetLinkFlags(CorNativeLinkFlags linkflags)
430 {
431 LIMITED_METHOD_CONTRACT;
432 _ASSERTE( linkflags == (linkflags & (COR_NATIVE_LINK_FLAGS_MASK >> COR_NATIVE_LINK_FLAGS_SHIFT)));
433 // Clear out the old value first
434 m_wFlags &= (~COR_NATIVE_LINK_FLAGS_MASK);
435 // Then set the given value
436 m_wFlags |= (linkflags << COR_NATIVE_LINK_FLAGS_SHIFT);
437 }
438};
439
440
441#include "stubgen.h"
442
443class NDirectStubLinker : public ILStubLinker
444{
445public:
446 NDirectStubLinker(
447 DWORD dwStubFlags,
448 Module* pModule,
449 const Signature &signature,
450 SigTypeContext *pTypeContext,
451 MethodDesc* pTargetMD,
452 int iLCIDParamIdx,
453 BOOL fTargetHasThis,
454 BOOL fStubHasThis);
455
456 void SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg);
457
458 void Begin(DWORD dwStubFlags);
459 void End(DWORD dwStubFlags);
460 void DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD);
461 void EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal);
462 void LoadCleanupWorkList(ILCodeStream* pcsEmit);
463#ifdef PROFILING_SUPPORTED
464 DWORD EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags);
465 void EmitProfilerEndTransitionCallback(ILCodeStream* pcsEmit, DWORD dwStubFlags, DWORD dwMethodDescLocalNum);
466#endif
467#ifdef VERIFY_HEAP
468 void EmitValidateLocal(ILCodeStream* pcsEmit, DWORD dwLocalNum, bool fIsByref, DWORD dwStubFlags);
469 void EmitObjectValidation(ILCodeStream* pcsEmit, DWORD dwStubFlags);
470#endif // VERIFY_HEAP
471 void EmitLoadStubContext(ILCodeStream* pcsEmit, DWORD dwStubFlags);
472#ifdef MDA_SUPPORTED
473 void EmitCallGcCollectForMDA(ILCodeStream *pcsEmit, DWORD dwStubFlags);
474#endif // MDA_SUPPORTED
475 void GenerateInteropParamException(ILCodeStream* pcsEmit);
476 void NeedsCleanupList();
477
478#ifdef FEATURE_COMINTEROP
479 DWORD GetTargetInterfacePointerLocalNum();
480 DWORD GetTargetEntryPointLocalNum();
481 void EmitLoadRCWThis(ILCodeStream *pcsEmit, DWORD dwStubFlags);
482#endif // FEATURE_COMINTEROP
483 DWORD GetCleanupWorkListLocalNum();
484 DWORD GetThreadLocalNum();
485 DWORD GetReturnValueLocalNum();
486 void SetCleanupNeeded();
487 void SetExceptionCleanupNeeded();
488 BOOL IsCleanupWorkListSetup();
489 void GetCleanupFinallyOffsets(ILStubEHClause * pClause);
490 void AdjustTargetStackDeltaForReverseInteropHRESULTSwapping();
491 void AdjustTargetStackDeltaForExtraParam();
492
493 void SetInteropParamExceptionInfo(UINT resID, UINT paramIdx);
494 bool HasInteropParamExceptionInfo();
495
496 void ClearCode();
497
498 enum
499 {
500 CLEANUP_INDEX_ARG0_MARSHAL = 0x00000000, // cleanup index of the first argument (marshal and retval unmarshal stream)
501 CLEANUP_INDEX_RETVAL_UNMARSHAL = 0x3fffffff, // cleanup index of the return value (retval unmarshal stream)
502 CLEANUP_INDEX_ARG0_UNMARSHAL = 0x40000000, // cleanup index of the first argument (unmarshal stream)
503 CLEANUP_INDEX_ALL_DONE = 0x7ffffffe // everything was successfully marshaled and unmarshaled, no exception thrown
504 };
505
506 enum ArgCleanupBranchKind
507 {
508 BranchIfMarshaled,
509 BranchIfNotMarshaled
510 };
511
512 void EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx);
513 void EmitCheckForArgCleanup(ILCodeStream* pcsEmit, UINT uArgIdx, ArgCleanupBranchKind branchKind, ILCodeLabel* pSkipCleanupLabel);
514
515 int GetLCIDParamIdx();
516
517 ILCodeStream* GetSetupCodeStream();
518 ILCodeStream* GetMarshalCodeStream();
519 ILCodeStream* GetUnmarshalCodeStream();
520 ILCodeStream* GetReturnUnmarshalCodeStream();
521 ILCodeStream* GetDispatchCodeStream();
522 ILCodeStream* GetCleanupCodeStream();
523 ILCodeStream* GetExceptionCleanupCodeStream();
524
525protected:
526 BOOL IsCleanupNeeded();
527 BOOL IsExceptionCleanupNeeded();
528 void InitCleanupCode();
529 void InitExceptionCleanupCode();
530
531
532
533 ILCodeStream* m_pcsSetup;
534 ILCodeStream* m_pcsMarshal;
535 ILCodeStream* m_pcsDispatch;
536 ILCodeStream* m_pcsRetUnmarshal;
537 ILCodeStream* m_pcsUnmarshal;
538 ILCodeStream* m_pcsExceptionCleanup;
539 ILCodeStream* m_pcsCleanup;
540
541
542 ILCodeLabel* m_pCleanupTryBeginLabel;
543 ILCodeLabel* m_pCleanupTryEndLabel;
544 ILCodeLabel* m_pCleanupFinallyBeginLabel;
545 ILCodeLabel* m_pCleanupFinallyEndLabel;
546 ILCodeLabel* m_pSkipExceptionCleanupLabel;
547
548#ifdef FEATURE_COMINTEROP
549 DWORD m_dwTargetInterfacePointerLocalNum;
550 DWORD m_dwTargetEntryPointLocalNum;
551 DWORD m_dwWinRTFactoryObjectLocalNum;
552#endif // FEATURE_COMINTEROP
553
554 BOOL m_fHasCleanupCode;
555 BOOL m_fHasExceptionCleanupCode;
556 BOOL m_fCleanupWorkListIsSetup;
557 DWORD m_dwThreadLocalNum; // managed-to-native only
558 DWORD m_dwArgMarshalIndexLocalNum;
559 DWORD m_dwCleanupWorkListLocalNum;
560 DWORD m_dwRetValLocalNum;
561
562
563 UINT m_ErrorResID;
564 UINT m_ErrorParamIdx;
565 int m_iLCIDParamIdx;
566
567 DWORD m_dwStubFlags;
568};
569
570// This attempts to guess whether a target is an API call that uses SetLastError to communicate errors.
571BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget);
572BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget);
573DWORD STDMETHODCALLTYPE FalseGetLastError();
574
575class NDirectStubParameters
576{
577public:
578
579 NDirectStubParameters(Signature sig,
580 SigTypeContext* pTypeContext,
581 Module* pModule,
582 Module* pLoaderModule,
583 CorNativeLinkType nlType,
584 CorNativeLinkFlags nlFlags,
585 CorPinvokeMap unmgdCallConv,
586 DWORD dwStubFlags, // NDirectStubFlags
587 int nParamTokens,
588 mdParamDef* pParamTokenArray,
589 int iLCIDArg
590 ) :
591 m_sig(sig),
592 m_pTypeContext(pTypeContext),
593 m_pModule(pModule),
594 m_pLoaderModule(pLoaderModule),
595 m_pParamTokenArray(pParamTokenArray),
596 m_unmgdCallConv(unmgdCallConv),
597 m_nlType(nlType),
598 m_nlFlags(nlFlags),
599 m_dwStubFlags(dwStubFlags),
600 m_iLCIDArg(iLCIDArg),
601 m_nParamTokens(nParamTokens)
602 {
603 LIMITED_METHOD_CONTRACT;
604 }
605
606 Signature m_sig;
607 SigTypeContext* m_pTypeContext;
608 Module* m_pModule;
609 Module* m_pLoaderModule;
610 mdParamDef* m_pParamTokenArray;
611 CorPinvokeMap m_unmgdCallConv;
612 CorNativeLinkType m_nlType;
613 CorNativeLinkFlags m_nlFlags;
614 DWORD m_dwStubFlags;
615 int m_iLCIDArg;
616 int m_nParamTokens;
617};
618
619PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD);
620
621MethodDesc *GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags);
622PCODE JitILStub(MethodDesc* pStubMD);
623MethodDesc *RestoreNGENedStub(MethodDesc* pStubMD);
624PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags = 0, MethodDesc **ppStubMD = NULL);
625
626#ifdef FEATURE_COMINTEROP
627// Resolve and return the predefined IL stub method
628HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, MethodDesc **ppRetStubMD);
629#endif // FEATURE_COMINTEROP
630
631//
632// Limit length of string field in IL stub ETW events so that the whole
633// IL stub ETW events won't exceed 64KB
634//
635#define ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE (1024)
636#define ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE (1024*32)
637
638class SString;
639
640//
641// Truncates a SString by first converting it to unicode and truncate it
642// if it is larger than size. "..." will be appened if it is truncated.
643//
644void TruncateUnicodeString(SString &string, COUNT_T bufSize);
645
646//=======================================================================
647// ILStubCreatorHelper
648// The class is used as a helper class in CreateInteropILStub. It mainly
649// puts two methods NDirect::GetStubMethodDesc and NDirect::RemoveILStubCacheEntry
650// into a holder. See CreateInteropILStub for more information
651//=======================================================================
652class ILStubCreatorHelper
653{
654public:
655 ILStubCreatorHelper(MethodDesc *pTargetMD,
656 NDirectStubParameters* pParams
657 ) :
658 m_pTargetMD(pTargetMD),
659 m_pParams(pParams),
660 m_pStubMD(NULL),
661 m_bILStubCreator(false)
662 {
663 STANDARD_VM_CONTRACT;
664 m_pHashParams = NDirect::CreateHashBlob(m_pParams);
665 }
666
667 ~ILStubCreatorHelper()
668 {
669 CONTRACTL
670 {
671 THROWS;
672 GC_TRIGGERS;
673 MODE_ANY;
674 }
675 CONTRACTL_END;
676
677 RemoveILStubCacheEntry();
678 }
679
680 inline void GetStubMethodDesc()
681 {
682 WRAPPER_NO_CONTRACT;
683
684 m_pStubMD = NDirect::GetStubMethodDesc(m_pTargetMD, m_pParams, m_pHashParams, &m_amTracker, m_bILStubCreator, m_pStubMD);
685 }
686
687 inline void RemoveILStubCacheEntry()
688 {
689 WRAPPER_NO_CONTRACT;
690
691 if (m_bILStubCreator)
692 {
693 NDirect::RemoveILStubCacheEntry(m_pParams, m_pHashParams);
694 m_bILStubCreator = false;
695 }
696 }
697
698 inline MethodDesc* GetStubMD()
699 {
700 LIMITED_METHOD_CONTRACT;
701 return m_pStubMD;
702 }
703
704 inline void SuppressRelease()
705 {
706 WRAPPER_NO_CONTRACT;
707 m_bILStubCreator = false;
708 m_amTracker.SuppressRelease();
709 }
710
711 DEBUG_NOINLINE static void HolderEnter(ILStubCreatorHelper *pThis)
712 {
713 WRAPPER_NO_CONTRACT;
714 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
715 pThis->GetStubMethodDesc();
716 }
717
718 DEBUG_NOINLINE static void HolderLeave(ILStubCreatorHelper *pThis)
719 {
720 WRAPPER_NO_CONTRACT;
721 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
722 pThis->RemoveILStubCacheEntry();
723 }
724
725private:
726 MethodDesc* m_pTargetMD;
727 NDirectStubParameters* m_pParams;
728 NewArrayHolder<ILStubHashBlob> m_pHashParams;
729 AllocMemTracker* m_pAmTracker;
730 MethodDesc* m_pStubMD;
731 AllocMemTracker m_amTracker;
732 bool m_bILStubCreator; // Only the creator can remove the ILStub from the Cache
733}; //ILStubCreatorHelper
734
735typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder;
736
737#endif // __dllimport_h__
738