//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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__