[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / dllimportcallback.h
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: DllImportCallback.h
6 //
7
8 //
9
10
11 #ifndef __dllimportcallback_h__
12 #define __dllimportcallback_h__
13
14 #include "object.h"
15 #include "stublink.h"
16 #include "ceeload.h"
17 #include "class.h"
18 #include "dllimport.h"
19
20 enum UMThunkStubFlags
21 {
22     umtmlIsStatic           = 0x0001,
23     umtmlThisCall           = 0x0002,
24     umtmlThisCallHiddenArg  = 0x0004,
25     umtmlFpu                = 0x0008,
26 #ifdef _TARGET_X86_
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_
30 };
31
32 #include <pshpack1.h>
33 //--------------------------------------------------------------------------
34 // This structure captures basic info needed to build an UMThunk.
35 //--------------------------------------------------------------------------
36 struct UMThunkStubInfo
37 {
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
42 };
43 #include <poppack.h>
44
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.
50 //
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 //----------------------------------------------------------------------
55
56 class UMThunkMarshInfo
57 {
58     friend class CheckAsmOffsets;
59
60 private:
61     enum
62     {
63         kLoadTimeInited = 0x4c55544d,   //'LUTM'
64         kRunTimeInited  = 0x5255544d,   //'RUTM'
65     };
66
67 public:
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);
76
77     //----------------------------------------------------------
78     // This initializer finishes the init started by LoadTimeInit.
79     // It does all the ML stub creation, and can throw a COM+
80     // exception.
81     //
82     // It can safely be called multiple times and by concurrent
83     // threads.
84     //----------------------------------------------------------
85     VOID RunTimeInit();
86
87     // Destructor.
88     //----------------------------------------------------------
89     ~UMThunkMarshInfo();
90
91     //----------------------------------------------------------
92     // Accessor functions
93     //----------------------------------------------------------
94     Signature GetSignature()
95     {
96         LIMITED_METHOD_CONTRACT;
97         return m_sig;
98     }
99
100     Module* GetModule()
101     {
102         LIMITED_METHOD_CONTRACT;
103         return m_pModule;
104     }
105
106     MethodDesc * GetMethod()
107     {
108         LIMITED_METHOD_CONTRACT;
109         return m_pMD;
110     }
111
112 #if defined(_TARGET_X86_) && !defined(FEATURE_STUBS_AS_IL)
113     PCODE GetExecStubEntryPoint()
114     {
115         WRAPPER_NO_CONTRACT;
116         return GetExecStub()->GetEntryPoint();
117     }
118
119     Stub* GetExecStub()
120     {
121         CONTRACT (Stub*)
122         {
123             NOTHROW;
124             GC_NOTRIGGER;
125             MODE_ANY;
126             PRECONDITION(IsCompletelyInited());
127             POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
128         }
129         CONTRACT_END;
130
131         RETURN m_pExecStub;
132     }
133
134     UINT16 GetCbRetPop()
135     {
136         CONTRACTL
137         {
138             NOTHROW;
139             GC_NOTRIGGER;
140             MODE_ANY;
141             SUPPORTS_DAC;
142             PRECONDITION(IsCompletelyInited());
143         }
144         CONTRACTL_END;
145
146         return m_cbRetPop;
147     }
148
149     CorPinvokeMap GetCallingConvention()
150     {
151         CONTRACTL
152         {
153             NOTHROW;
154             GC_NOTRIGGER;
155             MODE_ANY;
156             SUPPORTS_DAC;
157             PRECONDITION(IsCompletelyInited());
158         }
159         CONTRACTL_END;
160
161         return (CorPinvokeMap)m_callConv;
162     }
163
164     VOID SetCallingConvention(const CorPinvokeMap callConv)
165     {
166         m_callConv = (UINT16)callConv;
167     }
168
169 #else
170     PCODE GetExecStubEntryPoint();
171 #endif
172
173     UINT32 GetCbActualArgSize()
174     {
175         CONTRACTL
176         {
177             NOTHROW;
178             GC_NOTRIGGER;
179             MODE_ANY;
180             PRECONDITION(IsCompletelyInited());
181         }
182         CONTRACTL_END;
183
184         return m_cbActualArgSize;
185     }
186
187     BOOL IsCompletelyInited()
188     {
189         LIMITED_METHOD_CONTRACT;
190         return (m_pILStub != (PCODE)1);
191     }
192
193     static MethodDesc* GetILStubMethodDesc(MethodDesc* pInvokeMD, PInvokeStaticSigInfo* pSigInfo, DWORD dwStubFlags);
194
195     static UINT32 GetOffsetOfStub()
196     {
197         LIMITED_METHOD_CONTRACT;
198         return (UINT32)offsetof(UMThunkMarshInfo, m_pILStub);
199     }
200
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
206
207 #if defined(_TARGET_X86_) && defined(FEATURE_STUBS_AS_IL)
208     struct ArgumentRegisters
209     {
210         UINT32 Ecx;
211         UINT32 Edx;
212     };
213
214     VOID SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst);
215 #endif // _TARGET_X86_ && FEATURE_STUBS_AS_IL
216
217 private:
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
227 #else
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_
232
233     MethodDesc *      m_pMD;                // maybe null
234     Module *          m_pModule;
235     Signature         m_sig;
236 };
237
238
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.
243 //
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 //----------------------------------------------------------------------
248 class UMEntryThunk
249 {
250     friend class CheckAsmOffsets;
251     friend class NDirectStubLinker;
252     friend class UMEntryThunkFreeList;
253
254 private:
255 #ifdef _DEBUG
256     enum
257     {
258         kLoadTimeInited = 0x4c554554,   //'LUET'
259         kRunTimeInited  = 0x52554554,   //'RUET'
260     };
261 #endif
262
263 public:
264     static UMEntryThunk* CreateUMEntryThunk();
265     static VOID FreeUMEntryThunk(UMEntryThunk* p);
266
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,
279                                      UINT *psrcofsregs,
280                                      UINT *psrcofs,
281                                      UINT retbufofs);
282 #endif // _TARGET_X86_ && !FEATURE_STUBS_AS_IL
283
284 #ifndef DACCESS_COMPILE
285     VOID LoadTimeInit(PCODE                   pManagedTarget,
286                       OBJECTHANDLE            pObjectHandle,
287                       UMThunkMarshInfo       *pUMThunkMarshInfo,
288                       MethodDesc             *pMD)
289     {
290         CONTRACTL
291         {
292             NOTHROW;
293             GC_NOTRIGGER;
294             MODE_ANY;
295             PRECONDITION(CheckPointer(pUMThunkMarshInfo));
296             PRECONDITION(pMD != NULL);
297         }
298         CONTRACTL_END;
299
300         m_pManagedTarget = pManagedTarget;
301         m_pObjectHandle     = pObjectHandle;
302         m_pUMThunkMarshInfo = pUMThunkMarshInfo;
303
304         m_pMD = pMD;    // For debugging and profiling, so they can identify the target
305
306         m_code.Encode((BYTE*)TheUMThunkPreStub(), this);
307
308 #ifdef _DEBUG
309         m_state = kLoadTimeInited;
310 #endif
311     }
312
313     ~UMEntryThunk()
314     {
315         CONTRACTL
316         {
317             NOTHROW;
318             GC_NOTRIGGER;
319             MODE_ANY;
320         }
321         CONTRACTL_END;
322
323         if (GetObjectHandle())
324         {
325             DestroyLongWeakHandle(GetObjectHandle());
326         }
327     }
328
329     void Terminate();
330
331     VOID RunTimeInit()
332     {
333         STANDARD_VM_CONTRACT;
334
335         // Ensure method's module is activate in app domain
336         m_pMD->EnsureActive();
337
338         m_pUMThunkMarshInfo->RunTimeInit();
339
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();
343
344         m_code.Encode((BYTE*)m_pUMThunkMarshInfo->GetExecStubEntryPoint(), this);
345
346 #ifdef _DEBUG
347         m_state = kRunTimeInited;
348 #endif
349     }
350
351     // asm entrypoint
352     static VOID STDCALL DoRunTimeInit(UMEntryThunk* pThis);
353
354     PCODE GetManagedTarget() const
355     {
356         CONTRACT (PCODE)
357         {
358             THROWS;
359             GC_TRIGGERS;
360             MODE_ANY;
361             PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
362             POSTCONDITION(RETVAL != NULL);
363         }
364         CONTRACT_END;
365
366         OBJECTHANDLE hndDelegate = GetObjectHandle();
367         if (hndDelegate != NULL)
368         {
369             GCX_COOP();
370
371             DELEGATEREF orDelegate = (DELEGATEREF)ObjectFromHandle(hndDelegate);
372             _ASSERTE(orDelegate != NULL);
373             _ASSERTE(m_pMD->IsEEImpl());
374                 
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();
379         }
380         else
381         {
382             if (m_pManagedTarget != NULL)
383             {
384                 RETURN m_pManagedTarget;
385             }
386             else
387             {
388                 RETURN m_pMD->GetMultiCallableAddrOfCode();
389             }
390         }
391     }
392 #endif // !DACCESS_COMPILE
393
394     OBJECTHANDLE GetObjectHandle() const
395     {
396         CONTRACT (OBJECTHANDLE)
397         {
398             NOTHROW;
399             GC_NOTRIGGER;
400             MODE_ANY;
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);
407         }
408         CONTRACT_END;
409
410         RETURN m_pObjectHandle;
411     }
412
413     UMThunkMarshInfo* GetUMThunkMarshInfo() const
414     {
415         CONTRACT (UMThunkMarshInfo*)
416         {
417             NOTHROW;
418             GC_NOTRIGGER;
419             MODE_ANY;
420             SUPPORTS_DAC;
421             PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
422             POSTCONDITION(CheckPointer(RETVAL));
423         }
424         CONTRACT_END;
425     
426         RETURN m_pUMThunkMarshInfo;
427     }
428     
429
430     const BYTE* GetCode() const
431     {
432         CONTRACT (const BYTE*)
433         {
434             NOTHROW;
435             GC_NOTRIGGER;
436             MODE_ANY;
437             PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
438             POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
439         }
440         CONTRACT_END;
441
442         RETURN m_code.GetEntryPoint();
443     }
444
445     static UMEntryThunk* RecoverUMEntryThunk(const VOID* pCode)
446     {
447         LIMITED_METHOD_CONTRACT;
448         return (UMEntryThunk*)( ((LPBYTE)pCode) - offsetof(UMEntryThunk, m_code) );
449     }
450
451
452     MethodDesc* GetMethod() const
453     {
454         CONTRACT (MethodDesc*)
455         {
456             NOTHROW;
457             GC_NOTRIGGER;
458             MODE_ANY;
459             PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
460             POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
461         }
462         CONTRACT_END;
463
464         RETURN m_pMD;
465     }
466
467     static DWORD GetOffsetOfMethodDesc()
468     {
469         LIMITED_METHOD_CONTRACT;
470         return offsetof(class UMEntryThunk, m_pMD);
471     }
472
473     static DWORD GetCodeOffset()
474     {
475         LIMITED_METHOD_CONTRACT;
476         return offsetof(UMEntryThunk, m_code);
477     }
478
479     static UMEntryThunk* Decode(LPVOID pCallback);
480
481     static VOID __fastcall ReportViolation(UMEntryThunk* p);
482
483 private:
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;
488
489     // This is used for profiling.
490     PTR_MethodDesc          m_pMD;
491
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;
495
496     union
497     {
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;
502     };
503
504 #ifdef _DEBUG
505     DWORD                   m_state;        // the initialization state
506 #endif
507
508     UMEntryThunkCode        m_code;
509 };
510
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
514 {
515 public:
516     UMEntryThunkCache(AppDomain *pDomain);
517     ~UMEntryThunkCache();
518
519     UMEntryThunk *GetUMEntryThunk(MethodDesc *pMD);
520
521 private:
522     struct CacheElement
523     {
524         CacheElement()
525         {
526             LIMITED_METHOD_CONTRACT;
527             m_pMD = NULL;
528             m_pThunk = NULL;
529         }
530
531         MethodDesc   *m_pMD;
532         UMEntryThunk *m_pThunk;
533     };
534
535     class ThunkSHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits<CacheElement> >
536     {
537     public:
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); }
544     };
545
546     static void DestroyMarshInfo(UMThunkMarshInfo *pMarshInfo)
547     {
548         WRAPPER_NO_CONTRACT;
549         pMarshInfo->~UMThunkMarshInfo();
550     }
551
552     SHash<ThunkSHashTraits> m_hash;
553     Crst       m_crst;
554     AppDomain *m_pDomain;
555 };
556
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
563
564 //-------------------------------------------------------------------------
565 // NExport stub
566 //-------------------------------------------------------------------------
567 #if  !defined(_WIN64) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
568 EXCEPTION_HANDLER_DECL(FastNExportExceptHandler);
569 EXCEPTION_HANDLER_DECL(UMThunkPrestubHandler);
570 #endif // _WIN64
571
572 extern "C" void TheUMEntryPrestub(void);
573 extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk);
574
575 EXTERN_C void UMThunkStub(void);
576
577 #ifdef _DEBUG
578 void STDCALL LogUMTransition(UMEntryThunk* thunk);
579 #endif
580
581 #endif //__dllimportcallback_h__