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 | |
13 | class ILStubHashBlob; |
14 | class NDirectStubParameters; |
15 | struct PInvokeStaticSigInfo; |
16 | class LoadLibErrorTracker; |
17 | |
18 | // This structure groups together data that describe the signature for which a marshaling stub is being generated. |
19 | struct StubSigDesc |
20 | { |
21 | public: |
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 | //======================================================================= |
57 | class NDirect |
58 | { |
59 | friend class NDirectMethodDesc; |
60 | |
61 | public: |
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 | |
122 | private: |
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 | |
135 | public: |
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 | //---------------------------------------------------------------- |
147 | enum 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 | |
190 | enum 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 | |
214 | inline bool SF_IsVarArgStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)); } |
215 | inline bool SF_IsBestFit (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_BESTFIT)); } |
216 | inline bool SF_IsThrowOnUnmappableChar (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_THROWONUNMAPPABLECHAR)); } |
217 | inline bool SF_IsNGENedStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)); } |
218 | inline bool SF_IsDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DELEGATE)); } |
219 | inline bool SF_IsHRESULTSwapping (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_DOHRESULTSWAPPING)); } |
220 | inline bool SF_IsReverseStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)); } |
221 | inline bool SF_IsNGENedStubForProfiling(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUBFORPROFILING)); } |
222 | inline bool SF_IsDebuggableStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_GENERATEDEBUGGABLEIL)); } |
223 | inline bool SF_IsCALLIStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)); } |
224 | inline bool SF_IsStubWithCctorTrigger (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_TRIGGERCCTOR)); } |
225 | inline 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 |
228 | inline 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 |
234 | inline bool SF_IsMulticastDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_MULTICASTDELEGATE_INVOKE); } |
235 | #endif |
236 | |
237 | #ifdef FEATURE_STUBS_AS_IL |
238 | inline bool SF_IsSecureDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_SECUREDELEGATE_INVOKE); } |
239 | inline bool SF_IsUnboxingILStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_UNBOXINGILSTUB); } |
240 | inline bool SF_IsInstantiatingStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_INSTANTIATINGSTUB); } |
241 | #endif |
242 | |
243 | inline bool SF_IsCOMStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COM)); } |
244 | inline bool SF_IsWinRTStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRT)); } |
245 | inline bool SF_IsCOMLateBoundStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMLATEBOUND)); } |
246 | inline bool SF_IsCOMEventCallStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COMEVENTCALL)); } |
247 | inline bool SF_IsFieldGetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDGETTER)); } |
248 | inline bool SF_IsFieldSetterStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_FIELDSETTER)); } |
249 | inline bool SF_IsWinRTDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTDELEGATE)); } |
250 | inline bool SF_IsWinRTCtorStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCTOR)); } |
251 | inline bool SF_IsWinRTCompositionStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTCOMPOSITION)); } |
252 | inline bool SF_IsWinRTStaticStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSTATIC)); } |
253 | inline bool SF_IsWinRTSharedGenericStub(DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTSHAREDGENERIC)); } |
254 | inline bool SF_IsWinRTHasRedirection (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRTHASREDIRECTION)); } |
255 | |
256 | inline 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 | |
269 | inline bool SF_IsForwardStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return !SF_IsReverseStub(dwStubFlags); } |
270 | |
271 | inline bool SF_IsForwardPInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } |
272 | inline bool SF_IsReversePInvokeStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (!SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } |
273 | |
274 | inline bool SF_IsForwardCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } |
275 | inline bool SF_IsReverseCOMStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsCOMStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } |
276 | |
277 | inline bool SF_IsForwardDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsForwardStub(dwStubFlags)); } |
278 | inline bool SF_IsReverseDelegateStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return (SF_IsDelegateStub(dwStubFlags) && SF_IsReverseStub(dwStubFlags)); } |
279 | |
280 | #undef COM_ONLY |
281 | |
282 | inline 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 | |
302 | enum 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 | //--------------------------------------------------------- |
321 | struct PInvokeStaticSigInfo |
322 | { |
323 | public: |
324 | enum ThrowOnError { THROW_ON_ERROR = TRUE, NO_THROW_ON_ERROR = FALSE }; |
325 | |
326 | public: |
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 | |
335 | public: |
336 | void ReportErrors(); |
337 | |
338 | private: |
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 | |
346 | public: |
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 | |
394 | private: |
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 | |
443 | class NDirectStubLinker : public ILStubLinker |
444 | { |
445 | public: |
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 (); |
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 | |
525 | protected: |
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. |
571 | BOOL HeuristicDoesThisLooksLikeAnApiCall(LPBYTE pTarget); |
572 | BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget); |
573 | DWORD STDMETHODCALLTYPE FalseGetLastError(); |
574 | |
575 | class NDirectStubParameters |
576 | { |
577 | public: |
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 | |
619 | PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD); |
620 | |
621 | MethodDesc *GetStubMethodDescFromInteropMethodDesc(MethodDesc* pMD, DWORD dwStubFlags); |
622 | PCODE JitILStub(MethodDesc* pStubMD); |
623 | MethodDesc *RestoreNGENedStub(MethodDesc* pStubMD); |
624 | PCODE GetStubForInteropMethod(MethodDesc* pMD, DWORD dwStubFlags = 0, MethodDesc **ppStubMD = NULL); |
625 | |
626 | #ifdef FEATURE_COMINTEROP |
627 | // Resolve and return the predefined IL stub method |
628 | HRESULT 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 | |
638 | class 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 | // |
644 | void 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 | //======================================================================= |
652 | class ILStubCreatorHelper |
653 | { |
654 | public: |
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 | |
725 | private: |
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 | |
735 | typedef Wrapper<ILStubCreatorHelper*, ILStubCreatorHelper::HolderEnter, ILStubCreatorHelper::HolderLeave> ILStubCreatorHelperHolder; |
736 | |
737 | #endif // __dllimport_h__ |
738 | |