mirror of
https://github.com/ZuneDev/dotnet-runtime.git
synced 2026-07-27 13:22:01 -07:00
Adds a JIT-EE API to report metadata back to the EE side about the JIT compilation, and adds support for saving these metrics as part of SPMI runs. Switches a number of adhoc metrics to use this scheme, and also adds a few new ones. The metadata is currently only reported with checked JITs. Also adds support for fast perfscore diffs, and adds perfscore into the reports generated by `superpmi.py asmdiffs`. Fix #52877
1167 lines
41 KiB
C
1167 lines
41 KiB
C
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
// ===========================================================================
|
|
// File: JITinterface.H
|
|
//
|
|
|
|
// ===========================================================================
|
|
|
|
|
|
#ifndef JITINTERFACE_H
|
|
#define JITINTERFACE_H
|
|
|
|
#include "corjit.h"
|
|
|
|
#ifndef TARGET_UNIX
|
|
#define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((32*1024)-1) // when generating JIT code
|
|
#else // !TARGET_UNIX
|
|
#define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((GetOsPageSize() / 2) - 1)
|
|
#endif // !TARGET_UNIX
|
|
#include "pgo.h"
|
|
|
|
enum StompWriteBarrierCompletionAction
|
|
{
|
|
SWB_PASS = 0x0,
|
|
SWB_ICACHE_FLUSH = 0x1,
|
|
SWB_EE_RESTART = 0x2
|
|
};
|
|
|
|
enum SignatureKind
|
|
{
|
|
SK_NOT_CALLSITE,
|
|
SK_CALLSITE,
|
|
SK_VIRTUAL_CALLSITE,
|
|
SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE,
|
|
};
|
|
|
|
class Stub;
|
|
class MethodDesc;
|
|
class NativeCodeVersion;
|
|
class FieldDesc;
|
|
enum RuntimeExceptionKind;
|
|
class AwareLock;
|
|
class PtrArray;
|
|
#if defined(FEATURE_GDBJIT)
|
|
class CalledMethod;
|
|
#endif
|
|
|
|
#include "genericdict.h"
|
|
|
|
inline FieldDesc* GetField(CORINFO_FIELD_HANDLE fieldHandle)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return (FieldDesc*) fieldHandle;
|
|
}
|
|
|
|
inline
|
|
bool SigInfoFlagsAreValid (CORINFO_SIG_INFO *sig)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return !(sig->flags & ~( CORINFO_SIGFLAG_IS_LOCAL_SIG
|
|
| CORINFO_SIGFLAG_IL_STUB
|
|
));
|
|
}
|
|
|
|
|
|
void InitJITHelpers1();
|
|
void InitJITHelpers2();
|
|
|
|
PCODE UnsafeJitFunction(PrepareCodeConfig* config,
|
|
COR_ILMETHOD_DECODER* header,
|
|
CORJIT_FLAGS* pJitFlags,
|
|
ULONG* pSizeOfCode);
|
|
|
|
void getMethodInfoILMethodHeaderHelper(
|
|
COR_ILMETHOD_DECODER* header,
|
|
CORINFO_METHOD_INFO* methInfo
|
|
);
|
|
|
|
|
|
BOOL LoadDynamicInfoEntry(Module *currentModule,
|
|
RVA fixupRva,
|
|
SIZE_T *entry,
|
|
BOOL mayUsePrecompiledNDirectMethods = TRUE);
|
|
|
|
//
|
|
// The legacy x86 monitor helpers do not need a state argument
|
|
//
|
|
#if !defined(TARGET_X86)
|
|
|
|
#define FCDECL_MONHELPER(funcname, arg) FCDECL2(void, funcname, arg, BYTE* pbLockTaken)
|
|
#define HCIMPL_MONHELPER(funcname, arg) HCIMPL2(void, funcname, arg, BYTE* pbLockTaken)
|
|
#define MONHELPER_STATE(x) x
|
|
#define MONHELPER_ARG pbLockTaken
|
|
|
|
#else
|
|
|
|
#define FCDECL_MONHELPER(funcname, arg) FCDECL1(void, funcname, arg)
|
|
#define HCIMPL_MONHELPER(funcname, arg) HCIMPL1(void, funcname, arg)
|
|
#define MONHELPER_STATE(x)
|
|
#define MONHELPER_ARG NULL
|
|
|
|
#endif // TARGET_X86
|
|
|
|
// thread local struct to store the "thread static blocks"
|
|
struct ThreadStaticBlockInfo
|
|
{
|
|
uint32_t NonGCMaxThreadStaticBlocks;
|
|
void** NonGCThreadStaticBlocks;
|
|
|
|
uint32_t GCMaxThreadStaticBlocks;
|
|
void** GCThreadStaticBlocks;
|
|
};
|
|
|
|
#ifdef _MSC_VER
|
|
EXTERN_C __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics;
|
|
EXTERN_C __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize;
|
|
EXTERN_C __declspec(thread) uint32_t t_GCThreadStaticBlocksSize;
|
|
#else
|
|
EXTERN_C __thread ThreadStaticBlockInfo t_ThreadStatics;
|
|
EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize;
|
|
EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize;
|
|
#endif // _MSC_VER
|
|
|
|
//
|
|
// JIT HELPER ALIASING FOR PORTABILITY.
|
|
//
|
|
// The portable helper is used if the platform does not provide optimized implementation.
|
|
//
|
|
|
|
#ifndef JIT_MonEnter
|
|
#define JIT_MonEnter JIT_MonEnter_Portable
|
|
#endif
|
|
EXTERN_C FCDECL1(void, JIT_MonEnter, Object *obj);
|
|
EXTERN_C FCDECL1(void, JIT_MonEnter_Portable, Object *obj);
|
|
|
|
#ifndef JIT_MonEnterWorker
|
|
#define JIT_MonEnterWorker JIT_MonEnterWorker_Portable
|
|
#endif
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonEnterWorker, Object *obj);
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonEnterWorker_Portable, Object *obj);
|
|
|
|
#ifndef JIT_MonReliableEnter
|
|
#define JIT_MonReliableEnter JIT_MonReliableEnter_Portable
|
|
#endif
|
|
EXTERN_C FCDECL2(void, JIT_MonReliableEnter, Object* obj, BYTE *tookLock);
|
|
EXTERN_C FCDECL2(void, JIT_MonReliableEnter_Portable, Object* obj, BYTE *tookLock);
|
|
|
|
#ifndef JIT_MonTryEnter
|
|
#define JIT_MonTryEnter JIT_MonTryEnter_Portable
|
|
#endif
|
|
EXTERN_C FCDECL3(void, JIT_MonTryEnter, Object *obj, INT32 timeout, BYTE* pbLockTaken);
|
|
EXTERN_C FCDECL3(void, JIT_MonTryEnter_Portable, Object *obj, INT32 timeout, BYTE* pbLockTaken);
|
|
|
|
#ifndef JIT_MonExit
|
|
#define JIT_MonExit JIT_MonExit_Portable
|
|
#endif
|
|
EXTERN_C FCDECL1(void, JIT_MonExit, Object *obj);
|
|
EXTERN_C FCDECL1(void, JIT_MonExit_Portable, Object *obj);
|
|
|
|
#ifndef JIT_MonExitWorker
|
|
#define JIT_MonExitWorker JIT_MonExitWorker_Portable
|
|
#endif
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonExitWorker, Object *obj);
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonExitWorker_Portable, Object *obj);
|
|
|
|
#ifndef JIT_MonEnterStatic
|
|
#define JIT_MonEnterStatic JIT_MonEnterStatic_Portable
|
|
#endif
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonEnterStatic, AwareLock *lock);
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonEnterStatic_Portable, AwareLock *lock);
|
|
|
|
#ifndef JIT_MonExitStatic
|
|
#define JIT_MonExitStatic JIT_MonExitStatic_Portable
|
|
#endif
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic, AwareLock *lock);
|
|
EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic_Portable, AwareLock *lock);
|
|
|
|
|
|
#ifndef JIT_GetSharedGCStaticBase
|
|
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_Portable
|
|
#endif
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
|
|
|
|
#ifndef JIT_GetSharedNonGCStaticBase
|
|
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_Portable
|
|
#endif
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
|
|
|
|
#ifndef JIT_GetSharedGCStaticBaseNoCtor
|
|
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_Portable
|
|
#endif
|
|
EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor, DomainLocalModule *pLocalModule);
|
|
EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule);
|
|
|
|
#ifndef JIT_GetSharedNonGCStaticBaseNoCtor
|
|
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_Portable
|
|
#endif
|
|
EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor, DomainLocalModule *pLocalModule);
|
|
EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule);
|
|
|
|
extern FCDECL1(Object*, JIT_NewS_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_);
|
|
extern FCDECL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_);
|
|
|
|
extern FCDECL1(StringObject*, AllocateString_MP_FastPortable, DWORD stringLength);
|
|
extern FCDECL1(StringObject*, UnframedAllocateString, DWORD stringLength);
|
|
extern FCDECL1(StringObject*, FramedAllocateString, DWORD stringLength);
|
|
|
|
extern FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
|
|
extern FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
|
|
extern FCDECL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
|
|
|
|
EXTERN_C FCDECL_MONHELPER(JITutil_MonEnterWorker, Object* obj);
|
|
EXTERN_C FCDECL2(void, JITutil_MonReliableEnter, Object* obj, BYTE* pbLockTaken);
|
|
EXTERN_C FCDECL3(void, JITutil_MonTryEnter, Object* obj, INT32 timeOut, BYTE* pbLockTaken);
|
|
EXTERN_C FCDECL_MONHELPER(JITutil_MonExitWorker, Object* obj);
|
|
EXTERN_C FCDECL_MONHELPER(JITutil_MonSignal, AwareLock* lock);
|
|
EXTERN_C FCDECL_MONHELPER(JITutil_MonContention, AwareLock* awarelock);
|
|
EXTERN_C FCDECL2(void, JITutil_MonReliableContention, AwareLock* awarelock, BYTE* pbLockTaken);
|
|
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID);
|
|
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID);
|
|
|
|
EXTERN_C void DoJITFailFast ();
|
|
EXTERN_C FCDECL0(void, JIT_FailFast);
|
|
|
|
FCDECL0(int, JIT_GetCurrentManagedThreadId);
|
|
|
|
#if !defined(FEATURE_USE_ASM_GC_WRITE_BARRIERS) && defined(FEATURE_COUNT_GC_WRITE_BARRIERS)
|
|
// Extra argument for the classification of the checked barriers.
|
|
extern "C" FCDECL3(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref, CheckedWriteBarrierKinds kind);
|
|
#else
|
|
// Regular checked write barrier.
|
|
extern "C" FCDECL2(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref);
|
|
#endif
|
|
|
|
extern "C" FCDECL2(VOID, JIT_WriteBarrier, Object **dst, Object *ref);
|
|
extern "C" FCDECL2(VOID, JIT_WriteBarrierEnsureNonHeapTarget, Object **dst, Object *ref);
|
|
|
|
extern "C" FCDECL2(Object*, ChkCastAny_NoCacheLookup, CORINFO_CLASS_HANDLE type, Object* obj);
|
|
extern "C" FCDECL2(Object*, IsInstanceOfAny_NoCacheLookup, CORINFO_CLASS_HANDLE type, Object* obj);
|
|
extern "C" FCDECL2(LPVOID, Unbox_Helper, CORINFO_CLASS_HANDLE type, Object* obj);
|
|
extern "C" FCDECL3(void, JIT_Unbox_Nullable, void * destPtr, CORINFO_CLASS_HANDLE type, Object* obj);
|
|
|
|
// ARM64 JIT_WriteBarrier uses speciall ABI and thus is not callable directly
|
|
// Copied write barriers must be called at a different location
|
|
extern "C" FCDECL2(VOID, JIT_WriteBarrier_Callable, Object **dst, Object *ref);
|
|
#define WriteBarrier_Helper JIT_WriteBarrier_Callable
|
|
|
|
extern "C" FCDECL1(void, JIT_InternalThrow, unsigned exceptNum);
|
|
extern "C" FCDECL1(void*, JIT_InternalThrowFromHelper, unsigned exceptNum);
|
|
|
|
#ifdef TARGET_AMD64
|
|
|
|
|
|
class WriteBarrierManager
|
|
{
|
|
public:
|
|
enum WriteBarrierType
|
|
{
|
|
WRITE_BARRIER_UNINITIALIZED,
|
|
WRITE_BARRIER_PREGROW64,
|
|
WRITE_BARRIER_POSTGROW64,
|
|
#ifdef FEATURE_SVR_GC
|
|
WRITE_BARRIER_SVR64,
|
|
#endif // FEATURE_SVR_GC
|
|
WRITE_BARRIER_BYTE_REGIONS64,
|
|
WRITE_BARRIER_BIT_REGIONS64,
|
|
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
|
|
WRITE_BARRIER_WRITE_WATCH_PREGROW64,
|
|
WRITE_BARRIER_WRITE_WATCH_POSTGROW64,
|
|
#ifdef FEATURE_SVR_GC
|
|
WRITE_BARRIER_WRITE_WATCH_SVR64,
|
|
#endif // FEATURE_SVR_GC
|
|
WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64,
|
|
WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64,
|
|
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
|
|
WRITE_BARRIER_BUFFER
|
|
};
|
|
|
|
WriteBarrierManager();
|
|
void Initialize();
|
|
|
|
int UpdateEphemeralBounds(bool isRuntimeSuspended);
|
|
int UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck);
|
|
|
|
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
|
|
int SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
|
|
int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
|
|
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
|
|
size_t GetCurrentWriteBarrierSize();
|
|
|
|
protected:
|
|
size_t GetSpecificWriteBarrierSize(WriteBarrierType writeBarrier);
|
|
PBYTE CalculatePatchLocation(LPVOID base, LPVOID label, int offset);
|
|
PCODE GetCurrentWriteBarrierCode();
|
|
int ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended);
|
|
bool NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, bool bUseBitwiseWriteBarrier, WriteBarrierType* pNewWriteBarrierType);
|
|
|
|
private:
|
|
void Validate();
|
|
|
|
WriteBarrierType m_currentWriteBarrier;
|
|
|
|
PBYTE m_pWriteWatchTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION
|
|
PBYTE m_pLowerBoundImmediate; // PREGROW | POSTGROW | | WRITE_WATCH | REGION
|
|
PBYTE m_pCardTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION
|
|
PBYTE m_pCardBundleTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION
|
|
PBYTE m_pUpperBoundImmediate; // | POSTGROW | | WRITE_WATCH | REGION
|
|
PBYTE m_pRegionToGenTableImmediate; // | | | WRITE_WATCH | REGION
|
|
PBYTE m_pRegionShrDest; // | | | WRITE_WATCH | REGION
|
|
PBYTE m_pRegionShrSrc; // | | | WRITE_WATCH | RETION
|
|
};
|
|
|
|
#endif // TARGET_AMD64
|
|
|
|
#ifdef HOST_64BIT
|
|
EXTERN_C FCDECL1(Object*, JIT_TrialAllocSFastMP_InlineGetThread, CORINFO_CLASS_HANDLE typeHnd_);
|
|
EXTERN_C FCDECL2(Object*, JIT_BoxFastMP_InlineGetThread, CORINFO_CLASS_HANDLE type, void* data);
|
|
EXTERN_C FCDECL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
|
|
EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
|
|
|
|
#endif // HOST_64BIT
|
|
|
|
EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2);
|
|
|
|
EXTERN_C FCDECL1_V(INT64, JIT_Dbl2Lng, double val);
|
|
EXTERN_C FCDECL1_V(INT64, JIT_Dbl2IntSSE2, double val);
|
|
EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngP4x87, double val);
|
|
EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngSSE3, double val);
|
|
EXTERN_C FCDECL1_V(INT64, JIT_Dbl2LngOvf, double val);
|
|
|
|
EXTERN_C FCDECL1_V(INT32, JIT_Dbl2IntOvf, double val);
|
|
|
|
EXTERN_C FCDECL2_VV(float, JIT_FltRem, float dividend, float divisor);
|
|
EXTERN_C FCDECL2_VV(double, JIT_DblRem, double dividend, double divisor);
|
|
|
|
#ifndef HOST_64BIT
|
|
#ifdef TARGET_X86
|
|
// JIThelp.asm
|
|
EXTERN_C void STDCALL JIT_LLsh();
|
|
EXTERN_C void STDCALL JIT_LRsh();
|
|
EXTERN_C void STDCALL JIT_LRsz();
|
|
#else // TARGET_X86
|
|
EXTERN_C FCDECL2_VV(UINT64, JIT_LLsh, UINT64 num, int shift);
|
|
EXTERN_C FCDECL2_VV(INT64, JIT_LRsh, INT64 num, int shift);
|
|
EXTERN_C FCDECL2_VV(UINT64, JIT_LRsz, UINT64 num, int shift);
|
|
#endif // !TARGET_X86
|
|
#endif // !HOST_64BIT
|
|
|
|
#ifdef TARGET_X86
|
|
|
|
#define ENUM_X86_WRITE_BARRIER_REGISTERS() \
|
|
X86_WRITE_BARRIER_REGISTER(EAX) \
|
|
X86_WRITE_BARRIER_REGISTER(ECX) \
|
|
X86_WRITE_BARRIER_REGISTER(EBX) \
|
|
X86_WRITE_BARRIER_REGISTER(ESI) \
|
|
X86_WRITE_BARRIER_REGISTER(EDI) \
|
|
X86_WRITE_BARRIER_REGISTER(EBP)
|
|
|
|
extern "C"
|
|
{
|
|
|
|
// JIThelp.asm/JIThelp.s
|
|
#define X86_WRITE_BARRIER_REGISTER(reg) \
|
|
void STDCALL JIT_CheckedWriteBarrier##reg(); \
|
|
void STDCALL JIT_DebugWriteBarrier##reg(); \
|
|
void STDCALL JIT_WriteBarrier##reg();
|
|
|
|
ENUM_X86_WRITE_BARRIER_REGISTERS()
|
|
#undef X86_WRITE_BARRIER_REGISTER
|
|
|
|
void STDCALL JIT_WriteBarrierGroup();
|
|
void STDCALL JIT_WriteBarrierGroup_End();
|
|
|
|
void STDCALL JIT_PatchedWriteBarrierGroup();
|
|
void STDCALL JIT_PatchedWriteBarrierGroup_End();
|
|
}
|
|
|
|
void ValidateWriteBarrierHelpers();
|
|
|
|
#endif //TARGET_X86
|
|
|
|
extern "C"
|
|
{
|
|
#ifndef FEATURE_EH_FUNCLETS
|
|
void STDCALL JIT_EndCatch(); // JIThelp.asm/JIThelp.s
|
|
#endif // TARGET_X86
|
|
|
|
void STDCALL JIT_ByRefWriteBarrier(); // JIThelp.asm/JIThelp.s
|
|
|
|
#if defined(TARGET_AMD64) || defined(TARGET_ARM)
|
|
|
|
FCDECL2VA(void, JIT_TailCall, PCODE copyArgs, PCODE target);
|
|
|
|
#else // TARGET_AMD64 || TARGET_ARM
|
|
|
|
void STDCALL JIT_TailCall(); // JIThelp.asm
|
|
|
|
#endif // TARGET_AMD64 || TARGET_ARM
|
|
|
|
void STDCALL JIT_MemSet(void *dest, int c, SIZE_T count);
|
|
void STDCALL JIT_MemCpy(void *dest, const void *src, SIZE_T count);
|
|
|
|
void STDMETHODCALLTYPE JIT_ProfilerEnterLeaveTailcallStub(UINT_PTR ProfilerHandle);
|
|
#if !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
|
|
void STDCALL JIT_StackProbe();
|
|
#endif // TARGET_ARM64
|
|
};
|
|
|
|
/*********************************************************************/
|
|
/*********************************************************************/
|
|
|
|
// Transient data for a MethodDesc involved
|
|
// in the current JIT compilation.
|
|
struct TransientMethodDetails final
|
|
{
|
|
MethodDesc* Method;
|
|
COR_ILMETHOD_DECODER* Header;
|
|
CORINFO_MODULE_HANDLE Scope;
|
|
|
|
TransientMethodDetails() = default;
|
|
TransientMethodDetails(MethodDesc* pMD, _In_opt_ COR_ILMETHOD_DECODER* header, CORINFO_MODULE_HANDLE scope);
|
|
TransientMethodDetails(const TransientMethodDetails&) = delete;
|
|
TransientMethodDetails(TransientMethodDetails&&);
|
|
~TransientMethodDetails();
|
|
|
|
TransientMethodDetails& operator=(const TransientMethodDetails&) = delete;
|
|
TransientMethodDetails& operator=(TransientMethodDetails&&);
|
|
};
|
|
|
|
class CEEInfo : public ICorJitInfo
|
|
{
|
|
friend class CEEDynamicCodeInfo;
|
|
|
|
void GetTypeContext(const CORINFO_SIG_INST* info, SigTypeContext* pTypeContext);
|
|
MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context);
|
|
TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context);
|
|
void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext* pTypeContext);
|
|
|
|
void HandleException(struct _EXCEPTION_POINTERS* pExceptionPointers);
|
|
public:
|
|
#include "icorjitinfoimpl_generated.h"
|
|
uint32_t getClassAttribsInternal (CORINFO_CLASS_HANDLE cls);
|
|
bool isObjectImmutableInteral(OBJECTREF obj);
|
|
|
|
static unsigned getClassAlignmentRequirementStatic(TypeHandle clsHnd);
|
|
|
|
static unsigned getClassGClayoutStatic(TypeHandle th, BYTE* gcPtrs);
|
|
static CorInfoHelpFunc getNewHelperStatic(MethodTable * pMT, bool * pHasSideEffects);
|
|
static CorInfoHelpFunc getNewArrHelperStatic(TypeHandle clsHnd);
|
|
static CorInfoHelpFunc getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing);
|
|
|
|
// Returns that compilation flags that are shared between JIT and NGen
|
|
static CORJIT_FLAGS GetBaseCompileFlags(MethodDesc * ftn);
|
|
|
|
static CorInfoHelpFunc getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT);
|
|
|
|
static size_t findNameOfToken (Module* module, mdToken metaTOK,
|
|
_Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity);
|
|
|
|
DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd);
|
|
|
|
bool resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info);
|
|
|
|
CORINFO_CLASS_HANDLE getDefaultComparerClassHelper(
|
|
CORINFO_CLASS_HANDLE elemType
|
|
);
|
|
|
|
CORINFO_CLASS_HANDLE getDefaultEqualityComparerClassHelper(
|
|
CORINFO_CLASS_HANDLE elemType
|
|
);
|
|
|
|
CorInfoType getFieldTypeInternal (CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType = NULL,CORINFO_CLASS_HANDLE owner = NULL);
|
|
|
|
protected:
|
|
void freeArrayInternal(void* array);
|
|
|
|
public:
|
|
|
|
bool getTailCallHelpersInternal(
|
|
CORINFO_RESOLVED_TOKEN* callToken,
|
|
CORINFO_SIG_INFO* sig,
|
|
CORINFO_GET_TAILCALL_HELPERS_FLAGS flags,
|
|
CORINFO_TAILCALL_HELPERS* pResult);
|
|
|
|
bool getStaticObjRefContent(OBJECTREF obj, uint8_t* buffer, bool ignoreMovableObjects);
|
|
|
|
// This normalizes EE type information into the form expected by the JIT.
|
|
//
|
|
// If typeHnd contains exact type information, then *clsRet will contain
|
|
// the normalized CORINFO_CLASS_HANDLE information on return.
|
|
static CorInfoType asCorInfoType (CorElementType cet,
|
|
TypeHandle typeHnd = TypeHandle() /* optional in */,
|
|
CORINFO_CLASS_HANDLE *clsRet = NULL /* optional out */ );
|
|
|
|
CEEInfo(MethodDesc * fd = NULL, bool fAllowInlining = true) :
|
|
m_pJitHandles(nullptr),
|
|
m_pMethodBeingCompiled(fd),
|
|
m_transientDetails(NULL),
|
|
m_pThread(GetThreadNULLOk()),
|
|
m_hMethodForSecurity_Key(NULL),
|
|
m_pMethodForSecurity_Value(NULL),
|
|
#if defined(FEATURE_GDBJIT)
|
|
m_pCalledMethods(NULL),
|
|
#endif
|
|
m_allowInlining(fAllowInlining)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
}
|
|
|
|
virtual ~CEEInfo()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
|
|
#if !defined(DACCESS_COMPILE)
|
|
// Free all handles used by JIT
|
|
if (m_pJitHandles != nullptr)
|
|
{
|
|
OBJECTHANDLE* elements = m_pJitHandles->GetElements();
|
|
unsigned count = m_pJitHandles->GetCount();
|
|
for (unsigned i = 0; i < count; i++)
|
|
{
|
|
DestroyHandle(elements[i]);
|
|
}
|
|
delete m_pJitHandles;
|
|
}
|
|
|
|
delete m_transientDetails;
|
|
#endif
|
|
}
|
|
|
|
// Performs any work JIT-related work that should be performed at process shutdown.
|
|
void JitProcessShutdownWork();
|
|
|
|
void setJitFlags(const CORJIT_FLAGS& jitFlags);
|
|
|
|
private:
|
|
// Shrinking these buffers drastically reduces the amount of stack space
|
|
// required for each instance of the interpreter, and thereby reduces SOs.
|
|
#ifdef FEATURE_INTERPRETER
|
|
#define CLS_STRING_SIZE 8 // force heap allocation
|
|
#define CLS_BUFFER_SIZE SBUFFER_PADDED_SIZE(8)
|
|
#else
|
|
#define CLS_STRING_SIZE MAX_CLASSNAME_LENGTH
|
|
#define CLS_BUFFER_SIZE MAX_CLASSNAME_LENGTH
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
InlineSString<MAX_CLASSNAME_LENGTH> ssClsNameBuff;
|
|
InlineSString<MAX_CLASSNAME_LENGTH> ssClsNameBuffUTF8;
|
|
#endif
|
|
|
|
public:
|
|
MethodDesc * GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle);
|
|
|
|
// Prepare the information about how to do a runtime lookup of the handle with shared
|
|
// generic variables.
|
|
void ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
|
|
CORINFO_RESOLVED_TOKEN * pResolvedToken,
|
|
CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */,
|
|
MethodDesc * pTemplateMD /* for method-based slots */,
|
|
CORINFO_LOOKUP *pResultLookup);
|
|
|
|
#if defined(FEATURE_GDBJIT)
|
|
CalledMethod * GetCalledMethods() { return m_pCalledMethods; }
|
|
#endif
|
|
|
|
// Add/Remove/Find transient method details.
|
|
void AddTransientMethodDetails(TransientMethodDetails details);
|
|
TransientMethodDetails RemoveTransientMethodDetails(MethodDesc* pMD);
|
|
bool FindTransientMethodDetails(MethodDesc* pMD, TransientMethodDetails** details);
|
|
|
|
protected:
|
|
SArray<OBJECTHANDLE>* m_pJitHandles; // GC handles used by JIT
|
|
MethodDesc* m_pMethodBeingCompiled; // Top-level method being compiled
|
|
SArray<TransientMethodDetails, FALSE>* m_transientDetails; // Transient details for dynamic codegen scenarios.
|
|
Thread * m_pThread; // Cached current thread for faster JIT-EE transitions
|
|
CORJIT_FLAGS m_jitFlags;
|
|
|
|
CORINFO_METHOD_HANDLE getMethodBeingCompiled()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return (CORINFO_METHOD_HANDLE)m_pMethodBeingCompiled;
|
|
}
|
|
|
|
CORINFO_OBJECT_HANDLE getJitHandleForObject(OBJECTREF objref, bool knownFrozen = false);
|
|
OBJECTREF getObjectFromJitHandle(CORINFO_OBJECT_HANDLE handle);
|
|
|
|
// Cache of last GetMethodForSecurity() lookup
|
|
CORINFO_METHOD_HANDLE m_hMethodForSecurity_Key;
|
|
MethodDesc * m_pMethodForSecurity_Value;
|
|
|
|
#if defined(FEATURE_GDBJIT)
|
|
CalledMethod * m_pCalledMethods;
|
|
#endif
|
|
|
|
bool m_allowInlining;
|
|
|
|
void EnsureActive(TypeHandle th, MethodDesc * pMD = NULL);
|
|
};
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
class EEJitManager;
|
|
struct HeapList;
|
|
struct _hpCodeHdr;
|
|
typedef struct _hpCodeHdr CodeHeader;
|
|
|
|
// CEEJitInfo is the concrete implementation of callbacks that the EE must provide for the JIT to do its
|
|
// work. See code:ICorJitInfo#JitToEEInterface for more on this interface.
|
|
class CEEJitInfo : public CEEInfo
|
|
{
|
|
public:
|
|
// ICorJitInfo stuff
|
|
|
|
void allocMem (AllocMemArgs *pArgs) override final;
|
|
|
|
void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize) override final;
|
|
|
|
void allocUnwindInfo (
|
|
uint8_t * pHotCode, /* IN */
|
|
uint8_t * pColdCode, /* IN */
|
|
uint32_t startOffset, /* IN */
|
|
uint32_t endOffset, /* IN */
|
|
uint32_t unwindSize, /* IN */
|
|
uint8_t * pUnwindBlock, /* IN */
|
|
CorJitFuncKind funcKind /* IN */
|
|
) override final;
|
|
|
|
void * allocGCInfo (size_t size) override final;
|
|
|
|
void setEHcount (unsigned cEH) override final;
|
|
|
|
void setEHinfo (
|
|
unsigned EHnumber,
|
|
const CORINFO_EH_CLAUSE* clause) override final;
|
|
|
|
void getEHinfo(
|
|
CORINFO_METHOD_HANDLE ftn, /* IN */
|
|
unsigned EHnumber, /* IN */
|
|
CORINFO_EH_CLAUSE* clause /* OUT */
|
|
) override final;
|
|
|
|
HRESULT allocPgoInstrumentationBySchema(
|
|
CORINFO_METHOD_HANDLE ftnHnd, /* IN */
|
|
PgoInstrumentationSchema* pSchema, /* IN/OUT */
|
|
uint32_t countSchemaItems, /* IN */
|
|
uint8_t** pInstrumentationData /* OUT */
|
|
) override final;
|
|
|
|
HRESULT getPgoInstrumentationResults(
|
|
CORINFO_METHOD_HANDLE ftnHnd, /* IN */
|
|
PgoInstrumentationSchema** pSchema, /* OUT */
|
|
uint32_t* pCountSchemaItems, /* OUT */
|
|
uint8_t**pInstrumentationData, /* OUT */
|
|
PgoSource *pPgoSource /* OUT */
|
|
) override final;
|
|
|
|
void recordCallSite(
|
|
uint32_t instrOffset, /* IN */
|
|
CORINFO_SIG_INFO * callSig, /* IN */
|
|
CORINFO_METHOD_HANDLE methodHandle /* IN */
|
|
) override final;
|
|
|
|
void recordRelocation(
|
|
void *location,
|
|
void *locationRW,
|
|
void *target,
|
|
uint16_t fRelocType,
|
|
int32_t addlDelta) override final;
|
|
|
|
uint16_t getRelocTypeHint(void * target) override final;
|
|
|
|
uint32_t getExpectedTargetArchitecture() override final;
|
|
|
|
void ResetForJitRetry()
|
|
{
|
|
CONTRACTL {
|
|
NOTHROW;
|
|
GC_NOTRIGGER;
|
|
} CONTRACTL_END;
|
|
|
|
if (m_CodeHeaderRW != m_CodeHeader)
|
|
freeArrayInternal(m_CodeHeaderRW);
|
|
|
|
m_CodeHeader = NULL;
|
|
m_CodeHeaderRW = NULL;
|
|
|
|
m_codeWriteBufferSize = 0;
|
|
#ifdef USE_INDIRECT_CODEHEADER
|
|
m_pRealCodeHeader = NULL;
|
|
#endif
|
|
m_pCodeHeap = NULL;
|
|
|
|
if (m_pOffsetMapping != NULL)
|
|
freeArrayInternal(m_pOffsetMapping);
|
|
|
|
if (m_pNativeVarInfo != NULL)
|
|
freeArrayInternal(m_pNativeVarInfo);
|
|
|
|
m_iOffsetMapping = 0;
|
|
m_pOffsetMapping = NULL;
|
|
m_iNativeVarInfo = 0;
|
|
m_pNativeVarInfo = NULL;
|
|
|
|
if (m_inlineTreeNodes != NULL)
|
|
freeArrayInternal(m_inlineTreeNodes);
|
|
if (m_richOffsetMappings != NULL)
|
|
freeArrayInternal(m_richOffsetMappings);
|
|
|
|
m_inlineTreeNodes = NULL;
|
|
m_numInlineTreeNodes = 0;
|
|
m_richOffsetMappings = NULL;
|
|
m_numRichOffsetMappings = 0;
|
|
|
|
#ifdef FEATURE_ON_STACK_REPLACEMENT
|
|
if (m_pPatchpointInfoFromJit != NULL)
|
|
freeArrayInternal(m_pPatchpointInfoFromJit);
|
|
|
|
m_pPatchpointInfoFromJit = NULL;
|
|
#endif
|
|
|
|
#ifdef FEATURE_EH_FUNCLETS
|
|
m_moduleBase = NULL;
|
|
m_totalUnwindSize = 0;
|
|
m_usedUnwindSize = 0;
|
|
m_theUnwindBlock = NULL;
|
|
m_totalUnwindInfos = 0;
|
|
m_usedUnwindInfos = 0;
|
|
#endif // FEATURE_EH_FUNCLETS
|
|
}
|
|
|
|
#ifdef TARGET_AMD64
|
|
void SetAllowRel32(BOOL fAllowRel32)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
m_fAllowRel32 = fAllowRel32;
|
|
}
|
|
#endif
|
|
|
|
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
|
|
void SetJumpStubOverflow(BOOL fJumpStubOverflow)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
m_fJumpStubOverflow = fJumpStubOverflow;
|
|
}
|
|
|
|
BOOL IsJumpStubOverflow()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return m_fJumpStubOverflow;
|
|
}
|
|
|
|
BOOL JitAgain()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return m_fJumpStubOverflow;
|
|
}
|
|
|
|
size_t GetReserveForJumpStubs()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return m_reserveForJumpStubs;
|
|
}
|
|
|
|
void SetReserveForJumpStubs(size_t value)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
m_reserveForJumpStubs = value;
|
|
}
|
|
#else
|
|
BOOL JitAgain()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return FALSE;
|
|
}
|
|
|
|
size_t GetReserveForJumpStubs()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return 0;
|
|
}
|
|
#endif // defined(TARGET_AMD64) || defined(TARGET_ARM64)
|
|
|
|
#ifdef FEATURE_ON_STACK_REPLACEMENT
|
|
// Called by the runtime to supply patchpoint information to the jit.
|
|
void SetOSRInfo(PatchpointInfo* patchpointInfo, unsigned ilOffset)
|
|
{
|
|
_ASSERTE(m_pPatchpointInfoFromRuntime == NULL);
|
|
_ASSERTE(patchpointInfo != NULL);
|
|
m_pPatchpointInfoFromRuntime = patchpointInfo;
|
|
m_ilOffset = ilOffset;
|
|
}
|
|
#endif
|
|
|
|
CEEJitInfo(MethodDesc* fd, COR_ILMETHOD_DECODER* header,
|
|
EEJitManager* jm, bool allowInlining = true)
|
|
: CEEInfo(fd, allowInlining),
|
|
m_jitManager(jm),
|
|
m_CodeHeader(NULL),
|
|
m_CodeHeaderRW(NULL),
|
|
m_codeWriteBufferSize(0),
|
|
#ifdef USE_INDIRECT_CODEHEADER
|
|
m_pRealCodeHeader(NULL),
|
|
#endif
|
|
m_pCodeHeap(NULL),
|
|
m_ILHeader(header),
|
|
#ifdef FEATURE_EH_FUNCLETS
|
|
m_moduleBase(NULL),
|
|
m_totalUnwindSize(0),
|
|
m_usedUnwindSize(0),
|
|
m_theUnwindBlock(NULL),
|
|
m_totalUnwindInfos(0),
|
|
m_usedUnwindInfos(0),
|
|
#endif
|
|
#ifdef TARGET_AMD64
|
|
m_fAllowRel32(FALSE),
|
|
#endif
|
|
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
|
|
m_fJumpStubOverflow(FALSE),
|
|
m_reserveForJumpStubs(0),
|
|
#endif
|
|
m_GCinfo_len(0),
|
|
m_EHinfo_len(0),
|
|
m_iOffsetMapping(0),
|
|
m_pOffsetMapping(NULL),
|
|
m_iNativeVarInfo(0),
|
|
m_pNativeVarInfo(NULL),
|
|
m_inlineTreeNodes(NULL),
|
|
m_numInlineTreeNodes(0),
|
|
m_richOffsetMappings(NULL),
|
|
m_numRichOffsetMappings(0),
|
|
#ifdef FEATURE_ON_STACK_REPLACEMENT
|
|
m_pPatchpointInfoFromJit(NULL),
|
|
m_pPatchpointInfoFromRuntime(NULL),
|
|
m_ilOffset(0),
|
|
#endif
|
|
m_gphCache()
|
|
{
|
|
CONTRACTL
|
|
{
|
|
NOTHROW;
|
|
GC_NOTRIGGER;
|
|
MODE_ANY;
|
|
} CONTRACTL_END;
|
|
}
|
|
|
|
~CEEJitInfo()
|
|
{
|
|
CONTRACTL
|
|
{
|
|
NOTHROW;
|
|
GC_NOTRIGGER;
|
|
MODE_ANY;
|
|
} CONTRACTL_END;
|
|
|
|
if (m_CodeHeaderRW != m_CodeHeader)
|
|
freeArrayInternal(m_CodeHeaderRW);
|
|
|
|
if (m_pOffsetMapping != NULL)
|
|
freeArrayInternal(m_pOffsetMapping);
|
|
|
|
if (m_pNativeVarInfo != NULL)
|
|
freeArrayInternal(m_pNativeVarInfo);
|
|
|
|
#ifdef FEATURE_ON_STACK_REPLACEMENT
|
|
if (m_pPatchpointInfoFromJit != NULL)
|
|
freeArrayInternal(m_pPatchpointInfoFromJit);
|
|
#endif
|
|
#ifdef FEATURE_PGO
|
|
if (m_foundPgoData != NULL)
|
|
{
|
|
ComputedPgoData* current = m_foundPgoData;
|
|
while (current != NULL)
|
|
{
|
|
ComputedPgoData* next = current->m_next;
|
|
delete current;
|
|
current = next;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// ICorDebugInfo stuff.
|
|
void setBoundaries(CORINFO_METHOD_HANDLE ftn,
|
|
ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap) override final;
|
|
void setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars,
|
|
ICorDebugInfo::NativeVarInfo *vars) override final;
|
|
void CompressDebugInfo();
|
|
|
|
void reportRichMappings(
|
|
ICorDebugInfo::InlineTreeNode* inlineTreeNodes,
|
|
uint32_t numInlineTreeNodes,
|
|
ICorDebugInfo::RichOffsetMapping* mappings,
|
|
uint32_t numMappings) override final;
|
|
|
|
void reportMetadata(const char* key, const void* value, size_t length) override final;
|
|
|
|
void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
|
|
void ** ppIndirection) override final; /* OUT */
|
|
static PCODE getHelperFtnStatic(CorInfoHelpFunc ftnNum);
|
|
|
|
// Override of CEEInfo::GetProfilingHandle. The first time this is called for a
|
|
// method desc, it calls through to CEEInfo::GetProfilingHandle and caches the
|
|
// result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
|
|
// rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
|
|
// making duplicate calls into the profiler's FunctionIDMapper callback.
|
|
void GetProfilingHandle(
|
|
bool *pbHookFunction,
|
|
void **pProfilerHandle,
|
|
bool *pbIndirectedHandles
|
|
) override final;
|
|
|
|
InfoAccessType constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void **ppValue) override final;
|
|
InfoAccessType emptyStringLiteral(void ** ppValue) override final;
|
|
CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) override final;
|
|
void* getMethodSync(CORINFO_METHOD_HANDLE ftnHnd, void **ppIndirection) override final;
|
|
|
|
void BackoutJitData(EEJitManager * jitMgr);
|
|
|
|
void WriteCode(EEJitManager * jitMgr);
|
|
|
|
void setPatchpointInfo(PatchpointInfo* patchpointInfo) override final;
|
|
PatchpointInfo* getOSRInfo(unsigned* ilOffset) override final;
|
|
|
|
protected :
|
|
|
|
void WriteCodeBytes();
|
|
|
|
#ifdef FEATURE_PGO
|
|
// PGO data
|
|
struct ComputedPgoData
|
|
{
|
|
ComputedPgoData(MethodDesc* pMD) : m_pMD(pMD) {}
|
|
|
|
ComputedPgoData* m_next = nullptr;
|
|
MethodDesc *m_pMD;
|
|
NewArrayHolder<BYTE> m_allocatedData;
|
|
PgoInstrumentationSchema* m_schema = nullptr;
|
|
UINT32 m_cSchemaElems;
|
|
BYTE *m_pInstrumentationData = nullptr;
|
|
HRESULT m_hr = E_NOTIMPL;
|
|
PgoSource m_pgoSource = PgoSource::Unknown;
|
|
};
|
|
ComputedPgoData* m_foundPgoData = nullptr;
|
|
#endif
|
|
|
|
|
|
EEJitManager* m_jitManager; // responsible for allocating memory
|
|
CodeHeader* m_CodeHeader; // descriptor for JITTED code - read/execute address
|
|
CodeHeader* m_CodeHeaderRW; // descriptor for JITTED code - code write scratch buffer address
|
|
size_t m_codeWriteBufferSize;
|
|
#ifdef USE_INDIRECT_CODEHEADER
|
|
BYTE* m_pRealCodeHeader;
|
|
#endif
|
|
HeapList* m_pCodeHeap;
|
|
COR_ILMETHOD_DECODER * m_ILHeader; // the code header as exist in the file
|
|
#ifdef FEATURE_EH_FUNCLETS
|
|
TADDR m_moduleBase; // Base for unwind Infos
|
|
ULONG m_totalUnwindSize; // Total reserved unwind space
|
|
uint32_t m_usedUnwindSize; // used space in m_theUnwindBlock
|
|
BYTE * m_theUnwindBlock; // start of the unwind memory block
|
|
ULONG m_totalUnwindInfos; // Number of RUNTIME_FUNCTION needed
|
|
ULONG m_usedUnwindInfos;
|
|
#endif
|
|
|
|
#ifdef TARGET_AMD64
|
|
BOOL m_fAllowRel32; // Use 32-bit PC relative address modes
|
|
#endif
|
|
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
|
|
BOOL m_fJumpStubOverflow; // Overflow while trying to alocate jump stub slot within PC relative branch region
|
|
// The code will need to be regenerated (with m_fRel32Allowed == FALSE for AMD64).
|
|
size_t m_reserveForJumpStubs; // Space to reserve for jump stubs when allocating code
|
|
#endif
|
|
|
|
#if defined(_DEBUG)
|
|
ULONG m_codeSize; // Code size requested via allocMem
|
|
#endif
|
|
|
|
size_t m_GCinfo_len; // Cached copy of GCinfo_len so we can backout in BackoutJitData()
|
|
size_t m_EHinfo_len; // Cached copy of EHinfo_len so we can backout in BackoutJitData()
|
|
|
|
ULONG32 m_iOffsetMapping;
|
|
ICorDebugInfo::OffsetMapping * m_pOffsetMapping;
|
|
|
|
ULONG32 m_iNativeVarInfo;
|
|
ICorDebugInfo::NativeVarInfo * m_pNativeVarInfo;
|
|
|
|
ICorDebugInfo::InlineTreeNode *m_inlineTreeNodes;
|
|
ULONG32 m_numInlineTreeNodes;
|
|
ICorDebugInfo::RichOffsetMapping *m_richOffsetMappings;
|
|
ULONG32 m_numRichOffsetMappings;
|
|
|
|
#ifdef FEATURE_ON_STACK_REPLACEMENT
|
|
PatchpointInfo * m_pPatchpointInfoFromJit;
|
|
PatchpointInfo * m_pPatchpointInfoFromRuntime;
|
|
unsigned m_ilOffset;
|
|
#endif
|
|
|
|
// The first time a call is made to CEEJitInfo::GetProfilingHandle() from this thread
|
|
// for this method, these values are filled in. Thereafter, these values are used
|
|
// in lieu of calling into the base CEEInfo::GetProfilingHandle() again. This protects the
|
|
// profiler from duplicate calls to its FunctionIDMapper() callback.
|
|
struct GetProfilingHandleCache
|
|
{
|
|
GetProfilingHandleCache() :
|
|
m_bGphIsCacheValid(false),
|
|
m_bGphHookFunction(false),
|
|
m_pvGphProfilerHandle(NULL)
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
}
|
|
|
|
bool m_bGphIsCacheValid : 1; // Tells us whether below values are valid
|
|
bool m_bGphHookFunction : 1;
|
|
void* m_pvGphProfilerHandle;
|
|
} m_gphCache;
|
|
|
|
};
|
|
|
|
/*********************************************************************/
|
|
/*********************************************************************/
|
|
|
|
typedef struct {
|
|
void * pfnHelper;
|
|
#ifdef _DEBUG
|
|
const char* name;
|
|
#endif
|
|
} VMHELPDEF;
|
|
|
|
#if defined(DACCESS_COMPILE)
|
|
|
|
GARY_DECL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
|
|
|
|
#else
|
|
|
|
extern "C" const VMHELPDEF hlpFuncTable[CORINFO_HELP_COUNT];
|
|
|
|
#endif
|
|
|
|
#if defined(_DEBUG) && (defined(TARGET_AMD64) || defined(TARGET_X86)) && !defined(TARGET_UNIX)
|
|
typedef struct {
|
|
void* pfnRealHelper;
|
|
const char* helperName;
|
|
LONG count;
|
|
LONG helperSize;
|
|
} VMHELPCOUNTDEF;
|
|
|
|
extern "C" VMHELPCOUNTDEF hlpFuncCountTable[CORINFO_HELP_COUNT+1];
|
|
|
|
void InitJitHelperLogging();
|
|
void WriteJitHelperCountToSTRESSLOG();
|
|
#else
|
|
inline void InitJitHelperLogging() { }
|
|
inline void WriteJitHelperCountToSTRESSLOG() { }
|
|
#endif
|
|
|
|
// enum for dynamically assigned helper calls
|
|
enum DynamicCorInfoHelpFunc {
|
|
#define JITHELPER(code, pfnHelper, sig)
|
|
#define DYNAMICJITHELPER(code, pfnHelper, sig) DYNAMIC_##code,
|
|
#include "jithelpers.h"
|
|
DYNAMIC_CORINFO_HELP_COUNT
|
|
};
|
|
|
|
#ifdef _MSC_VER
|
|
// GCC complains about duplicate "extern". And it is not needed for the GCC build
|
|
extern "C"
|
|
#endif
|
|
GARY_DECL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
|
|
|
|
#define SetJitHelperFunction(ftnNum, pFunc) _SetJitHelperFunction(DYNAMIC_##ftnNum, (void*)(pFunc))
|
|
void _SetJitHelperFunction(DynamicCorInfoHelpFunc ftnNum, void * pFunc);
|
|
|
|
void *GenFastGetSharedStaticBase(bool bCheckCCtor);
|
|
|
|
#ifdef HAVE_GCCOVER
|
|
void SetupGcCoverage(NativeCodeVersion nativeCodeVersion, BYTE* nativeCode);
|
|
void SetupGcCoverageForNativeImage(Module* module);
|
|
BOOL OnGcCoverageInterrupt(PT_CONTEXT regs);
|
|
void DoGcStress (PT_CONTEXT regs, NativeCodeVersion nativeCodeVersion);
|
|
#endif //HAVE_GCCOVER
|
|
|
|
EXTERN_C FCDECL2(LPVOID, ArrayStoreCheck, Object** pElement, PtrArray** pArray);
|
|
|
|
// ppPinnedString: If the string is pinned (e.g. allocated in frozen heap),
|
|
// the pointer to the pinned string is returned in *ppPinnedPointer. ppPinnedPointer == nullptr
|
|
// means that the caller does not care whether the string is pinned or not.
|
|
OBJECTHANDLE ConstructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void** ppPinnedString = nullptr);
|
|
|
|
FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data);
|
|
FCDECL0(VOID, JIT_PollGC);
|
|
|
|
BOOL ObjIsInstanceOf(Object *pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE);
|
|
BOOL ObjIsInstanceOfCore(Object* pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE);
|
|
|
|
EXTERN_C TypeHandle::CastResult STDCALL ObjIsInstanceOfCached(Object *pObject, TypeHandle toTypeHnd);
|
|
|
|
#ifdef HOST_64BIT
|
|
class InlinedCallFrame;
|
|
Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg);
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
extern LONG g_JitCount;
|
|
#endif
|
|
|
|
struct VirtualFunctionPointerArgs
|
|
{
|
|
CORINFO_CLASS_HANDLE classHnd;
|
|
CORINFO_METHOD_HANDLE methodHnd;
|
|
};
|
|
|
|
FCDECL2(CORINFO_MethodPtr, JIT_VirtualFunctionPointer_Dynamic, Object * objectUNSAFE, VirtualFunctionPointerArgs * pArgs);
|
|
|
|
typedef HCCALL2_PTR(TADDR, FnStaticBaseHelper, TADDR arg0, TADDR arg1);
|
|
|
|
struct StaticFieldAddressArgs
|
|
{
|
|
FnStaticBaseHelper staticBaseHelper;
|
|
TADDR arg0;
|
|
TADDR arg1;
|
|
SIZE_T offset;
|
|
};
|
|
|
|
FCDECL1(TADDR, JIT_StaticFieldAddress_Dynamic, StaticFieldAddressArgs * pArgs);
|
|
FCDECL1(TADDR, JIT_StaticFieldAddressUnbox_Dynamic, StaticFieldAddressArgs * pArgs);
|
|
|
|
struct GenericHandleArgs
|
|
{
|
|
LPVOID signature;
|
|
CORINFO_MODULE_HANDLE module;
|
|
DWORD dictionaryIndexAndSlot;
|
|
};
|
|
|
|
FCDECL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleMethodWithSlotAndModule, CORINFO_METHOD_HANDLE methodHnd, GenericHandleArgs * pArgs);
|
|
FCDECL2(CORINFO_GENERIC_HANDLE, JIT_GenericHandleClassWithSlotAndModule, CORINFO_CLASS_HANDLE classHnd, GenericHandleArgs * pArgs);
|
|
|
|
CORINFO_GENERIC_HANDLE JIT_GenericHandleWorker(MethodDesc *pMD,
|
|
MethodTable *pMT,
|
|
LPVOID signature,
|
|
DWORD dictionaryIndexAndSlot = -1,
|
|
Module * pModule = NULL);
|
|
|
|
void ClearJitGenericHandleCache();
|
|
|
|
CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags);
|
|
|
|
bool __stdcall TrackAllocationsEnabled();
|
|
|
|
|
|
extern Volatile<int64_t> g_cbILJitted;
|
|
extern Volatile<int64_t> g_cMethodsJitted;
|
|
extern Volatile<int64_t> g_c100nsTicksInJit;
|
|
extern thread_local int64_t t_cbILJittedForThread;
|
|
extern thread_local int64_t t_cMethodsJittedForThread;
|
|
extern thread_local int64_t t_c100nsTicksInJitForThread;
|
|
|
|
FCDECL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread);
|
|
FCDECL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread);
|
|
FCDECL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread);
|
|
|
|
#endif // JITINTERFACE_H
|