// ==++==
//
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
/******************************************************************************
Module Name:
codeman.h
Abstract:
Wrapper to facilitate multiple JITcompiler support in the COM+ Runtime
The ExecutionManager is responsible for managing the RangeSections.
Given an IP, it can find the RangeSection which holds that IP.
RangeSections contain the JITed codes. Each RangeSection knows the
IJitManager which created it.
An IJitManager knows about which method bodies live in each RangeSection.
It can handle methods of one given CodeType. It can map a method body to
a MethodDesc. It knows where the GCInfo about the method lives.
Today, we have 3 IJitManagers viz.
1. EEJitManager for JITcompiled code generated by mscorjit.dll
2. MNativeJitManager for ngenned code. We should be able to replace
this with EEJitManager
An ICodeManager knows how to crack a specific format of GCInfo. There is
a default format (handled by ExecutionManager::GetDefaultCodeManager())
which can be shared by different IJitManagers/IJitCompilers.
An ICorJitCompiler knows how to generate code for a method IL, and produce
GCInfo in a format which the corresponding IJitManager's ICodeManager
can handle.
ExecutionManager
|
+-----------+---------------+---------------+-----------+--- ...
| | | |
CodeType | CodeType |
| | | |
v v v v
+---------------+ +--------+<---- R +---------------+ +--------+<---- R
|ICorJitCompiler|<---->|IJitMan |<---- R |ICorJitCompiler|<---->|IJitMan |<---- R
+---------------+ +--------+<---- R +---------------+ +--------+<---- R
| x . | x .
| \ . | \ .
v \ . v \ .
+--------+ R +--------+ R
|ICodeMan| |ICodeMan| (RangeSections)
+--------+ +--------+
******************************************************************************/
#ifndef __CODEMAN_HPP__
#define __CODEMAN_HPP__
// this is the define the make ejitted code recognizable from regular jit even though they are
// both IL.
#define miManaged_IL_EJIT (miMaxMethodImplVal + 1)
#include "crst.h"
#include "eetwain.h"
#ifdef FJIT
#include "fjit_eetwain.h"
#endif
#include "ceeload.h"
#include "jitinterface.h"
#include "debuginfostore.h"
#include "shash.h"
class MethodDesc;
class ICorJitCompiler;
class IJitManager;
class EEJitManager;
class ExecutionManager;
class Thread;
class CrawlFrame;
class MethodEntryChunk;
class IDebugInfoStore;
struct JitDebugInfo;
struct EE_ILEXCEPTION;
struct EE_ILEXCEPTION_CLAUSE;
typedef unsigned EH_CLAUSE_ENUMERATOR;
inline DWORD MIN (DWORD a, DWORD b);
// Note PAGE_SIZE is 0x1000 (4096) on X86
// and 0x2000 (8192) on IA64
#define PAGE_MASK (PAGE_SIZE-1)
#define PAGE_ALIGN ~(PAGE_MASK)
#define ROUND_DOWN_TO_PAGE(x) ( (size_t) (x) & PAGE_ALIGN)
#define ROUND_UP_TO_PAGE(x) (((size_t) (x) + PAGE_MASK) & PAGE_ALIGN)
//-----------------------------------------------------------------------------
// Holds Jit (not ngen) debugging information manipulated by the EEJitManager.
typedef DPTR(struct JitDebugInfo) PTR_JitDebugInfo;
struct JitDebugInfo
{
void Init()
{
}
CompressDebugInfo::Boundaries m_bounds;
CompressDebugInfo::Vars m_vars;
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
};
//-----------------------------------------------------------------------------
// Method header which exists just before the code.
// Every IJitManager could have its own format for the header. However,
// everyone just used CodeHeader.
// MNativeJitManager use CORCOMPILE_METHOD_HEADER, however, that is a superset
// of CodeHeader, and we may eventually get rid of MNativeJitManager.
#ifdef USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader;
typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;
#else // USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpCodeHdr) PTR_CodeHeader;
#endif // USE_INDIRECT_CODEHEADER
#ifdef USE_INDIRECT_CODEHEADER
typedef struct _hpRealCodeHdr
#else // USE_INDIRECT_CODEHEADER
typedef struct _hpCodeHdr
#endif // USE_INDIRECT_CODEHEADER
{
public:
// On _Win64, this byte serves as padding to make
// the layout of CodeHeader match that used by the _WIN64 implementation of CORCOMPILE_METHOD_HEADER
PTR_JitDebugInfo phdrDebugInfo;
// Note - *(&(pCodeHeader->phdrJitEHInfo) - sizeof(size_t))
// contains the number of EH clauses, See EEJitManager::allocEHInfo
PTR_EE_ILEXCEPTION phdrJitEHInfo;
BYTE * phdrJitGCInfo;
// Also see CORCOMPILE_METHOD_HEADER for the layout of the NGEN code header
//
PTR_MethodDesc phdrMDesc;
public:
//
// Note: that the JITted code follows immediately after the MethodDesc*
//
#ifndef USE_INDIRECT_CODEHEADER
PTR_JitDebugInfo GetDebugInfo()
{
return phdrDebugInfo;
}
PTR_EE_ILEXCEPTION GetEHInfo()
{
return phdrJitEHInfo;
}
BYTE* GetGCInfo()
{
return phdrJitGCInfo;
}
PTR_MethodDesc GetMethodDesc()
{
return phdrMDesc;
}
BYTE* GetCodeStartAddress()
{
return ((BYTE*)PTR_HOST_TO_TADDR(this) + sizeof(CodeHeader));
// return (BYTE*)PTR_TO_TADDR(PTR_CodeHeader((CodeHeader*)this)) + sizeof(CodeHeader);
}
void SetRealCodeHeader(BYTE* pRCH)
{
// do nothing when we don't use an indirect header
return;
}
void SetDebugInfo(PTR_JitDebugInfo pDI)
{
phdrDebugInfo = pDI;
}
void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
{
phdrJitEHInfo = pEH;
}
void SetGCInfo(BYTE* pGC)
{
phdrJitGCInfo = pGC;
}
void SetMethodDesc(PTR_MethodDesc pMD)
{
phdrMDesc = pMD;
}
#endif // !USE_INDIRECT_CODEHEADER
// if we're using the indirect codeheaders then all enumeration is done by the code header
#ifndef USE_INDIRECT_CODEHEADER
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
#endif // DACCESS_COMPILE
#endif // USE_INDIRECT_CODEHEADER
#ifdef USE_INDIRECT_CODEHEADER
} RealCodeHeader;
#else // USE_INDIRECT_CODEHEADER
} CodeHeader;
#endif // USE_INDIRECT_CODEHEADER
#ifdef USE_INDIRECT_CODEHEADER
typedef struct _hpCodeHdr
{
PTR_RealCodeHeader pRealCodeHeader;
public:
PTR_JitDebugInfo GetDebugInfo()
{
return pRealCodeHeader->phdrDebugInfo;
}
PTR_EE_ILEXCEPTION GetEHInfo()
{
return pRealCodeHeader->phdrJitEHInfo;
}
BYTE* GetGCInfo()
{
return pRealCodeHeader->phdrJitGCInfo;
}
PTR_CodeHeader GetNextFuncletHeader()
{
return pRealCodeHeader->pNextFuncletHeader;
}
PTR_RUNTIME_FUNCTION GetUnwindInfo()
{
return pRealCodeHeader->pUnwindInfo;
}
PTR_MethodDesc GetMethodDesc()
{
return pRealCodeHeader->phdrMDesc;
}
BYTE* GetCodeStartAddress()
{
return ((BYTE*)PTR_HOST_TO_TADDR(this) + sizeof(CodeHeader));
}
PTR_CORCOMPILE_METHOD_COLD_HEADER GetColdHeader()
{
return pRealCodeHeader->pColdHeader;
}
void SetRealCodeHeader(BYTE* pRCH)
{
pRealCodeHeader = PTR_RealCodeHeader((RealCodeHeader*)pRCH);
}
void SetDebugInfo(PTR_JitDebugInfo pDI)
{
pRealCodeHeader->phdrDebugInfo = pDI;
}
void SetEHInfo(PTR_EE_ILEXCEPTION pEH)
{
pRealCodeHeader->phdrJitEHInfo = pEH;
}
void SetGCInfo(BYTE* pGC)
{
pRealCodeHeader->phdrJitGCInfo = pGC;
}
void SetNextFuncletHeader(PTR_CodeHeader pNext)
{
pRealCodeHeader->pNextFuncletHeader = pNext;
}
void SetUnwindInfo(PTR_RUNTIME_FUNCTION pUnwind)
{
pRealCodeHeader->pUnwindInfo = pUnwind;
}
void SetMethodDesc(PTR_MethodDesc pMD)
{
pRealCodeHeader->phdrMDesc = pMD;
}
void SetColdHeader(PTR_CORCOMPILE_METHOD_COLD_HEADER pColdHeader)
{
pRealCodeHeader->pColdHeader = pColdHeader;
}
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJitMan);
#endif // DACCESS_COMPILE
} CodeHeader;
#endif // USE_INDIRECT_CODEHEADER
//-----------------------------------------------------------------------------
// This is a structure used to consolidate the information that we
// need we creating new code heaps.
// When creating new JumpStubs we have a constarint that the address used
// should be in the range [loAddr..hiAddr]
//
struct CodeHeapRequestInfo
{
MethodDesc * m_pMD;
BaseDomain * m_pDomain;
const BYTE * m_loAddr; // lowest address to use to satisfy our request (0 -- don't care)
const BYTE * m_hiAddr; // hihest address to use to satisfy our request (0 -- don't care)
size_t m_requestSize; // minimum size that must be made available
size_t m_reserveSize; // Amount that VirtualAlloc will reserved
size_t m_cacheSize;
bool m_isDynamicDomain;
bool IsDynamicDomain() { return m_isDynamicDomain; }
size_t getRequestSize() { return m_requestSize; }
void setRequestSize(size_t requestSize) { m_requestSize = requestSize; }
size_t getReserveSize() { return m_reserveSize; }
void setReserveSize(size_t reserveSize) { m_reserveSize = reserveSize; }
size_t getCacheSize() { return m_cacheSize; }
void setCacheSize(size_t cacheSize) { m_cacheSize = cacheSize; }
void Init();
CodeHeapRequestInfo(MethodDesc *pMD)
: m_pMD(pMD), m_pDomain(0),
m_loAddr(0), m_hiAddr(0),
m_requestSize(0), m_reserveSize(0), m_cacheSize(0)
{ Init(); }
CodeHeapRequestInfo(MethodDesc *pMD, BaseDomain *pDomain, size_t requestSize,
BYTE * loAddr, BYTE * hiAddr)
: m_pMD(pMD), m_pDomain(pDomain),
m_loAddr(loAddr), m_hiAddr(hiAddr),
m_requestSize(requestSize), m_reserveSize(0), m_cacheSize(0)
{ Init(); }
};
//-----------------------------------------------------------------------------
//
// A CodeHeap is the abstraction the IJitManager uses to allocate memory
// needed to the jitting of a method.
// The CodeHeap works together with the HeapList to manage a contiguous block of memory.
// The CodeHeap is a non growable chunk of memory (it can be reserved and
// committed on demand).
//
// A CodeHeap is naturally protected from multiple threads by the code heap
// critical section - m_pCodeHeapCritSec - so if the implementation of the heap
// is only for the code manager, no locking needs to occur.
// It's important however that a delete operation on the CodeHeap (if any) happens
// via EEJitManager::ReleaseReferenceToHeap(CodeHeap*, MethodDesc*)
//
// The heap to be created depends on the MethodDesc that is being compiled.
// Standard code uses the LoaderCodeHeap, a heap based on the LoaderHeap.
// DynamicMethods - and only those - use a HostCodeHeap, a heap that does
// normal Alloc/Free so reclamation can be performed.
//
// The convention is that every heap implementation would have a static create
// function that returns a HeapList. The HeapList *must* be properly initialized
// on return except for the next pointer
//
typedef VPTR(class CodeHeap) PTR_CodeHeap;
class CodeHeap
{
VPTR_BASE_VTABLE_CLASS(CodeHeap)
public:
#ifdef DACCESS_COMPILE
CodeHeap() {}
#endif
// virtual dtor. Clean up heap
virtual ~CodeHeap() {}
// Alloc the specified numbers of bytes.
// There are only 2 flavors of Alloc that the CodeHeap cares about: a throw and a non-throw.
// We could combine them together and use a flag to call one or the other but the overall model
// appears to favor explicit naming convention.
virtual void* AllocMemory(size_t size, DWORD alignment) = 0;
virtual void* AllocMemory_NoThrow(size_t size, DWORD alignment) = 0;
// the inital address of the CodeHeap
virtual void* GetHeapStartAddress() = 0;
#ifdef _DEBUG
// for assert usage only. Return whatever internal data is used in the CodeHeap on return from Create.
// Typically this value minus the start address in the HeapList should return the heap start address
virtual size_t GetReservedPrivateData() = 0;
#endif
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0;
#endif
protected:
friend class EEJitManager;
// allows for reclamation of methods from the heap. Not every MethodDesc asks to be reclaimed
// and a heap is free to ignore the request.
// However for locking reasons is important this method is not called directly (hence protected)
// but always via the EEJitManager::ReleaseReferenceToHeap(CodeHeap*, MethodDesc*)
virtual void ReleaseReferenceToHeap(MethodDesc* pMD) = 0;
virtual void DestroyHeap() = 0;
};
//-----------------------------------------------------------------------------
// The HeapList works together with the CodeHeap to manage a contiguous block of memory.
//
// A single HeapList contains code only for a single AppDomain. EEJitManager uses
// EEJitManager::DomainCodeHeapList to keep a list of HeapLists for each AppDomain.
typedef DPTR(struct _HeapList) PTR_HeapList;
typedef struct _HeapList
{
PTR_HeapList hpNext;
PTR_CodeHeap pHeap;
TADDR startAddress;
TADDR endAddress; // the current end of the used portion of the Heap
// Counters which are incremented by writers.
// Readers can check that changeEnd before the read is the same as
// changeStart after the read to ensure that no writer was stomping
// on the heap while they were reading it
volatile PBYTE changeStart;
volatile PBYTE changeEnd;
TADDR mapBase; // "startAddress" rounded down to PAGE_SIZE. pHdrMap is relative to this address
PTR_DWORD pHdrMap; // bit array used to find the start of methods
size_t maxCodeHeapSize;// Size of the entire contiguous block of memory
DWORD cBlocks; // Number of allocations
DWORD /*volatile*/ bFull; // Heap is considered full do not use for new allocations
// We have a hashtable cache to map from an address to a HeapList
// This allows us to look up frequently used HeapLists faster.
PBYTE pCacheSpacePtr;
size_t bCacheSpaceSize;
PTR_HeapList GetVolatile_hpNext()
{ return hpNext; }
void SetVolatile_hpNext(PTR_HeapList next)
{ hpNext = next; }
void SetHeapFull()
{ *((volatile DWORD *) &bFull) = TRUE; }
bool IsHeapFull()
{ return (*((volatile DWORD *) &bFull) != 0); }
} HeapList;
//-----------------------------------------------------------------------------
// Implementation of the standard CodeHeap.
// Use the ExplicitControlLoaderHeap for allocations
// (Check the base class above - CodeHeap - for comments on the functions)
//
typedef VPTR(class LoaderCodeHeap) PTR_LoaderCodeHeap;
class LoaderCodeHeap : CodeHeap
{
#ifdef DACCESS_COMPILE
friend class ClrDataAccess;
#endif
VPTR_VTABLE_CLASS(LoaderCodeHeap, CodeHeap)
private:
PTR_ExplicitControlLoaderHeap pLoaderHeap;
LoaderCodeHeap(ExplicitControlLoaderHeap *pHeap)
{
LEAF_CONTRACT;
pLoaderHeap = PTR_ExplicitControlLoaderHeap(pHeap);
}
public:
static HeapList* CreateCodeHeap(CodeHeapRequestInfo *pInfo, LoaderHeap *pJitMetaHeap);
public:
virtual ~LoaderCodeHeap()
{
#ifndef DACCESS_COMPILE
WRAPPER_CONTRACT;
if (pLoaderHeap)
delete pLoaderHeap;
#endif
}
virtual void* AllocMemory(size_t size, DWORD alignment)
{
#ifndef DACCESS_COMPILE
WRAPPER_CONTRACT;
return (void*)pLoaderHeap->AllocAlignedmem(size, alignment, FALSE);
#else
return NULL;
#endif
}
virtual void* AllocMemory_NoThrow(size_t size, DWORD alignment)
{
#ifndef DACCESS_COMPILE
WRAPPER_CONTRACT;
return (void*)pLoaderHeap->AllocAlignedmem_NoThrow(size, alignment, FALSE);
#else
return NULL;
#endif
}
virtual void* GetHeapStartAddress()
{
WRAPPER_CONTRACT;
return pLoaderHeap->GetFirstBlockVirtualAddress();
}
#ifdef _DEBUG
virtual size_t GetReservedPrivateData()
{
LEAF_CONTRACT;
return sizeof(HeapList) + sizeof(LoaderHeapBlock);
}
#endif
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
WRAPPER_CONTRACT;
pLoaderHeap->EnumMemoryRegions(flags);
}
#endif
protected:
// the LoaderHeap does not allow for reclamation of methods
virtual void ReleaseReferenceToHeap(MethodDesc* pMD) {LEAF_CONTRACT;}
virtual void DestroyHeap() {LEAF_CONTRACT;}
};
//-----------------------------------------------------------------------------
// The ExecutionManager uses RangeSection ss the abstration of a contiguous
// address range to track the code heaps.
typedef DPTR(struct _rangesection) PTR_RangeSection;
typedef struct _rangesection
{
TADDR LowAddress;
TADDR HighAddress;
PTR_IJitManager pjit; // The owner of this address range
TADDR ptable;
PTR_RangeSection pnext; // link rangesections in a sorted list
PTR_RangeSection pLastUsed; // for the head node only: a link to rangesections that was used most recently
DWORD flags;
PTR_RangeSection pcold; // pointer to cold range section (only present in hot range sections)
PTR_Module pModule; // only valid for zapped images where a range section only contains code from one module
} RangeSection;
#define RANGE_SECTION_COLD 0x01
/*****************************************************************************/
#define FAILED_JIT 0x01
#define FAILED_EJIT 0x02
#define MIH_GC_OFFSET (offsetof(IMAGE_COR_MIH_ENTRY, MIHData) - offsetof(IMAGE_COR_MIH_ENTRY, Flags))
// METHODTOKEN == CORCOMPILE_METHOD_HEADER* for managed native code
// == CodeHeader* for EEJitManager
typedef struct _METHODTOKEN {
inline PTR_CodeHeader GetCodeHeader()
{
LEAF_CONTRACT;
return PTR_CodeHeader((CodeHeader*)this);
}
} *METHODTOKEN;
struct JumpStubBlockHeader;
//-----------------------------------------------------------------------------
//
// Manages the CodeHeap for some of the RangeSections in the ExecutionManager
//
//-----------------------------------------------------------------------------
class IJitManager
{
VPTR_BASE_VTABLE_CLASS(IJitManager)
public:
struct MethodRegionInfo
{
BYTE *hotStartAddress;
size_t hotSize;
BYTE *coldStartAddress;
size_t coldSize;
};
enum ScanFlag {ScanReaderLock, ScanNoReaderLock};
#ifndef DACCESS_COMPILE
IJitManager();
virtual ~IJitManager();
#endif // #ifndef DACCESS_COMPILE
// Get an DebugInfoStore, which lets us access jit information.
virtual void GetDebugInfoStore(IDebugInfoStore ** ppStore) = 0;
#ifndef DACCESS_COMPILE
// Used to populate the info store.
// The calls do not own the arrays passed in. It is expected that the implementations will compress
// the arrays, and thus not need the uncompressed copy that was passed in.
virtual void setVars(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars) = 0;
virtual void setBoundaries(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) = 0;
#endif
virtual void JitCodeToMethodInfo(
SLOT currentPC,
MethodDesc** ppMethodDesc,
METHODTOKEN* pMethodToken = NULL,
DWORD* pPCOffset = NULL,
ScanFlag scanFlag = ScanReaderLock) = 0;
virtual MethodDesc* JitTokenToMethodDesc(METHODTOKEN MethodToken)=0;
virtual BYTE* JitTokenToStartAddress(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock)=0;
virtual size_t JitTokenToMethodHotSize(METHODTOKEN MethodToken)=0;
virtual void JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo) = 0;
virtual unsigned InitializeEHEnumeration(METHODTOKEN MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)=0;
virtual EE_ILEXCEPTION_CLAUSE* GetNextEHClause(METHODTOKEN MethodToken,
EH_CLAUSE_ENUMERATOR* pEnumState,
EE_ILEXCEPTION_CLAUSE* pEHclause)=0;
#ifndef DACCESS_COMPILE
virtual TypeHandle ResolveEHClause(METHODTOKEN MethodToken,
EH_CLAUSE_ENUMERATOR* pEnumState,
EE_ILEXCEPTION_CLAUSE* pEHClauseOut,
CrawlFrame *pCf)=0;
#endif // #ifndef DACCESS_COMPILE
virtual void* GetGCInfo(METHODTOKEN MethodToken)=0;
#ifndef DACCESS_COMPILE
virtual void RemoveJitData(METHODTOKEN MethodToken, size_t GCinfo_len, size_t EHinfo_len)=0;
virtual void Unload(AppDomain *pDomain)=0; // for appdomain unloading
virtual BOOL LoadJIT(LPCWSTR szJITdll);
virtual void ResumeAtJitEH (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, Thread *pThread, BOOL unwindStack)=0;
virtual int CallJitEHFilter (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj)=0;
virtual void CallJitEHFinally(CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel)=0;
virtual CodeHeader* allocCode(MethodDesc* pFD, size_t blockSize, CorJitAllocMemFlag flag)=0;
#endif // #ifndef DACCESS_COMPILE
#ifndef DACCESS_COMPILE
virtual BYTE * allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize)=0;
virtual EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize)=0;
virtual JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps,
BYTE * loAddr, BYTE * hiAddr,
BaseDomain *pDomain)=0;
#endif // #ifndef DACCESS_COMPILE
#ifndef DACCESS_COMPILE
virtual BYTE* GetNativeEntry(BYTE* startAddress)=0;
#endif // #ifndef DACCESS_COMPILE
static ScanFlag GetScanFlags();
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
#ifndef DACCESS_COMPILE
void SetCodeManager(ICodeManager *codeMgr, BOOL bIsDefault)
{
LEAF_CONTRACT;
m_runtimeSupport = codeMgr;
m_IsDefaultCodeMan = bIsDefault;
return;
}
#endif
ICodeManager *GetCodeManager()
{
LEAF_CONTRACT;
return m_runtimeSupport;
}
void SetCodeType(DWORD type)
{
LEAF_CONTRACT;
m_CodeType = type;
return;
}
DWORD GetCodeType()
{
LEAF_CONTRACT;
return(m_CodeType);
}
BOOL IsJitForType(DWORD type)
{
LEAF_CONTRACT;
if (type == m_CodeType)
return TRUE;
else
return FALSE;
}
BOOL IsJitLoaded()
{
LEAF_CONTRACT;
return (m_jit != NULL);
}
VOID ClearCache()
{
if( m_jit != NULL )
{
m_jit->clearCache();
}
}
BOOL IsCacheCleanupRequired()
{
if( m_jit != NULL )
{
return m_jit->isCacheCleanupRequired();
}
return FALSE;
}
ICorJitCompiler * m_jit;
PTR_IJitManager m_next;
protected:
DWORD m_CodeType;
DWORD m_IsDefaultCodeMan;
PTR_ICodeManager m_runtimeSupport;
HINSTANCE m_JITCompiler;
};
//-----------------------------------------------------------------------------
struct JumpStubBlockHeader
{
JumpStubBlockHeader * m_next;
UINT32 m_used;
UINT32 m_allocated;
BaseDomain * m_domain;
UINT64 m_zero;
};
//-----------------------------------------------------------------------------
// Ideally, EEJitManager would just implement IDebugInfoStore directly, but DAC
// doesn't support multiple inheritence.
// The only thing in here is a VTable.
// This is conceptually an extension to EEJitManager
class EEJitDebugInfoStore : public IDebugInfoStore
{
public:
VPTR_VTABLE_CLASS(EEJitDebugInfoStore, IDebugInfoStore)
EEJitDebugInfoStore() { }
static CodeHeader * EEJitDebugInfoStore::GetCodeHeaderFromJitRequest(const DebugInfoRequest & request);
virtual HRESULT GetVars(
const DebugInfoRequest & request,
IN FP_IDS_NEW fpNew, IN void * pNewData,
OUT ULONG32 * pcVars,
OUT ICorDebugInfo::NativeVarInfo ** ppVars);
virtual HRESULT GetBoundaries(
const DebugInfoRequest & request,
IN FP_IDS_NEW fpNew, IN void * pNewData,
OUT ULONG32 * pcMap,
OUT ICorDebugInfo::OffsetMapping ** ppMap);
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD);
#endif
};
/*****************************************************************************/
#if defined (_MSC_VER) && _MSC_VER <= 1300
template void DoNothing(EEJitManager*);
template BOOL CompareDefault(EEJitManager*,EEJitManager*);
typedef DacHolder<EEJitManager *, DoNothing, DoNothing> HACKEEJitManagerLockHolder;
#endif
typedef VPTR(class EEJitManager) PTR_EEJitManager;
class EEJitManager :public IJitManager
{
#ifdef DACCESS_COMPILE
friend class ClrDataAccess;
#endif
friend class CheckDuplicatedStructLayouts;
friend class EEJitDebugInfoStore;
VPTR_VTABLE_CLASS(EEJitManager, IJitManager)
public:
#ifndef DACCESS_COMPILE
EEJitManager();
// No destructor necessary. Only one instance of this class that is destroyed at process shutdown.
// ~EEJitManager();
#endif // #ifndef DACCESS_COMPILE
// Used to get a reader interface for the stores.
virtual void GetDebugInfoStore(IDebugInfoStore ** ppStore);
#ifndef DACCESS_COMPILE
// Used to populate the info store.
virtual void setVars(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars);
virtual void setBoundaries(CodeHeader * pHeader, CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap);
#endif
virtual void JitCodeToMethodInfo(SLOT currentPC,
MethodDesc** ppMethodDesc,
METHODTOKEN* pMethodToken=NULL,
DWORD* pPCOffset=NULL,
ScanFlag scanFlag=ScanReaderLock);
virtual MethodDesc* JitTokenToMethodDesc(METHODTOKEN MethodToken);
static BYTE* JitTokenToStartAddressStatic(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock);
virtual BYTE* JitTokenToStartAddress(METHODTOKEN MethodToken, ScanFlag scanFlag=ScanReaderLock);
virtual size_t JitTokenToMethodHotSize(METHODTOKEN MethodToken);
virtual void JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo);
virtual unsigned InitializeEHEnumeration(METHODTOKEN MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState);
virtual EE_ILEXCEPTION_CLAUSE* GetNextEHClause(METHODTOKEN MethodToken,
EH_CLAUSE_ENUMERATOR* pEnumState,
EE_ILEXCEPTION_CLAUSE* pEHclause);
#ifndef DACCESS_COMPILE
virtual TypeHandle ResolveEHClause(METHODTOKEN MethodToken,
EH_CLAUSE_ENUMERATOR* pEnumState,
EE_ILEXCEPTION_CLAUSE* pEHClauseOut,
CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
void* GetGCInfo(METHODTOKEN MethodToken);
#ifndef DACCESS_COMPILE
virtual void RemoveJitData(METHODTOKEN MethodToken, size_t GCinfo_len, size_t EHinfo_len);
virtual void Unload(AppDomain *pDomain);
virtual void ResumeAtJitEH (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, Thread *pThread, BOOL unwindStack);
virtual int CallJitEHFilter (CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel, OBJECTREF thrownObj);
virtual void CallJitEHFinally(CrawlFrame* pCf, EE_ILEXCEPTION_CLAUSE *EHClausePtr, DWORD nestingLevel);
CodeHeader* allocCode(MethodDesc* pFD, size_t blockSize, CorJitAllocMemFlag flag);
void allocEntryChunk(MethodDescChunk *pMDChunk);
BYTE * allocGCInfo(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
EE_ILEXCEPTION* allocEHInfo(CodeHeader* pCodeHeader, unsigned numClauses, size_t * pAllocationSize);
JumpStubBlockHeader* allocJumpStubBlock(MethodDesc* pMD, DWORD numJumps,
BYTE * loAddr, BYTE * hiAddr,
BaseDomain *pDomain);
#endif // #ifndef DACCESS_COMPILE
inline virtual BOOL IsStub(const BYTE* address)
{ // This is needed by the debugger, this code manager does not produce stubs, so always return false
LEAF_CONTRACT;
return false;
}
inline virtual const BYTE* FollowStub(const BYTE* address)
{
LEAF_CONTRACT;
_ASSERTE(!"Should not be called");
return NULL;
}
#ifdef DACCESS_COMPILE
virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
// Heap Management functions
static void NibbleMapSet(DWORD *pMap, size_t delta, BOOL bSet = TRUE);
static size_t FindMethodCode(PTR_DWORD pMap, TADDR delta);
inline virtual BYTE* GetNativeEntry(BYTE* startAddress)
{
LEAF_CONTRACT;
return startAddress;
}
/* =========== NOT CURRENTLY USED =====================
void *NewNativeHeap(DWORD startAddr, DWORD length);
BOOL IsJITforCurrentIP(DWORD currentPC);
=========== NOT CURRENTLY USED ===================*/
#ifndef DACCESS_COMPILE
void ReleaseReferenceToHeap(CodeHeap *pCodeHeap, MethodDesc *pMD);
void ReleaseHeap(CodeHeap *pCodeHeap);
void DeleteCodeHeap(HeapList *pHeapList);
void RemoveCodeHeapFromDomainList(CodeHeap *pHeap, BaseDomain *pDomain);
#endif
private :
struct DomainCodeHeapList {
BaseDomain *m_pDomain;
CDynArray<HeapList *> m_CodeHeapList;
DomainCodeHeapList();
~DomainCodeHeapList();
};
#ifndef DACCESS_COMPILE
HeapList* NewCodeHeap(CodeHeapRequestInfo *pInfo, DomainCodeHeapList *pADHeapList);
HeapList* GetCodeHeap(CodeHeapRequestInfo *pInfo);
void* allocCodeRaw(CodeHeapRequestInfo *pInfo,
size_t blockSize, unsigned align,
HeapList ** ppCodeHeap /* Writeback, Can be null */ );
DomainCodeHeapList *GetCodeHeapList(MethodDesc *pMD, BaseDomain *pDomain);
LoaderHeap* GetJitMetaHeap(MethodDesc *pMD);
protected :
void * allocEHInfoRaw(CodeHeader* pCodeHeader, DWORD blockSize, size_t * pAllocationSize);
private :
#endif // #ifndef DACCESS_COMPILE
static CodeHeader * GetCodeHeaderFromAddr(TADDR startAddress)
{
LEAF_CONTRACT;
//return PTR_CodeHeader((PTR_HOST_TO_TADDR(startAddress) & ~3) - sizeof(CodeHeader));
return PTR_CodeHeader((startAddress & ~3) - sizeof(CodeHeader));
}
PTR_HeapList m_pCodeHeap;
PTR_HeapList GetVolatile_pCodeHeap()
{ return m_pCodeHeap; }
void SetVolatile_pCodeHeap(PTR_HeapList value)
{ m_pCodeHeap = value; }
protected :
CrstExplicitInit m_CodeHeapCritSec;
private :
EEJitDebugInfoStore m_DebugInfoStore;
// must hold critical section to access this structure.
CUnorderedArray<DomainCodeHeapList *, 5> m_DomainCodeHeaps;
CUnorderedArray<DomainCodeHeapList *, 5> m_DynamicDomainCodeHeaps;
// infrastructure to manage readers so we can lock them out and delete domain data
volatile LONG m_dwReaderCount;
volatile LONG m_dwWriterLock;
MethodDesc* JitCodeToMethodDescWrapper( SLOT currentPC,
METHODTOKEN* pMethodToken=NULL,
DWORD* pPCOffset=NULL
);
void AddRangeToJitHeapCache (TADDR startAddr, TADDR endAddr, HeapList* pHp);
void DeleteJitHeapCache (HeapList *pHeapList);
size_t GetCodeHeapCacheSize (size_t bAllocationRequest);
const static DWORD HASH_BUCKETS = 256;
const static size_t CACHE_BLOCK_SIZE = 0x00010000; // ( 64 KB )
const static size_t CACHE_BLOCK_MASK = CACHE_BLOCK_SIZE-1; // 0x0000ffff
const static size_t CACHE_BLOCK_ALIGN = ~CACHE_BLOCK_MASK; // 0xffff0000
const static size_t CACHE_INDEX_MASK = (HASH_BUCKETS-1) * CACHE_BLOCK_SIZE; // 0x00ff0000
const static DWORD CACHE_INDEX_RSHIFT = 16;
inline DWORD GET_CACHE_INDEX(size_t addr)
{ return ((DWORD)(addr & CACHE_INDEX_MASK)) >> CACHE_INDEX_RSHIFT; }
inline size_t COMPUTE_HASH_KEY(size_t addr)
{ return (addr & CACHE_BLOCK_ALIGN); }
typedef struct _HashEntry
{
size_t hashKey; // Key stored as COMPUTE_HASH_KEY(currentPC), hash is computed GET_CACHE_INDEX(hashKey)
PTR_HeapList pHp; // Value points to the HeapList's node
DPTR(struct _HashEntry) pNext;
} HashEntry;
typedef DPTR(HashEntry) PTR_HashEntry;
PTR_HashEntry m_JitCodeHashTable[HASH_BUCKETS];
HashEntry *m_pJitHeapCacheUnlinkedList;
#ifdef _DEBUG
BOOL DebugContainedInHeapList (HeapList *pHashEntryHp);
void DebugCheckJitHeapCacheValidity ();
#endif // _DEBUG
static void IncrementReader(EEJitManager *pMgr);
static void DecrementReader(EEJitManager *pMgr);
static void TakeWriter(EEJitManager *pMgr);
static void ReleaseWriter(EEJitManager *pMgr);
typedef DacHolder<EEJitManager *, EEJitManager::IncrementReader, EEJitManager::DecrementReader> ReaderLockHolder;
typedef DacHolder<EEJitManager *, EEJitManager::TakeWriter, EEJitManager::ReleaseWriter> WriterLockHolder;
};
//*****************************************************************************
//
// This class manages IJitManagers and ICorJitCompilers. It has only static
// members. It should never be constucted.
//
//*****************************************************************************
#if defined (_MSC_VER) && _MSC_VER <= 1300
template void DoNothing(ExecutionManager*);
template BOOL CompareDefault(ExecutionManager*,ExecutionManager*);
typedef DacHolder<ExecutionManager *, DoNothing, DoNothing> HACKExecutionManagerLockHolder;
#endif
class ExecutionManager
{
friend class CorExternalDataAccess;
#ifdef DACCESS_COMPILE
friend class ClrDataAccess;
#endif
friend bool decodeMethodEntryPoint(const BYTE* pBuffer, BYTE epSize, const BYTE** pTarget, SSIZE_T* pMDOffset, bool fHasLock);
static IJitManager* FindJitManNonZeroWrapper(SLOT currentPC);
static IJitManager* FindJitManNonZero(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock);
public :
static void Init();
// this gets called a lot for stackwalking, so inline the zero case
static IJitManager* FindJitMan(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
SO_TOLERANT;
} CONTRACTL_END;
return (currentPC ? FindJitManNonZero(currentPC, scanFlag) : NULL);
}
static IJitManager* FindJitManPCOnly(SLOT currentPC)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
SO_TOLERANT;
} CONTRACTL_END;
return (currentPC ? FindJitManNonZeroWrapper(currentPC) : NULL);
}
// Find a code manager from the current locations of the IP
static ICodeManager* FindCodeMan(SLOT currentPC, IJitManager::ScanFlag scanFlag=IJitManager::ScanReaderLock)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
SO_TOLERANT;
} CONTRACTL_END;
IJitManager * pJitMan = FindJitMan(currentPC, scanFlag);
return pJitMan != NULL ? pJitMan->GetCodeManager() : NULL;
}
// Use JitCodeToMethodOffset() to get the offset relative to the start of the method.
static DWORD JitCodeToOffset(TADDR currentPC);
static IJitManager* FindJitForType(DWORD Flags);
static void ClearCaches( void );
static BOOL IsCacheCleanupRequired();
static LPWSTR GetJitName();
static IJitManager* GetJitForType(DWORD Flags, bool dontLoadJit = false);
static void Unload(AppDomain *pDomain);
static BOOL PatchEntryPoint(BYTE* pBuffer, BYTE epSize,
BYTE* target, MethodDesc * methodDesc);
static void AddJitManager(IJitManager * newjitmgr);
static RangeSection * AddCodeRange(TADDR StartRange, TADDR EndRange,
IJitManager* pJit, TADDR Table,
DWORD flags=0,
RangeSection *pColdRangeSection=NULL,
Module* pModule=NULL);
static void DeleteCodeRange(TADDR StartRange);
static RangeSection * AddDataRange(TADDR StartRange, TADDR EndRange,
Module* pModule=NULL);
static void DeleteDataRange(TADDR StartRange);
static void ReleaseReferenceToHeap(EEJitManager *pJitManager, CodeHeap *pCodeHeap, MethodDesc *pMethod);
static void ReleaseHeap(EEJitManager *pJitManager, CodeHeap *pCodeHeap);
#ifndef FJITONLY
static ICodeManager* GetDefaultCodeManager()
{
LEAF_CONTRACT;
return (ICodeManager *)m_pDefaultCodeMan;
}
#endif
static Module* FindZapModule(TADDR currentData);
// NOTE: This will only work well for NGEN'd images
static Module* FindZapModuleForNativeCode(TADDR currentCode);
static RangeSection* GetRangeSection(RangeSection *pRS, TADDR addr);
static RangeSection* GetRangeSectionAndPrev(RangeSection *pRS, TADDR addr, RangeSection **ppPrev);
static RangeSection* GetRangeSectionForAddress(TADDR startAddress);
#ifdef DACCESS_COMPILE
static void EnumRangeList(RangeSection* list,
CLRDataEnumMemoryFlags flags);
static void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
#ifndef DACCESS_COMPILE
static void preallocatedJumpStubBlock(BYTE * mem, DWORD blockSize, BaseDomain *pDomain);
static void unlinkPreallocatedJumpStubBlock(BYTE * mem, DWORD blockSize, BaseDomain *pDomain);
static void deleteJumpStubBlock(HeapList *pHeapList);
static void deleteJumpStubBlockHelper(TADDR startAddr, TADDR endAddr);
static JumpStubBlockHeader * recoverJumpStubBlockHeader(BYTE * jumpStub);
static BYTE * jumpStub(MethodDesc* pMD,
BYTE * target,
BYTE * loAddr,
BYTE * hiAddr,
BaseDomain *pDomain = NULL);
#endif
private :
SPTR_DECL(RangeSection, m_CodeRangeList);
SPTR_DECL(RangeSection, m_DataRangeList);
SPTR_DECL(IJitManager, m_pJitList);
#ifndef FJITONLY
SPTR_DECL(EECodeManager, m_pDefaultCodeMan);
#endif
static CrstStatic m_ExecutionManagerCrst;
static CrstStatic m_JumpStubCrst;
static CrstStatic m_RangeCrst; // Aquire before writing into m_CodeRangeList and m_DataRangeList
static BYTE m_fFailedToLoad;
// infrastructure to manage readers so we can lock them out and delete domain data
// make ReaderCount volatile because we have order dependency in READER_INCREMENT
#ifndef DACCESS_COMPILE
static volatile LONG m_dwReaderCount;
static volatile LONG m_dwWriterLock;
#else
SVAL_DECL(LONG, m_dwReaderCount);
SVAL_DECL(LONG, m_dwWriterLock);
#endif
#ifdef DACCESS_COMPILE
static bool IsSafe(void)
{
return m_dwWriterLock == 0;
}
#endif
static void IncrementReader(ExecutionManager *pMgr);
static void DecrementReader(ExecutionManager *pMgr);
static void TakeWriter(ExecutionManager *pMgr);
static void ReleaseWriter(ExecutionManager *pMgr);
typedef DacHolder<ExecutionManager *, ExecutionManager::IncrementReader, ExecutionManager::DecrementReader, 0, NoNull<ExecutionManager *> > ReaderLockHolder;
typedef DacHolder<ExecutionManager *, ExecutionManager::TakeWriter, ExecutionManager::ReleaseWriter, 0, NoNull<ExecutionManager *> > WriterLockHolder;
static RangeSection * AddRangeHelper(RangeSection** ppRangeList,
TADDR StartRange,
TADDR EndRange,
IJitManager* pJit,
TADDR Table,
DWORD flags=0,
RangeSection *pColdRangeSection=NULL,
Module* pModule=NULL);
static void DeleteRangeHelper(RangeSection** ppRangeList,
TADDR StartRange);
#ifndef DACCESS_COMPILE
static BYTE * getNextJumpStub(MethodDesc* pMD,
IJitManager* pJitMan,
BYTE * target,
BYTE * loAddr, BYTE * hiAddr,
BaseDomain *pDomain);
#endif
private:
static JumpStubBlockHeader * m_jumpStubBlock;
// ***************************************************************************
// Hashtable for JumpStubs for jitted code
struct JumpStubEntry {
BYTE* m_target;
BYTE* m_jumpStub;
};
class JumpStubTraits : public DefaultSHashTraits<JumpStubEntry>
{
public:
typedef BYTE* key_t;
static key_t GetKey(element_t e)
{
LEAF_CONTRACT;
return e.m_target;
}
static BOOL Equals(key_t k1, key_t k2)
{
LEAF_CONTRACT;
return k1 == k2;
}
static count_t Hash(key_t k)
{
LEAF_CONTRACT;
return (count_t)(size_t)k;
}
static const element_t Null() { LEAF_CONTRACT; JumpStubEntry e; e.m_target = NULL; return e; }
static bool IsNull(const element_t &e) { LEAF_CONTRACT; return e.m_target == NULL; }
static const element_t Deleted() { LEAF_CONTRACT; JumpStubEntry e; e.m_target = (BYTE*)-1; return e; }
static bool IsDeleted(const element_t &e) { LEAF_CONTRACT; return e.m_target == (BYTE*)-1; }
};
typedef SHash<JumpStubTraits> JumpStubTable;
static JumpStubTable * m_jumpStubTable;
};
//-----------------------------------------------------------------------------
inline
/* static */ DWORD ExecutionManager::JitCodeToOffset(TADDR currentPC)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
DWORD offset;
IJitManager *pJitMan = FindJitMan((SLOT)currentPC);
_ASSERTE(pJitMan != NULL);
pJitMan->JitCodeToMethodInfo((SLOT)currentPC,
NULL,
NULL,
&offset
);
return offset;
}
//-----------------------------------------------------------------------------
// this is only called from a couple of places, but inlining helps EH perf
inline void* EEJitManager::GetGCInfo(METHODTOKEN MethodToken)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
CodeHeader* pHeader = MethodToken->GetCodeHeader();
return pHeader->GetGCInfo();
}
inline BYTE* EEJitManager::JitTokenToStartAddress(METHODTOKEN MethodToken, IJitManager::ScanFlag scanFlag)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
return JitTokenToStartAddressStatic(MethodToken, scanFlag);
}
inline BYTE* EEJitManager::JitTokenToStartAddressStatic(METHODTOKEN MethodToken, IJitManager::ScanFlag scanFlag)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
WIN64_ONLY(PRECONDITION(!MethodToken->IsFuncletMethodToken()));
} CONTRACTL_END;
if (MethodToken)
{
return MethodToken->GetCodeHeader()->GetCodeStartAddress();
}
return NULL;
}
inline size_t EEJitManager::JitTokenToMethodHotSize(METHODTOKEN MethodToken)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
return GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
}
inline void EEJitManager::JitTokenToMethodRegionInfo(METHODTOKEN MethodToken, MethodRegionInfo *methodRegionInfo)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
PRECONDITION(methodRegionInfo != NULL);
WIN64_ONLY(PRECONDITION(!MethodToken->IsFuncletMethodToken()));
} CONTRACTL_END;
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
methodRegionInfo->hotSize = JitTokenToMethodHotSize(MethodToken);
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
}
//-----------------------------------------------------------------------------
//*****************************************************************************
// Implementation of the ICodeInfo interface
class EECodeInfo : public ICodeInfo
{
public:
EECodeInfo(METHODTOKEN token, IJitManager * pJM);
EECodeInfo(METHODTOKEN token, IJitManager * pJM, MethodDesc * pMD);
const char* __stdcall getMethodName(const char **moduleName /* OUT */ );
void __stdcall getMethodSig(CORINFO_SIG_HANDLE *phsig, /* OUT */
DWORD *pcbSigSize,/* OUT */
CORINFO_MODULE_HANDLE *phscope); /* OUT */
virtual LPVOID __stdcall getStartAddress();
IJitManager* __stdcall getJitManager() { LEAF_CONTRACT; return m_pJM; };
bool __stdcall IsSynchronized();
bool __stdcall AcquiresInstMethodTableFromThis();
bool __stdcall RequiresInstArg();
METHODTOKEN m_methodToken;
MethodDesc *m_pMD;
IJitManager *m_pJM;
static inline CEEInfo* GetCEEInfo()
{ LEAF_CONTRACT; return (CEEInfo*)&s_ceeInfoMemory; }
static BYTE s_ceeInfoMemory[sizeof(CEEInfo)];
#ifndef DACCESS_COMPILE
static void Init();
#endif
};
#endif // !__CODEMAN_HPP__