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.
5 // File: DllImportCallback.h
11 #ifndef __dllimportcallback_h__
12 #define __dllimportcallback_h__
18 #include "dllimport.h"
22 umtmlIsStatic = 0x0001,
23 umtmlThisCall = 0x0002,
24 umtmlThisCallHiddenArg = 0x0004,
27 // the signature is trivial so stub need not be generated and the target can be called directly
28 umtmlSkipStub = 0x0080,
29 #endif // _TARGET_X86_
33 //--------------------------------------------------------------------------
34 // This structure captures basic info needed to build an UMThunk.
35 //--------------------------------------------------------------------------
36 struct UMThunkStubInfo
38 UINT32 m_cbDstStack; //# of bytes of stack portion of managed args
39 UINT16 m_cbSrcStack; //# of bytes of stack portion of unmanaged args
40 UINT16 m_cbRetPop; //# of bytes to pop on return to unmanaged
41 UINT16 m_wFlags; // UMThunkStubFlags enum
45 //----------------------------------------------------------------------
46 // This structure collects all information needed to marshal an
47 // unmanaged->managed thunk. The only information missing is the
48 // managed target and the "this" object (if any.) Those two pieces
49 // are broken out into a small UMEntryThunk.
51 // The idea is to share UMThunkMarshInfo's between multiple thunks
52 // that have the same signature while the UMEntryThunk contains the
53 // minimal info needed to distinguish between actual function pointers.
54 //----------------------------------------------------------------------
56 class UMThunkMarshInfo
58 friend class CheckAsmOffsets;
63 kLoadTimeInited = 0x4c55544d, //'LUTM'
64 kRunTimeInited = 0x5255544d, //'RUTM'
68 //----------------------------------------------------------
69 // This initializer can be called during load time.
70 // It does not do any ML stub initialization or sigparsing.
71 // The RunTimeInit() must be called subsequently before this
72 // can safely be used.
73 //----------------------------------------------------------
74 VOID LoadTimeInit(MethodDesc* pMD);
75 VOID LoadTimeInit(Signature sig, Module * pModule, MethodDesc * pMD = NULL);
77 //----------------------------------------------------------
78 // This initializer finishes the init started by LoadTimeInit.
79 // It does all the ML stub creation, and can throw a COM+
82 // It can safely be called multiple times and by concurrent
84 //----------------------------------------------------------
88 //----------------------------------------------------------
91 //----------------------------------------------------------
93 //----------------------------------------------------------
94 Signature GetSignature()
96 LIMITED_METHOD_CONTRACT;
102 LIMITED_METHOD_CONTRACT;
106 MethodDesc * GetMethod()
108 LIMITED_METHOD_CONTRACT;
112 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
113 PCODE GetExecStubEntryPoint()
116 return GetExecStub()->GetEntryPoint();
126 PRECONDITION(IsCompletelyInited());
127 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
142 PRECONDITION(IsCompletelyInited());
149 CorPinvokeMap GetCallingConvention()
157 PRECONDITION(IsCompletelyInited());
161 return (CorPinvokeMap)m_callConv;
164 VOID SetCallingConvention(const CorPinvokeMap callConv)
166 m_callConv = (UINT16)callConv;
170 PCODE GetExecStubEntryPoint();
173 UINT32 GetCbActualArgSize()
180 PRECONDITION(IsCompletelyInited());
184 return m_cbActualArgSize;
187 BOOL IsCompletelyInited()
189 LIMITED_METHOD_CONTRACT;
190 return (m_pILStub != (PCODE)1);
193 static MethodDesc* GetILStubMethodDesc(MethodDesc* pInvokeMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags);
195 static UINT32 GetOffsetOfStub()
197 LIMITED_METHOD_CONTRACT;
198 return (UINT32)offsetof(UMThunkMarshInfo, m_pILStub);
201 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
202 // Compiles an unmanaged to managed thunk for the given signature. The thunk
203 // will call the stub or, if fNoStub == TRUE, directly the managed target.
204 Stub *CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub);
205 #endif // _TARGET_X86_ && !FEATURE_STUBS_AS_IL
207 #if defined(_TARGET_X86_) && defined(FEATURE_STUBS_AS_IL)
208 struct ArgumentRegisters
214 VOID SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst);
215 #endif // _TARGET_X86_ && FEATURE_STUBS_AS_IL
218 PCODE m_pILStub; // IL stub for marshaling
219 // On x86, NULL for no-marshal signatures
220 // On non-x86, the managed entrypoint for no-delegate no-marshal signatures
221 UINT32 m_cbActualArgSize; // caches m_pSig.SizeOfFrameArgumentArray()
222 // On x86/Linux we have to augment with numRegistersUsed * STACK_ELEM_SIZE
223 #if defined(_TARGET_X86_)
224 UINT16 m_cbRetPop; // stack bytes popped by callee (for UpdateRegDisplay)
225 #if defined(FEATURE_STUBS_AS_IL)
226 UINT32 m_cbStackArgSize; // stack bytes pushed for managed code
228 Stub* m_pExecStub; // UMEntryThunk jumps directly here
229 UINT16 m_callConv; // unmanaged calling convention and flags (CorPinvokeMap)
230 #endif // FEATURE_STUBS_AS_IL
231 #endif // _TARGET_X86_
233 MethodDesc * m_pMD; // maybe null
239 //----------------------------------------------------------------------
240 // This structure contains the minimal information required to
241 // distinguish one function pointer from another, with the rest
242 // being stored in a shared UMThunkMarshInfo.
244 // This structure also contains the actual code bytes that form the
245 // front end of the thunk. A pointer to the m_code[] byte array is
246 // what is actually handed to unmanaged client code.
247 //----------------------------------------------------------------------
250 friend class CheckAsmOffsets;
251 friend class NDirectStubLinker;
252 friend class UMEntryThunkFreeList;
258 kLoadTimeInited = 0x4c554554, //'LUET'
259 kRunTimeInited = 0x52554554, //'RUET'
264 static UMEntryThunk* CreateUMEntryThunk();
265 static VOID FreeUMEntryThunk(UMEntryThunk* p);
267 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
268 // Compiles an unmanaged to managed thunk with the given calling convention adaptation.
269 // - psrcofsregs are stack offsets that should be loaded to argument registers (ECX, EDX)
270 // - psrcofs are stack offsets that should be repushed for the managed target
271 // - retbufofs is the offset of the hidden byref structure argument when returning large
272 // structures; -1 means there is none
273 // Special values recognized by psrcofsregs and psrcofs are -1 which means not present
274 // and 1 which means that this register/stack slot should get the UMEntryThunk pointer.
275 // This method is used for all reverse P/Invoke calls on x86 (the umtmlSkipStub
276 // flag determines whether the managed target is stub or the actual target method).
277 static VOID CompileUMThunkWorker(UMThunkStubInfo *pInfo,
278 CPUSTUBLINKER *pcpusl,
282 #endif // _TARGET_X86_ && !FEATURE_STUBS_AS_IL
284 #ifndef DACCESS_COMPILE
285 VOID LoadTimeInit(PCODE pManagedTarget,
286 OBJECTHANDLE pObjectHandle,
287 UMThunkMarshInfo *pUMThunkMarshInfo,
295 PRECONDITION(CheckPointer(pUMThunkMarshInfo));
296 PRECONDITION(pMD != NULL);
300 m_pManagedTarget = pManagedTarget;
301 m_pObjectHandle = pObjectHandle;
302 m_pUMThunkMarshInfo = pUMThunkMarshInfo;
304 m_pMD = pMD; // For debugging and profiling, so they can identify the target
306 m_code.Encode((BYTE*)TheUMThunkPreStub(), this);
309 m_state = kLoadTimeInited;
323 if (GetObjectHandle())
325 DestroyLongWeakHandle(GetObjectHandle());
333 STANDARD_VM_CONTRACT;
335 // Ensure method's module is activate in app domain
336 m_pMD->EnsureActive();
338 m_pUMThunkMarshInfo->RunTimeInit();
340 // Ensure that we have either the managed target or the delegate.
341 if (m_pObjectHandle == NULL && m_pManagedTarget == NULL)
342 m_pManagedTarget = m_pMD->GetMultiCallableAddrOfCode();
344 m_code.Encode((BYTE*)m_pUMThunkMarshInfo->GetExecStubEntryPoint(), this);
347 m_state = kRunTimeInited;
352 static VOID STDCALL DoRunTimeInit(UMEntryThunk* pThis);
354 PCODE GetManagedTarget() const
361 PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
362 POSTCONDITION(RETVAL != NULL);
366 OBJECTHANDLE hndDelegate = GetObjectHandle();
367 if (hndDelegate != NULL)
371 DELEGATEREF orDelegate = (DELEGATEREF)ObjectFromHandle(hndDelegate);
372 _ASSERTE(orDelegate != NULL);
373 _ASSERTE(m_pMD->IsEEImpl());
375 // We have optimizations that skip the Invoke method and call directly the
376 // delegate's target method. We need to return the target in that case,
377 // otherwise debugger would fail to step in.
378 RETURN orDelegate->GetMethodPtr();
382 if (m_pManagedTarget != NULL)
384 RETURN m_pManagedTarget;
388 RETURN m_pMD->GetMultiCallableAddrOfCode();
392 #endif // !DACCESS_COMPILE
394 OBJECTHANDLE GetObjectHandle() const
396 CONTRACT (OBJECTHANDLE)
401 // If we OOM after we create the holder but
402 // before we set the m_state we can have
403 // m_state == 0 and m_pObjectHandle == NULL
404 PRECONDITION(m_state == kRunTimeInited ||
405 m_state == kLoadTimeInited ||
406 m_pObjectHandle == NULL);
410 RETURN m_pObjectHandle;
413 UMThunkMarshInfo* GetUMThunkMarshInfo() const
415 CONTRACT (UMThunkMarshInfo*)
421 PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
422 POSTCONDITION(CheckPointer(RETVAL));
426 RETURN m_pUMThunkMarshInfo;
430 const BYTE* GetCode() const
432 CONTRACT (const BYTE*)
437 PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
438 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
442 RETURN m_code.GetEntryPoint();
445 static UMEntryThunk* RecoverUMEntryThunk(const VOID* pCode)
447 LIMITED_METHOD_CONTRACT;
448 return (UMEntryThunk*)( ((LPBYTE)pCode) - offsetof(UMEntryThunk, m_code) );
452 MethodDesc* GetMethod() const
454 CONTRACT (MethodDesc*)
459 PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
460 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
467 static DWORD GetOffsetOfMethodDesc()
469 LIMITED_METHOD_CONTRACT;
470 return offsetof(class UMEntryThunk, m_pMD);
473 static DWORD GetCodeOffset()
475 LIMITED_METHOD_CONTRACT;
476 return offsetof(UMEntryThunk, m_code);
479 static UMEntryThunk* Decode(LPVOID pCallback);
481 static VOID __fastcall ReportViolation(UMEntryThunk* p);
484 // The start of the managed code.
485 // if m_pObjectHandle is non-NULL, this field is still set to help with diagnostic of call on collected delegate crashes
486 // but it may not have the correct value.
487 PCODE m_pManagedTarget;
489 // This is used for profiling.
490 PTR_MethodDesc m_pMD;
492 // Object handle holding "this" reference. May be a strong or weak handle.
493 // Field is NULL for a static method.
494 OBJECTHANDLE m_pObjectHandle;
498 // Pointer to the shared structure containing everything else
499 PTR_UMThunkMarshInfo m_pUMThunkMarshInfo;
500 // Pointer to the next UMEntryThunk in the free list. Used when it is freed.
501 UMEntryThunk *m_pNextFreeThunk;
505 DWORD m_state; // the initialization state
508 UMEntryThunkCode m_code;
511 // Cache to hold UMEntryThunk/UMThunkMarshInfo instances associated with MethodDescs.
512 // All UMEntryThunk/UMThunkMarshInfo instances are destroyed when the cache goes away.
513 class UMEntryThunkCache
516 UMEntryThunkCache(AppDomain *pDomain);
517 ~UMEntryThunkCache();
519 UMEntryThunk *GetUMEntryThunk(MethodDesc *pMD);
526 LIMITED_METHOD_CONTRACT;
532 UMEntryThunk *m_pThunk;
535 class ThunkSHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits<CacheElement> >
538 typedef MethodDesc *key_t;
539 static key_t GetKey(element_t e) { LIMITED_METHOD_CONTRACT; return e.m_pMD; }
540 static BOOL Equals(key_t k1, key_t k2) { LIMITED_METHOD_CONTRACT; return (k1 == k2); }
541 static count_t Hash(key_t k) { LIMITED_METHOD_CONTRACT; return (count_t)(size_t)k; }
542 static const element_t Null() { LIMITED_METHOD_CONTRACT; return CacheElement(); }
543 static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return (e.m_pMD == NULL); }
546 static void DestroyMarshInfo(UMThunkMarshInfo *pMarshInfo)
549 pMarshInfo->~UMThunkMarshInfo();
552 SHash<ThunkSHashTraits> m_hash;
554 AppDomain *m_pDomain;
557 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
558 //-------------------------------------------------------------------------
559 // One-time creation of special prestub to initialize UMEntryThunks.
560 //-------------------------------------------------------------------------
561 Stub *GenerateUMThunkPrestub();
562 #endif // _TARGET_X86_ && !FEATURE_STUBS_AS_IL
564 //-------------------------------------------------------------------------
566 //-------------------------------------------------------------------------
567 #if !defined(_WIN64) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
568 EXCEPTION_HANDLER_DECL(FastNExportExceptHandler);
569 EXCEPTION_HANDLER_DECL(UMThunkPrestubHandler);
572 extern "C" void TheUMEntryPrestub(void);
573 extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk);
575 EXTERN_C void UMThunkStub(void);
578 void STDCALL LogUMTransition(UMEntryThunk* thunk);
581 #endif //__dllimportcallback_h__