mirror of
https://github.com/ZuneDev/dotnet-runtime.git
synced 2026-07-27 13:22:01 -07:00
622 lines
16 KiB
C
622 lines
16 KiB
C
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
// precode.h
|
|
//
|
|
|
|
//
|
|
// Stub that runs before the actual native code
|
|
|
|
#ifndef __PRECODE_H__
|
|
#define __PRECODE_H__
|
|
|
|
#define PRECODE_ALIGNMENT sizeof(void*)
|
|
|
|
#if defined(TARGET_AMD64)
|
|
|
|
#define OFFSETOF_PRECODE_TYPE 0
|
|
#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5
|
|
#define OFFSETOF_PRECODE_TYPE_MOV_R10 10
|
|
|
|
#define SIZEOF_PRECODE_BASE 16
|
|
|
|
#elif defined(TARGET_X86)
|
|
|
|
EXTERN_C VOID STDCALL PrecodeRemotingThunk();
|
|
|
|
#define OFFSETOF_PRECODE_TYPE 0
|
|
#define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5
|
|
#define OFFSETOF_PRECODE_TYPE_MOV_RM_R 6
|
|
|
|
#define SIZEOF_PRECODE_BASE 8
|
|
|
|
#elif defined(TARGET_ARM64)
|
|
|
|
#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN
|
|
#define OFFSETOF_PRECODE_TYPE 0
|
|
|
|
#elif defined(TARGET_ARM)
|
|
|
|
#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN * 2
|
|
#define OFFSETOF_PRECODE_TYPE 7
|
|
|
|
#elif defined(TARGET_LOONGARCH64)
|
|
|
|
#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN
|
|
#define OFFSETOF_PRECODE_TYPE 0
|
|
|
|
#elif defined(TARGET_RISCV64)
|
|
|
|
#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN
|
|
#define OFFSETOF_PRECODE_TYPE 0
|
|
|
|
#endif // TARGET_AMD64
|
|
|
|
#ifndef DACCESS_COMPILE
|
|
// Given an address in a slot, figure out if the prestub will be called
|
|
BOOL DoesSlotCallPrestub(PCODE pCode);
|
|
#endif
|
|
|
|
#include <pshpack1.h>
|
|
|
|
// Invalid precode type
|
|
struct InvalidPrecode
|
|
{
|
|
#if defined(TARGET_AMD64) || defined(TARGET_X86)
|
|
// int3
|
|
static const int Type = 0xCC;
|
|
#elif defined(TARGET_ARM64) || defined(TARGET_ARM)
|
|
static const int Type = 0;
|
|
#elif defined(TARGET_LOONGARCH64)
|
|
static const int Type = 0xff;
|
|
#elif defined(TARGET_RISCV64)
|
|
static const int Type = 0xff;
|
|
#endif
|
|
};
|
|
|
|
struct StubPrecodeData
|
|
{
|
|
PTR_MethodDesc MethodDesc;
|
|
PCODE Target;
|
|
BYTE Type;
|
|
};
|
|
|
|
typedef DPTR(StubPrecodeData) PTR_StubPrecodeData;
|
|
|
|
#if !(defined(TARGET_ARM64) && defined(TARGET_UNIX))
|
|
extern "C" void StubPrecodeCode();
|
|
extern "C" void StubPrecodeCode_End();
|
|
#endif
|
|
|
|
// Regular precode
|
|
struct StubPrecode
|
|
{
|
|
#if defined(TARGET_AMD64)
|
|
static const BYTE Type = 0x4C;
|
|
static const SIZE_T CodeSize = 24;
|
|
#elif defined(TARGET_X86)
|
|
static const BYTE Type = 0xA1;
|
|
static const SIZE_T CodeSize = 24;
|
|
#elif defined(TARGET_ARM64)
|
|
static const int Type = 0x4A;
|
|
static const SIZE_T CodeSize = 24;
|
|
#elif defined(TARGET_ARM)
|
|
static const int Type = 0xFF;
|
|
static const SIZE_T CodeSize = 12;
|
|
#elif defined(TARGET_LOONGARCH64)
|
|
static const int Type = 0x4;
|
|
static const SIZE_T CodeSize = 24;
|
|
#elif defined(TARGET_RISCV64)
|
|
static const int Type = 0x17;
|
|
static const SIZE_T CodeSize = 24;
|
|
#endif // TARGET_AMD64
|
|
|
|
BYTE m_code[CodeSize];
|
|
|
|
#if defined(TARGET_ARM64) && defined(TARGET_UNIX)
|
|
static void (*StubPrecodeCode)();
|
|
static void (*StubPrecodeCode_End)();
|
|
#endif
|
|
|
|
void Init(StubPrecode* pPrecodeRX, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator = NULL, BYTE type = StubPrecode::Type, TADDR target = NULL);
|
|
|
|
static void StaticInitialize();
|
|
|
|
PTR_StubPrecodeData GetData() const
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return dac_cast<PTR_StubPrecodeData>(dac_cast<TADDR>(this) + GetStubCodePageSize());
|
|
}
|
|
|
|
TADDR GetMethodDesc()
|
|
{
|
|
LIMITED_METHOD_DAC_CONTRACT;
|
|
|
|
return dac_cast<TADDR>(GetData()->MethodDesc);
|
|
}
|
|
|
|
PCODE GetTarget()
|
|
{
|
|
LIMITED_METHOD_DAC_CONTRACT;
|
|
|
|
return GetData()->Target;
|
|
}
|
|
|
|
BYTE GetType()
|
|
{
|
|
return GetData()->Type;
|
|
}
|
|
|
|
#ifndef DACCESS_COMPILE
|
|
static BOOL IsStubPrecodeByASM(PCODE addr);
|
|
|
|
void ResetTargetInterlocked()
|
|
{
|
|
CONTRACTL
|
|
{
|
|
THROWS;
|
|
GC_NOTRIGGER;
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
StubPrecodeData *pData = GetData();
|
|
InterlockedExchangeT<PCODE>(&pData->Target, GetPreStubEntryPoint());
|
|
}
|
|
|
|
BOOL SetTargetInterlocked(TADDR target, TADDR expected)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
THROWS;
|
|
GC_NOTRIGGER;
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
StubPrecodeData *pData = GetData();
|
|
return InterlockedCompareExchangeT<PCODE>(&pData->Target, (PCODE)target, (PCODE)expected) == expected;
|
|
}
|
|
|
|
static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size);
|
|
|
|
#endif // !DACCESS_COMPILE
|
|
};
|
|
|
|
typedef DPTR(StubPrecode) PTR_StubPrecode;
|
|
|
|
|
|
#ifdef HAS_NDIRECT_IMPORT_PRECODE
|
|
|
|
// NDirect import precode
|
|
// (This is fake precode. VTable slot does not point to it.)
|
|
struct NDirectImportPrecode : StubPrecode
|
|
{
|
|
static const int Type = 0x05;
|
|
|
|
void Init(NDirectImportPrecode* pPrecodeRX, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
|
|
|
|
LPVOID GetEntrypoint()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return (LPVOID)PINSTRToPCODE(dac_cast<TADDR>(this));
|
|
}
|
|
};
|
|
typedef DPTR(NDirectImportPrecode) PTR_NDirectImportPrecode;
|
|
|
|
#endif // HAS_NDIRECT_IMPORT_PRECODE
|
|
|
|
|
|
#ifdef HAS_FIXUP_PRECODE
|
|
|
|
struct FixupPrecodeData
|
|
{
|
|
PCODE Target;
|
|
MethodDesc *MethodDesc;
|
|
PCODE PrecodeFixupThunk;
|
|
};
|
|
|
|
typedef DPTR(FixupPrecodeData) PTR_FixupPrecodeData;
|
|
|
|
#if !(defined(TARGET_ARM64) && defined(TARGET_UNIX))
|
|
extern "C" void FixupPrecodeCode();
|
|
extern "C" void FixupPrecodeCode_End();
|
|
#endif
|
|
|
|
// Fixup precode is used in ngen images when the prestub does just one time fixup.
|
|
// The fixup precode is simple jump once patched. It does not have the two instruction overhead of regular precode.
|
|
struct FixupPrecode
|
|
{
|
|
#if defined(TARGET_AMD64)
|
|
static const int Type = 0xFF;
|
|
static const SIZE_T CodeSize = 24;
|
|
static const int FixupCodeOffset = 6;
|
|
#elif defined(TARGET_X86)
|
|
static const int Type = 0xFF;
|
|
static const SIZE_T CodeSize = 24;
|
|
static const int FixupCodeOffset = 6;
|
|
#elif defined(TARGET_ARM64)
|
|
static const int Type = 0x0B;
|
|
static const SIZE_T CodeSize = 24;
|
|
static const int FixupCodeOffset = 8;
|
|
#elif defined(TARGET_ARM)
|
|
static const int Type = 0xCF;
|
|
static const SIZE_T CodeSize = 12;
|
|
static const int FixupCodeOffset = 4 + THUMB_CODE;
|
|
#elif defined(TARGET_LOONGARCH64)
|
|
static const int Type = 0x3;
|
|
static const SIZE_T CodeSize = 32;
|
|
static const int FixupCodeOffset = 12;
|
|
#elif defined(TARGET_RISCV64)
|
|
static const int Type = 0x97;
|
|
static const SIZE_T CodeSize = 32;
|
|
static const int FixupCodeOffset = 10;
|
|
#endif // TARGET_AMD64
|
|
|
|
BYTE m_code[CodeSize];
|
|
|
|
#if defined(TARGET_ARM64) && defined(TARGET_UNIX)
|
|
static void (*FixupPrecodeCode)();
|
|
static void (*FixupPrecodeCode_End)();
|
|
#endif
|
|
|
|
void Init(FixupPrecode* pPrecodeRX, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
|
|
|
|
static void StaticInitialize();
|
|
|
|
static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size);
|
|
|
|
PTR_FixupPrecodeData GetData() const
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return dac_cast<PTR_FixupPrecodeData>(dac_cast<TADDR>(this) + GetStubCodePageSize());
|
|
}
|
|
|
|
TADDR GetMethodDesc()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return (TADDR)GetData()->MethodDesc;
|
|
}
|
|
|
|
PCODE GetTarget()
|
|
{
|
|
LIMITED_METHOD_DAC_CONTRACT;
|
|
return GetData()->Target;
|
|
}
|
|
|
|
PCODE *GetTargetSlot()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return &GetData()->Target;
|
|
}
|
|
|
|
#ifndef DACCESS_COMPILE
|
|
static BOOL IsFixupPrecodeByASM(PCODE addr);
|
|
|
|
void ResetTargetInterlocked()
|
|
{
|
|
CONTRACTL
|
|
{
|
|
NOTHROW;
|
|
GC_NOTRIGGER;
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
PCODE target = (PCODE)this + FixupCodeOffset;
|
|
|
|
_ASSERTE(IS_ALIGNED(&GetData()->Target, sizeof(SIZE_T)));
|
|
InterlockedExchangeT<PCODE>(&GetData()->Target, target);
|
|
}
|
|
|
|
BOOL SetTargetInterlocked(TADDR target, TADDR expected)
|
|
{
|
|
CONTRACTL
|
|
{
|
|
NOTHROW;
|
|
GC_NOTRIGGER;
|
|
}
|
|
CONTRACTL_END;
|
|
|
|
PCODE oldTarget = (PCODE)GetData()->Target;
|
|
if (oldTarget != ((PCODE)this + FixupCodeOffset))
|
|
{
|
|
#ifdef FEATURE_CODE_VERSIONING
|
|
// No change needed, jmp is already in place
|
|
#else
|
|
// Setting the target more than once is unexpected
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
_ASSERTE(IS_ALIGNED(&GetData()->Target, sizeof(SIZE_T)));
|
|
return InterlockedCompareExchangeT<PCODE>(&GetData()->Target, (PCODE)target, (PCODE)oldTarget) == (PCODE)oldTarget;
|
|
}
|
|
#endif
|
|
|
|
#ifdef DACCESS_COMPILE
|
|
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
|
|
#endif
|
|
};
|
|
|
|
typedef DPTR(FixupPrecode) PTR_FixupPrecode;
|
|
|
|
#endif // HAS_FIXUP_PRECODE
|
|
|
|
#include <poppack.h>
|
|
|
|
typedef DPTR(class Precode) PTR_Precode;
|
|
|
|
enum PrecodeType {
|
|
PRECODE_INVALID = InvalidPrecode::Type,
|
|
PRECODE_STUB = StubPrecode::Type,
|
|
#ifdef HAS_NDIRECT_IMPORT_PRECODE
|
|
PRECODE_NDIRECT_IMPORT = NDirectImportPrecode::Type,
|
|
#endif // HAS_NDIRECT_IMPORT_PRECODE
|
|
#ifdef HAS_FIXUP_PRECODE
|
|
PRECODE_FIXUP = FixupPrecode::Type,
|
|
#endif // HAS_FIXUP_PRECODE
|
|
#ifdef HAS_THISPTR_RETBUF_PRECODE
|
|
PRECODE_THISPTR_RETBUF = ThisPtrRetBufPrecode::Type,
|
|
#endif // HAS_THISPTR_RETBUF_PRECODE
|
|
};
|
|
|
|
// For more details see. file:../../doc/BookOfTheRuntime/ClassLoader/MethodDescDesign.doc
|
|
class Precode {
|
|
|
|
BYTE m_data[SIZEOF_PRECODE_BASE];
|
|
|
|
StubPrecode* AsStubPrecode()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
return dac_cast<PTR_StubPrecode>(this);
|
|
}
|
|
|
|
#ifdef HAS_NDIRECT_IMPORT_PRECODE
|
|
public:
|
|
// Fake precodes has to be exposed
|
|
NDirectImportPrecode* AsNDirectImportPrecode()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
return dac_cast<PTR_NDirectImportPrecode>(this);
|
|
}
|
|
|
|
private:
|
|
#endif // HAS_NDIRECT_IMPORT_PRECODE
|
|
|
|
#ifdef HAS_FIXUP_PRECODE
|
|
PTR_FixupPrecode AsFixupPrecode()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
return dac_cast<PTR_FixupPrecode>(this);
|
|
}
|
|
#endif // HAS_FIXUP_PRECODE
|
|
|
|
#ifdef HAS_THISPTR_RETBUF_PRECODE
|
|
ThisPtrRetBufPrecode* AsThisPtrRetBufPrecode()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
return dac_cast<PTR_ThisPtrRetBufPrecode>(this);
|
|
}
|
|
#endif // HAS_THISPTR_RETBUF_PRECODE
|
|
|
|
TADDR GetStart()
|
|
{
|
|
SUPPORTS_DAC;
|
|
LIMITED_METHOD_CONTRACT;
|
|
return dac_cast<TADDR>(this);
|
|
}
|
|
|
|
static void UnexpectedPrecodeType(const char * originator, PrecodeType precodeType)
|
|
|
|
{
|
|
SUPPORTS_DAC;
|
|
#ifdef DACCESS_COMPILE
|
|
DacError(E_UNEXPECTED);
|
|
#else
|
|
#ifdef _PREFIX_
|
|
// We only use __UNREACHABLE here since otherwise it would be a hint
|
|
// for the compiler to fold this case with the other cases in a switch
|
|
// statement. However, we would rather have this case be a separate
|
|
// code path so that we will get a clean crash sooner.
|
|
__UNREACHABLE("Unexpected precode type");
|
|
#endif
|
|
CONSISTENCY_CHECK_MSGF(false, ("%s: Unexpected precode type: 0x%02x.", originator, precodeType));
|
|
#endif
|
|
}
|
|
|
|
public:
|
|
PrecodeType GetType()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
#ifdef OFFSETOF_PRECODE_TYPE
|
|
|
|
#if defined(TARGET_LOONGARCH64)
|
|
assert(0 == OFFSETOF_PRECODE_TYPE);
|
|
short type = *((short*)m_data);
|
|
type >>= 5;
|
|
#elif defined(TARGET_RISCV64)
|
|
assert(0 == OFFSETOF_PRECODE_TYPE);
|
|
BYTE type = *((BYTE*)m_data + OFFSETOF_PRECODE_TYPE);
|
|
#else
|
|
BYTE type = m_data[OFFSETOF_PRECODE_TYPE];
|
|
#endif
|
|
|
|
if (type == StubPrecode::Type)
|
|
{
|
|
// StubPrecode code is used for both StubPrecode and NDirectImportPrecode,
|
|
// so we need to get the real type
|
|
type = AsStubPrecode()->GetType();
|
|
}
|
|
|
|
return (PrecodeType)type;
|
|
|
|
#else // OFFSETOF_PRECODE_TYPE
|
|
return PRECODE_STUB;
|
|
#endif // OFFSETOF_PRECODE_TYPE
|
|
}
|
|
|
|
static BOOL IsValidType(PrecodeType t);
|
|
|
|
static int AlignOf(PrecodeType t)
|
|
{
|
|
SUPPORTS_DAC;
|
|
unsigned int align = PRECODE_ALIGNMENT;
|
|
|
|
#if defined(TARGET_ARM) && defined(HAS_COMPACT_ENTRYPOINTS)
|
|
// Precodes have to be aligned to allow fast compact entry points check
|
|
_ASSERTE (align >= sizeof(void*));
|
|
#endif // TARGET_ARM && HAS_COMPACT_ENTRYPOINTS
|
|
|
|
return align;
|
|
}
|
|
|
|
static SIZE_T SizeOf(PrecodeType t);
|
|
|
|
SIZE_T SizeOf()
|
|
{
|
|
WRAPPER_NO_CONTRACT;
|
|
return SizeOf(GetType());
|
|
}
|
|
|
|
// Note: This is immediate target of the precode. It does not follow jump stub if there is one.
|
|
PCODE GetTarget();
|
|
|
|
BOOL IsPointingTo(PCODE target, PCODE addr)
|
|
{
|
|
WRAPPER_NO_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
if (target == addr)
|
|
return TRUE;
|
|
|
|
#ifdef TARGET_AMD64
|
|
// Handle jump stubs
|
|
if (isJumpRel64(target)) {
|
|
target = decodeJump64(target);
|
|
if (target == addr)
|
|
return TRUE;
|
|
}
|
|
#endif // TARGET_AMD64
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL IsPointingToNativeCode(PCODE pNativeCode)
|
|
{
|
|
WRAPPER_NO_CONTRACT;
|
|
SUPPORTS_DAC;
|
|
|
|
return IsPointingTo(GetTarget(), pNativeCode);
|
|
}
|
|
|
|
BOOL IsPointingToPrestub(PCODE target);
|
|
|
|
BOOL IsPointingToPrestub()
|
|
{
|
|
WRAPPER_NO_CONTRACT;
|
|
return IsPointingToPrestub(GetTarget());
|
|
}
|
|
|
|
PCODE GetEntryPoint()
|
|
{
|
|
LIMITED_METHOD_CONTRACT;
|
|
return PINSTRToPCODE(dac_cast<TADDR>(this));
|
|
}
|
|
|
|
PTR_PCODE GetTargetSlot();
|
|
|
|
MethodDesc * GetMethodDesc(BOOL fSpeculative = FALSE);
|
|
BOOL IsCorrectMethodDesc(MethodDesc * pMD);
|
|
|
|
static Precode* Allocate(PrecodeType t, MethodDesc* pMD,
|
|
LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
|
|
void Init(Precode* pPrecodeRX, PrecodeType t, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator);
|
|
|
|
#ifndef DACCESS_COMPILE
|
|
void ResetTargetInterlocked();
|
|
BOOL SetTargetInterlocked(PCODE target, BOOL fOnlyRedirectFromPrestub = TRUE);
|
|
|
|
// Reset precode to point to prestub
|
|
void Reset();
|
|
#endif // DACCESS_COMPILE
|
|
|
|
static PTR_Precode GetPrecodeFromEntryPoint(PCODE addr, BOOL fSpeculative = FALSE)
|
|
{
|
|
LIMITED_METHOD_DAC_CONTRACT;
|
|
|
|
#ifdef DACCESS_COMPILE
|
|
// Always use speculative checks with DAC
|
|
fSpeculative = TRUE;
|
|
#endif
|
|
|
|
TADDR pInstr = PCODEToPINSTR(addr);
|
|
|
|
// Always do consistency check in debug
|
|
if (fSpeculative INDEBUG(|| TRUE))
|
|
{
|
|
if (!IS_ALIGNED(pInstr, PRECODE_ALIGNMENT) || !IsValidType(PTR_Precode(pInstr)->GetType()))
|
|
{
|
|
if (fSpeculative) return NULL;
|
|
_ASSERTE(!"Precode::GetPrecodeFromEntryPoint: Unexpected code in precode");
|
|
}
|
|
}
|
|
|
|
PTR_Precode pPrecode = PTR_Precode(pInstr);
|
|
return pPrecode;
|
|
}
|
|
|
|
// If addr is patched fixup precode, returns address that it points to. Otherwise returns NULL.
|
|
static PCODE TryToSkipFixupPrecode(PCODE addr);
|
|
|
|
//
|
|
// Precode as temporary entrypoint
|
|
//
|
|
|
|
static SIZE_T SizeOfTemporaryEntryPoint(PrecodeType t)
|
|
{
|
|
LIMITED_METHOD_DAC_CONTRACT;
|
|
|
|
return ALIGN_UP(SizeOf(t), AlignOf(t));
|
|
}
|
|
|
|
static Precode * GetPrecodeForTemporaryEntryPoint(TADDR temporaryEntryPoints, int index);
|
|
|
|
static SIZE_T SizeOfTemporaryEntryPoints(PrecodeType t, int count);
|
|
static SIZE_T SizeOfTemporaryEntryPoints(TADDR temporaryEntryPoints, int count);
|
|
|
|
static TADDR AllocateTemporaryEntryPoints(MethodDescChunk* pChunk,
|
|
LoaderAllocator *pLoaderAllocator, AllocMemTracker *pamTracker);
|
|
|
|
static DWORD GetMaxTemporaryEntryPointsCount()
|
|
{
|
|
SIZE_T maxPrecodeCodeSize = Max(FixupPrecode::CodeSize, StubPrecode::CodeSize);
|
|
SIZE_T count = GetStubCodePageSize() / maxPrecodeCodeSize;
|
|
_ASSERTE(count < MAXDWORD);
|
|
return (DWORD)count;
|
|
}
|
|
|
|
#ifdef DACCESS_COMPILE
|
|
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
|
|
#endif
|
|
};
|
|
|
|
// Verify that the type for each precode is different
|
|
static_assert_no_msg(StubPrecode::Type != NDirectImportPrecode::Type);
|
|
static_assert_no_msg(StubPrecode::Type != FixupPrecode::Type);
|
|
static_assert_no_msg(StubPrecode::Type != ThisPtrRetBufPrecode::Type);
|
|
static_assert_no_msg(FixupPrecode::Type != NDirectImportPrecode::Type);
|
|
static_assert_no_msg(FixupPrecode::Type != ThisPtrRetBufPrecode::Type);
|
|
static_assert_no_msg(NDirectImportPrecode::Type != ThisPtrRetBufPrecode::Type);
|
|
|
|
// Verify that the base type for each precode fits into each specific precode type
|
|
static_assert_no_msg(sizeof(Precode) <= sizeof(NDirectImportPrecode));
|
|
static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode));
|
|
static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode));
|
|
#endif // __PRECODE_H__
|