// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // // File: remoting.h // // // Purpose: Defines various remoting related objects such as // proxies // // #ifndef __REMOTING_H__ #define __REMOTING_H__ #ifndef FEATURE_REMOTING #error FEATURE_REMOTING is not set, please do not include remoting.h #endif #include "fcall.h" #include "stubmgr.h" // Forward declaration class TPMethodFrame; // @TODO: Set the hashtable to delete the data. // Thunk hash table - the keys are MethodDesc typedef EEHashTable, FALSE> EEThunkHashTable; // ConstVirtualThunkSize declares the size of the code generated by // CTPMethodTable::CreateThunkForVirtualMethod #ifdef _TARGET_X86_ static const DWORD ConstVirtualThunkSize = sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE) + sizeof(LONG); #elif defined(_TARGET_AMD64_) static const DWORD ConstVirtualThunkSize = sizeof(DWORD) + sizeof(UINT64) + 7; #elif defined(_TARGET_ARM_) static const DWORD ConstVirtualThunkSize = 12; #else PORTABILITY_WARNING("Remoting thunk size not defined for this platform.") static const DWORD ConstVirtualThunkSize = sizeof(LPVOID); #endif extern "C" { UINT_PTR __stdcall CRemotingServices__CheckForContextMatch(Object* pStubData); void __stdcall CRemotingServices__DispatchInterfaceCall(); void __stdcall CRemotingServices__CallFieldGetter(MethodDesc *pMD, LPVOID pThis, LPVOID pFirst, LPVOID pSecond, LPVOID pThird); void __stdcall CRemotingServices__CallFieldSetter(MethodDesc *pMD, LPVOID pThis, LPVOID pFirst, LPVOID pSecond, LPVOID pThird); } extern "C" LPVOID __stdcall CTPMethodTable__CallTargetHelper2(const void *pTarget, LPVOID pvFirst, LPVOID pvSecond); extern "C" LPVOID __stdcall CTPMethodTable__CallTargetHelper3(const void *pTarget, LPVOID pvFirst, LPVOID pvSecond, LPVOID pvThird); extern "C" BOOL __stdcall CTPMethodTable__GenericCheckForContextMatch(Object* orTP); // These are the values returned by RequiresManagedActivation enum ManagedActivationType { NoManagedActivation = 0, ManagedActivation = 0x1, #ifdef FEATURE_COMINTEROP ComObjectType = 0x2, #endif // FEATURE_COMINTEROP }; struct timingData { DWORD threadId; BYTE stage; __int64 cycleCount; }; // This struct is also accessed from managed world struct messageData { PVOID pFrame; MethodDesc *pMethodDesc; MethodDesc *pDelegateMD; MetaSig *pSig; TypeHandle thGoverningType; INT32 iFlags; }; // The real proxy class is the class behind the // transparent proxy class class CRealProxy { public: // Native helpers static FCDECL2(VOID, SetStubData, Object* orRPUNSAFE, Object* orStubDataUNSAFE); static FCDECL1(Object*, GetStubData, Object* orRPUNSAFE); static FCDECL1(LPVOID, GetStub, Object* orRPUNSAFE); static FCDECL0(LPVOID, GetDefaultStub); static FCDECL1(Object*, GetProxiedType, Object* orRPUNSAFE); static VOID UpdateOptFlags(OBJECTREF refTP); static BOOL ProxyTypeIdentityCheck(MethodTable *pCliHierarchy, MethodTable *pSrvHierarchy); }; // Forward declarations class CVirtualThunkMgr; class CNonVirtualThunkMgr; // Class that provides various remoting services // to the exposed world class CRemotingServices { private: //+------------------------------------------------------------------- // // Struct: FieldArgs // // Synopsis: Structure to GC protect arguments for a field accessor call. // DO NOT add non OBJECTREF data types in the structure // see GCPROTECT_BEGIN() for a better explanation. // //+------------------------------------------------------------------- typedef struct _FieldArgs { OBJECTREF obj; OBJECTREF val; STRINGREF typeName; STRINGREF fieldName; } FieldArgs; public: // Methods related to interception of non virtual methods & virtual methods called // non virtually static PCODE GetNonVirtualEntryPointForVirtualMethod(MethodDesc* pMD); #ifndef HAS_REMOTING_PRECODE static Stub* GetStubForNonVirtualMethod(MethodDesc* pMD, LPVOID pvAddrOfCode, Stub* pInnerStub); #endif static void DestroyThunk(MethodDesc* pMD); // Methods related to interception of interface calls static PCODE GetDispatchInterfaceHelper(MethodDesc* pMD); static OBJECTREF CreateProxyOrObject(MethodTable *pMT, BOOL fIsCom = FALSE, BOOL fIsNewObj = FALSE); // Methods related to field accessors static void FieldAccessor(FieldDesc* pFD, OBJECTREF o, LPVOID pVal, BOOL fIsGetter); // Methods related to wrapping/unwrapping of objects static OBJECTREF WrapHelper(OBJECTREF obj); static OBJECTREF Wrap(OBJECTREF obj); static OBJECTREF GetProxyFromObject(OBJECTREF obj); static OBJECTREF GetObjectFromProxy(OBJECTREF obj); static BOOL IsProxyToRemoteObject(OBJECTREF obj); static OBJECTREF GetServerContext(OBJECTREF obj); // Methods related to creation and marshaling of appdomains static OBJECTREF CreateProxyForDomain(AppDomain *pDomain); // Extract the true class of a proxy static REFLECTCLASSBASEREF GetClass(OBJECTREF pThis); // Initialization function. static VOID Initialize(); // Start up function. This actually starts up the remoting services. static void EnsureRemotingStarted(); // Other helper functions. inline static MethodDesc *MDofPrivateInvoke() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pRPPrivateInvoke; } inline static MethodDesc *MDofInvokeStatic() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pRPInvokeStatic; } inline static MethodDesc *MDofIsCurrentContextOK() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pIsCurrentContextOK; } inline static MethodDesc *MDofCheckCast() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pCheckCast; } inline static MethodDesc *MDofWrap() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pWrapMethodDesc; } inline static MethodDesc *MDofFieldSetter() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pFieldSetterDesc; } inline static MethodDesc *MDofFieldGetter() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pFieldGetterDesc; } inline static MethodDesc *MDofGetType() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pGetTypeDesc; } inline static MethodDesc *MDofObjectGetType() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pObjectGetTypeDesc; } #ifdef FEATURE_COMINTEROP inline static MethodDesc *MDofCreateObjectForCom() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pCreateObjectForCom; } static BOOL CallSupportsInterface(OBJECTREF realProxy, REFIID iid, ARG_SLOT *pret); // helpers to call methods in real proxy static VOID CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk); #endif // FEATURE_COMINTEROP inline static BOOL IsInstanceOfServerIdentity(MethodTable* pMT) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(pMT)); } CONTRACTL_END; return s_pServerIdentityClass == pMT; } inline static MethodTable *GetMarshalByRefClass() { CONTRACT (MethodTable*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pMarshalByRefObjectClass; } static INT32 IsTransparentProxy(Object* obj); static Object* GetRealProxy(Object* obj); static BOOL CheckCast(OBJECTREF orTP, TypeHandle ty); static BOOL CheckCast(OBJECTREF orTP, TypeHandle objTy, TypeHandle ty); static OBJECTREF GetExposedContext(); static AppDomain *GetServerDomainForProxy(OBJECTREF orTP); static Context *GetServerContextForProxy(OBJECTREF orTP); static int GetServerDomainIdForProxy(OBJECTREF orTP); static UINT_PTR CheckForContextMatch(Object* pStubData); static ManagedActivationType __stdcall RequiresManagedActivation(TypeHandle ty); static BOOL IsRemotingStarted() { LIMITED_METHOD_CONTRACT; return s_fRemotingStarted; }; static DWORD GetOffsetOfSrvIdentityInRP() { return s_dwSrvIdentityOffsetInRealProxy; } static DWORD GetOffsetOfCliIdentityInRP() { return s_dwIdOffset; } static DWORD GetOffsetOfTPOrObjInIdentity() { return s_dwTPOrObjOffsetInIdentity; } static DWORD GetOffsetOfLeaseInIdentity() { return s_dwLeaseOffsetInIdentity; } static DWORD GetOffsetOfURIInIdentity() { return s_dwURIOffsetInIdentity; } inline static MethodDesc *MDofRenewLeaseOnCall() { return s_pRenewLeaseOnCallDesc; } static PCODE GetStubForInterfaceMethod(MethodDesc *pItfMD); private: static void StartRemoting(); static void CopyDestToSrc(LPVOID pDest, LPVOID pSrc, UINT cbSize); static void CallFieldAccessor(FieldDesc* pFD, OBJECTREF o, VOID * pVal, BOOL fIsGetter, BOOL fIsByValue, BOOL fIsGCRef, TypeHandle ty, TypeHandle fldTy, CorElementType fieldType, UINT cbSize); static void GetTypeAndFieldName(FieldArgs *pArgs, FieldDesc *pFD, TypeHandle thEnclosingClass); static BOOL MatchField(FieldDesc* pCurField, LPCUTF8 szFieldName); static OBJECTREF SetExposedContext(OBJECTREF newContext); static OBJECTREF GetServerIdentityFromProxy(OBJECTREF obj); inline static MethodDesc *MDOfCreateProxyForDomain() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pProxyForDomainDesc; } inline static MethodDesc *MDofGetServerContextForProxy() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pServerContextForProxyDesc; } inline static MethodDesc *MDofGetServerDomainIdForProxy() { CONTRACT (MethodDesc*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN s_pServerDomainIdForProxyDesc; } static VOID InitActivationServicesClass(); static VOID InitRealProxyClass(); static VOID InitRemotingProxyClass(); static VOID InitServerIdentityClass(); static VOID InitIdentityClass(); static VOID InitMarshalByRefObjectClass(); static VOID InitRemotingServicesClass(); static VOID InitObjectClass(); static VOID InitLeaseClass(); static MethodTable *s_pMarshalByRefObjectClass; static MethodTable *CRemotingServices::s_pServerIdentityClass; static MethodTable *CRemotingServices::s_pContextClass; static MethodDesc *s_pRPPrivateInvoke; static MethodDesc *s_pRPInvokeStatic; static MethodDesc *s_pIsCurrentContextOK; static MethodDesc *s_pCheckCast; static MethodDesc *s_pWrapMethodDesc; static MethodDesc *s_pFieldSetterDesc; static MethodDesc *s_pFieldGetterDesc; static MethodDesc *s_pObjectGetTypeDesc; static MethodDesc *s_pGetTypeDesc; static MethodDesc *s_pProxyForDomainDesc; static MethodDesc *s_pServerContextForProxyDesc; static MethodDesc *s_pServerDomainIdForProxyDesc; static MethodDesc *s_pRenewLeaseOnCallDesc; static DWORD s_dwIdOffset; static DWORD s_dwServerOffsetInRealProxy; static DWORD s_dwSrvIdentityOffsetInRealProxy; static DWORD s_dwTPOrObjOffsetInIdentity; static DWORD s_dwLeaseOffsetInIdentity; static DWORD s_dwURIOffsetInIdentity; static DWORD s_dwMBRIDOffset; static CrstStatic s_RemotingCrst; static BOOL s_fRemotingStarted; #ifdef FEATURE_COMINTEROP static MethodDesc *s_pCreateObjectForCom; #endif // FEATURE_COMINTEROP }; // Class that manages transparent proxy thunks class CVirtualThunks { public: inline static CVirtualThunks* GetVirtualThunks() { CONTRACT (CVirtualThunks*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); SO_TOLERANT; } CONTRACT_END; RETURN s_pVirtualThunks; } inline static CVirtualThunks* SetVirtualThunks(CVirtualThunks* pThunks) { CONTRACT (CVirtualThunks*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(pThunks)); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN (s_pVirtualThunks = pThunks); } inline CVirtualThunks* GetNextThunk() { CONTRACT (CVirtualThunks*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); SO_TOLERANT; } CONTRACT_END; RETURN _pNext; } // Public member variables CVirtualThunks *_pNext; DWORD _dwReservedThunks; DWORD _dwStartThunk; DWORD _dwCurrentThunk; #ifdef CVIRTUALTHUNKS_ALIGNPAD_BYTES BYTE pad[CVIRTUALTHUNKS_ALIGNPAD_BYTES]; #endif struct tagThunkCode { BYTE pCode[ConstVirtualThunkSize]; } ThunkCode[1]; private: // Cannot be created CVirtualThunks(CVirtualThunks *pNext, DWORD dwCommitedSlots, DWORD dwReservedSlots, DWORD dwStartSlot, DWORD dwCurrentSlot) { LIMITED_METHOD_CONTRACT; } // Private statics static CVirtualThunks *s_pVirtualThunks; }; #ifndef HAS_REMOTING_PRECODE class CNonVirtualThunk { public: // Constructor CNonVirtualThunk(const BYTE* pbCode) : _addrOfCode(pbCode), _pNext(NULL) { WRAPPER_NO_CONTRACT; } ~CNonVirtualThunk(); inline LPVOID* GetAddrOfCode() { CONTRACT (LPVOID*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN (LPVOID*)&_addrOfCode; } inline const BYTE* GetThunkCode() { CONTRACT (const BYTE*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); SO_TOLERANT; } CONTRACT_END; RETURN _addrOfCode; } inline CNonVirtualThunk* GetNextThunk() { CONTRACT (CNonVirtualThunk*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); SO_TOLERANT; } CONTRACT_END; RETURN _pNext; } static void InitializeListLock(); static CNonVirtualThunk* AddrToThunk(LPVOID pAddr); inline static CNonVirtualThunk* GetNonVirtualThunks() { CONTRACT (CNonVirtualThunk*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); SO_TOLERANT; } CONTRACT_END; RETURN s_pNonVirtualThunks; } inline static SimpleRWLock* GetThunksListLock() { LIMITED_METHOD_CONTRACT; return s_pNonVirtualThunksListLock; } static CNonVirtualThunk* SetNonVirtualThunks(const BYTE* pbCode); const BYTE* _addrOfCode; private: void SetNextThunk(); // Private statics static CNonVirtualThunk *s_pNonVirtualThunks; // reader/writer lock to be taken when manipulating s_pNonVirtualThunks static SimpleRWLock* s_pNonVirtualThunksListLock; // Private members CNonVirtualThunk* _pNext; }; inline void CNonVirtualThunk::InitializeListLock() { CONTRACTL { THROWS; GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; if (s_pNonVirtualThunksListLock == NULL) s_pNonVirtualThunksListLock = new SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT); } inline void CNonVirtualThunk::SetNextThunk() { LIMITED_METHOD_CONTRACT; SimpleRWLock::SimpleWriteLockHolder swlh(s_pNonVirtualThunksListLock); _pNext = s_pNonVirtualThunks; s_pNonVirtualThunks = this; } inline CNonVirtualThunk* CNonVirtualThunk::AddrToThunk(LPVOID pAddr) { CONTRACT (CNonVirtualThunk*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(pAddr)); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN (CNonVirtualThunk *)((size_t)pAddr - (size_t)offsetof(CNonVirtualThunk, _addrOfCode)); } #endif // HAS_REMOTING_PRECODE class CTPMethodTable { friend class CRemotingServices; friend class RemotingNative; public: // Public statics static DWORD GetCommitedTPSlots() { LIMITED_METHOD_CONTRACT; return s_dwCommitedTPSlots; } static MethodTable *GetMethodTable() { CONTRACT (MethodTable*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; POSTCONDITION(CheckPointer(RETVAL)); SO_TOLERANT; } CONTRACT_END; RETURN s_pThunkTable; } static VOID Initialize(); #ifndef HAS_REMOTING_PRECODE static PTR_PCODE GetOrCreateNonVirtualSlotForVirtualMethod(MethodDesc* pMD); static PCODE CreateNonVirtualThunkForVirtualMethod(MethodDesc* pMD); static Stub* CreateStubForNonVirtualMethod(MethodDesc* pMD, CPUSTUBLINKER *psl, LPVOID pvAddrOfCode, Stub* pInnerStub); #endif // HAS_REMOTING_PRECODE static REALPROXYREF GetRP(OBJECTREF orTP); static MethodTable * GetMethodTableBeingProxied(OBJECTREF orTP); static LPVOID __stdcall CallTarget(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond); static LPVOID __stdcall CallTarget(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond, LPVOID pvThird); static BOOL CheckCastHelper(MethodDesc* pTargetMD, LPVOID pvFirst, LPVOID pvSecond); static BOOL CheckCast(MethodDesc* pTargetMD, TRANSPARENTPROXYREF orTP, TypeHandle ty); static void RefineProxy(TRANSPARENTPROXYREF orTP, TypeHandle ty); static PCODE GetTPStubEntryPoint(); static PCODE GetDelegateStubEntryPoint(); static void DestroyThunk(MethodDesc* pMD); // Interpretation of __TransparentProxy._stub typedef UINT_PTR CheckContextCrossingProc (Object*); inline static BOOL IsInstanceOfRemotingProxy(MethodTable *pMT) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(pMT)); } CONTRACTL_END; return s_pRemotingProxyClass == pMT; } private: #ifndef DACCESS_COMPILE // Private statics static void InitThunkTable(DWORD dwCommitedTPSlots, DWORD dwReservedTPSlots, MethodTable* pTPMethodTable) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(pTPMethodTable)); } CONTRACTL_END; s_dwCommitedTPSlots = dwCommitedTPSlots; s_dwReservedTPSlots = dwReservedTPSlots; s_pThunkTable = pTPMethodTable; } static void DestroyThunkTable() { WRAPPER_NO_CONTRACT; ::ClrVirtualFree(MTToAlloc(s_pThunkTable, s_dwGCInfoBytes), 0, MEM_RELEASE); s_pThunkTable = NULL; s_dwCommitedTPSlots = 0; s_dwReservedTPSlots = 0; } #endif // #ifndef DACCESS_COMPILE static void EnsureFieldsInitialized(); static void CreateTPOfClassForRP(TypeHandle ty, REALPROXYREF *pRP, TRANSPARENTPROXYREF *pTP); static void CreateTPMethodTable(MethodTable* pTPMT); static BOOL ExtendCommitedSlots(_In_range_(1,64*1024) DWORD dwSlots); static BOOL AllocateThunks(DWORD dwSlots, DWORD dwCommitSize); #ifdef HAS_REMOTING_PRECODE static void ActivatePrecodeRemotingThunk(); #endif // HAS_REMOTING_PRECODE static MethodTable *AllocToMT(BYTE *Alloc, LONG off) { CONTRACT (MethodTable*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(Alloc)); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN (MethodTable *) (Alloc + off); } static BYTE *MTToAlloc(MethodTable *MT, LONG off) { CONTRACT (BYTE*) { NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(CheckPointer(MT)); POSTCONDITION(CheckPointer(RETVAL)); } CONTRACT_END; RETURN (((BYTE *) MT) - off); } static PCODE CreateThunkForVirtualMethod(DWORD dwSlot, BYTE *bCode); // Static members static DWORD s_dwCommitedTPSlots; static DWORD s_dwReservedTPSlots; static DWORD s_dwReservedTPIndirectionSlotSize; SPTR_DECL(MethodTable, s_pThunkTable); static MethodTable* s_pRemotingProxyClass; static DWORD s_dwGCInfoBytes; static DWORD s_dwMTDataSlots; static CrstStatic s_TPMethodTableCrst; static EEThunkHashTable *s_pThunkHashTable; static BOOL s_fTPTableFieldsInitialized; }; extern "C" UINT32 STDCALL TransparentProxyStubWorker(TransitionBlock * pTransitionBlock, TADDR pMethodDescOrSlot); // Holder for remoting profiler notifications class ProfilerRemotingClientCallbackHolder { public: ProfilerRemotingClientCallbackHolder(); ~ProfilerRemotingClientCallbackHolder(); }; // These stub manager classes help the debugger to step // through the various stubs and thunks generated by the // remoting infrastructure class CVirtualThunkMgr :public StubManager { friend class CTPMethodTable; VPTR_VTABLE_CLASS(CVirtualThunkMgr, StubManager) public: static void InitVirtualThunkManager(); #ifndef DACCESS_COMPILE CVirtualThunkMgr() { WRAPPER_NO_CONTRACT; } #endif public: #ifdef _DEBUG virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "CVirtualThunkMgr"; } #endif virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress); virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) DAC_EMPTY_RET(FALSE); static MethodDesc *Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT); private: // Private methods LPBYTE FindThunk(const BYTE *stubStartAddress); static MethodDesc *GetMethodDescByASM(PCODE startaddr, MethodTable *pMT); static BOOL IsThunkByASM(PCODE startaddr); // Private statics static CVirtualThunkMgr *s_pVirtualThunkMgr; #ifdef DACCESS_COMPILE protected: virtual LPCWSTR GetStubManagerName(PCODE addr) { LIMITED_METHOD_CONTRACT; return W("CVirtualThunk"); } #endif }; #ifndef HAS_REMOTING_PRECODE class CNonVirtualThunkMgr :public StubManager { friend class CTPMethodTable; VPTR_VTABLE_CLASS(CNonVirtualThunkMgr, StubManager) public: static void InitNonVirtualThunkManager(); public: #ifdef _DEBUG virtual const char * DbgGetName() { return "CNonVirtualThunkMgr"; } #endif virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress); virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) DAC_EMPTY_RET(FALSE); virtual BOOL TraceManager(Thread *thread, TraceDestination *trace, CONTEXT *pContext, BYTE **pRetAddr) DAC_EMPTY_RET(FALSE); static MethodDesc *Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT); private: // Private methods CNonVirtualThunk* FindThunk(const BYTE *stubStartAddress); static MethodDesc *GetMethodDescByASM(PCODE startaddr); static BOOL IsThunkByASM(PCODE startaddr); // Private statics static CNonVirtualThunkMgr *s_pNonVirtualThunkMgr; #ifdef DACCESS_COMPILE protected: virtual LPCWSTR GetStubManagerName(PCODE addr) { LIMITED_METHOD_CONTRACT; return W("CNonVirtualThunk"); } #endif }; #endif // HAS_REMOTING_PRECODE #endif // __REMOTING_H__