Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ class AsmOffsets
// Debug build offsets
#if TARGET_AMD64
#if TARGET_UNIX
public const int SIZEOF__REGDISPLAY = 0x1b90;
public const int SIZEOF__REGDISPLAY = 0x1c10;
public const int OFFSETOF__REGDISPLAY__SP = 0x1b78;
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x1b80;
#else // TARGET_UNIX
public const int SIZEOF__REGDISPLAY = 0xbf0;
public const int SIZEOF__REGDISPLAY = 0xc70;
public const int OFFSETOF__REGDISPLAY__SP = 0xbd8;
public const int OFFSETOF__REGDISPLAY__ControlPC = 0xbe0;
#endif // TARGET_UNIX
Expand Down Expand Up @@ -82,7 +82,7 @@ class AsmOffsets
// Release build offsets
#if TARGET_AMD64
#if TARGET_UNIX
public const int SIZEOF__REGDISPLAY = 0x1b80;
public const int SIZEOF__REGDISPLAY = 0x1c00;
public const int OFFSETOF__REGDISPLAY__SP = 0x1b70;
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x1b78;
#else // TARGET_UNIX
Expand Down
15 changes: 14 additions & 1 deletion src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "handletable.inl"
#include "gcenv.inl"
#include "gceventstatus.h"
#include <minipal/cpufeatures.h>

#ifdef __INTELLISENSE__
#if defined(FEATURE_SVR_GC)
Expand Down Expand Up @@ -143,6 +144,15 @@ bool g_built_with_svr_gc = true;
bool g_built_with_svr_gc = false;
#endif // FEATURE_SVR_GC

// Stores the ISA capability of the hardware
int cpuFeatures = 0;
#if defined(TARGET_AMD64)
inline bool IsAPXSupported()
Copy link
Member

@jkotas jkotas Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary. We should introduce this in the GC only if the GC ever needs conditional paths for Apx - that is unlikely.

{
return (cpuFeatures & XArchIntrinsicConstants_Apx);
}
#endif // TARGET_AMD64

#if defined(BUILDENV_DEBUG)
uint8_t g_build_variant = 0;
#elif defined(BUILDENV_CHECKED)
Expand Down Expand Up @@ -14698,7 +14708,7 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size,
#endif // __linux__

#ifdef USE_VXSORT
InitSupportedInstructionSet ((int32_t)GCConfig::GetGCEnabledInstructionSets());
InitSupportedInstructionSet ((int32_t)GCConfig::GetGCEnabledInstructionSets(), cpuFeatures);
#endif

if (!init_semi_shared())
Expand Down Expand Up @@ -49286,6 +49296,9 @@ HRESULT GCHeap::Initialize()
return CLR_E_GC_BAD_HARD_LIMIT;
}

// initialize the cpuFeatures from minipal
cpuFeatures = minipal_getcpufeatures();

uint32_t nhp = 1;
uint32_t nhp_from_config = 0;
uint32_t max_nhp_from_config = (uint32_t)GCConfig::GetMaxHeapCount();
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/gc/gcimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ extern bool g_fFinalizerRunOnShutDown;
extern bool g_built_with_svr_gc;
extern uint8_t g_build_variant;
extern VOLATILE(int32_t) g_no_gc_lock;
// Stores the mask for supported instruction sets
extern int cpuFeatures;
#if defined(TARGET_AMD64)
extern inline bool IsAPXSupported();
#endif // TARGET_AMD64

class GCHeap : public IGCHeapInternal
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/gc/vxsort/do_vxsort.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ enum class InstructionSet
AVX512F = 1,
};

void InitSupportedInstructionSet (int32_t configSetting);
void InitSupportedInstructionSet (int32_t configSetting, int cpuFeatures);
bool IsSupportedInstructionSet (InstructionSet instructionSet);

void do_vxsort_avx2 (uint8_t** low, uint8_t** high, uint8_t *range_low, uint8_t *range_high);
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/gc/vxsort/isa_detection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ enum class SupportedISA
AVX512F = 1 << (int)InstructionSet::AVX512F
};

SupportedISA DetermineSupportedISA()
SupportedISA DetermineSupportedISA(int cpuFeatures)
{
int cpuFeatures = minipal_getcpufeatures();
// int cpuFeatures = minipal_getcpufeatures();
if ((cpuFeatures & XArchIntrinsicConstants_Avx2) != 0)
{
if ((cpuFeatures & XArchIntrinsicConstants_Avx512) != 0)
Expand All @@ -39,9 +39,9 @@ bool IsSupportedInstructionSet (InstructionSet instructionSet)
return ((int)s_supportedISA & (1 << (int)instructionSet)) != 0;
}

void InitSupportedInstructionSet (int32_t configSetting)
void InitSupportedInstructionSet (int32_t configSetting, int cpuFeatures)
{
s_supportedISA = (SupportedISA)((int)DetermineSupportedISA() & configSetting);
s_supportedISA = (SupportedISA)((int)DetermineSupportedISA(cpuFeatures) & configSetting);
// we are assuming that AVX2 can be used if AVX512F can,
// so if AVX2 is disabled, we need to disable AVX512F as well
if (!((int)s_supportedISA & (int)SupportedISA::AVX2))
Expand Down
50 changes: 48 additions & 2 deletions src/coreclr/gcinfo/gcinfodumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,24 @@ BOOL GcInfoDumper::ReportPointerRecord (
REG(r13, R13),
REG(r14, R14),
REG(r15, R15),
#undef REG
#define REG(reg, field) { offsetof(Amd64VolatileContextPointer, field) }
REG(r16, R16),
REG(r17, R17),
REG(r18, R18),
REG(r19, R19),
REG(r20, R20),
REG(r21, R21),
REG(r22, R22),
REG(r23, R23),
REG(r24, R24),
REG(r25, R25),
REG(r26, R26),
REG(r27, R27),
REG(r28, R28),
REG(r29, R29),
REG(r30, R30),
REG(r31, R31),
#elif defined(TARGET_ARM)
#undef REG
#define REG(reg, field) { offsetof(ArmVolatileContextPointer, field) }
Expand Down Expand Up @@ -294,7 +312,7 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this

#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64)
BYTE* pContext = (BYTE*)&(pRD->volatileCurrContextPointers);
#else
#else // TARGET_ARM || TARGET_ARM64 || TARGET_RISCV64 || TARGET_LOONGARCH64
BYTE* pContext = (BYTE*)pRD->pCurrentContext;
#endif

Expand Down Expand Up @@ -390,7 +408,12 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this
{
continue;
}
#endif
#elif defined(TARGET_AMD64)
if ((ctx != 0 && iEncodedReg > 15) || !IsAPXSupported())
{
break;
}
#endif // TARGET_AMD64
{
_ASSERTE(iReg < nCONTEXTRegisters);
#ifdef TARGET_ARM
Expand All @@ -414,6 +437,19 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this
{
pReg = (SIZE_T*)((BYTE*)pRD->pCurrentContext + rgRegisters[iReg].cbContextOffset);
}
#elif defined(TARGET_AMD64)
if (ctx == 0 && iReg == 16)
{
pContext = (BYTE*)&(pRD->volatileCurrContextPointers);
}
if (ctx == 0 && iReg >= 16)
{
pReg = *(SIZE_T**)(pContext + rgRegisters[iReg].cbContextOffset);
}
else
{
pReg = (SIZE_T*)(pContext + rgRegisters[iReg].cbContextOffset);
}
#else
pReg = (SIZE_T*)(pContext + rgRegisters[iReg].cbContextOffset);
#endif
Expand Down Expand Up @@ -664,6 +700,16 @@ GcInfoDumper::EnumerateStateChangesResults GcInfoDumper::EnumerateStateChanges (
*(ppCurrentRax + iReg) = &regdisp.pCurrentContext->Rax + iReg;
*(ppCallerRax + iReg) = &regdisp.pCallerContext ->Rax + iReg;
}
#if defined(TARGET_UNIX) && defined(HOST_UNIX)
if (IsAPXSupported())
{
ULONG64 **ppVolatileReg = &regdisp.volatileCurrContextPointers.R16;
for (iReg = 0; iReg < 16; iReg++)
{
*(ppVolatileReg+iReg) = &regdisp.pCurrentContext->R16 + iReg;
}
}
#endif // TARGET_UNIX
#elif defined(TARGET_ARM)
FILL_REGS(pCurrentContext->R0, 16);
FILL_REGS(pCallerContext->R0, 16);
Expand Down
47 changes: 46 additions & 1 deletion src/coreclr/inc/regdisp.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,33 @@ typedef struct _Arm64VolatileContextPointer
} Arm64VolatileContextPointer;
#endif //TARGET_ARM64

#if defined(TARGET_AMD64)
typedef struct _Amd64VolatileContextPointer
{
union {
struct {
PDWORD64 R16;
PDWORD64 R17;
PDWORD64 R18;
PDWORD64 R19;
PDWORD64 R20;
PDWORD64 R21;
PDWORD64 R22;
PDWORD64 R23;
PDWORD64 R24;
PDWORD64 R25;
PDWORD64 R26;
PDWORD64 R27;
PDWORD64 R28;
PDWORD64 R29;
PDWORD64 R30;
PDWORD64 R31;
};
PDWORD64 R[16];
};
} Amd64VolatileContextPointer;
#endif //TARGET_AMD64

#if defined(TARGET_LOONGARCH64)
typedef struct _LoongArch64VolatileContextPointer
{
Expand Down Expand Up @@ -253,6 +280,10 @@ struct REGDISPLAY : public REGDISPLAY_BASE {
LoongArch64VolatileContextPointer volatileCurrContextPointers;
#endif

#if defined(TARGET_AMD64)
Amd64VolatileContextPointer volatileCurrContextPointers;
#endif

#ifdef TARGET_RISCV64
RiscV64VolatileContextPointer volatileCurrContextPointers;
#endif
Expand Down Expand Up @@ -563,7 +594,11 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC
// Fill volatile context pointers. They can be used by GC in the case of the leaf frame
for (int i=0; i < 18; i++)
pRD->volatileCurrContextPointers.X[i] = &pctx->X[i];
#elif defined(TARGET_LOONGARCH64) // TARGET_ARM64
#elif defined(TARGET_AMD64) && defined(TARGET_UNIX) && defined(HOST_UNIX) // TARGET_ARM64
// Fill volatile context pointers. They can be used by GC in the case of the leaf frame
for (int i=0; i < 16; i++)
pRD->volatileCurrContextPointers.R[i] = &pctx->R[i];
#elif defined(TARGET_LOONGARCH64) // TARGET_ADM64 && TARGET_UNIX && HOST_UNIX
pRD->volatileCurrContextPointers.A0 = &pctx->A0;
pRD->volatileCurrContextPointers.A1 = &pctx->A1;
pRD->volatileCurrContextPointers.A2 = &pctx->A2;
Expand Down Expand Up @@ -663,6 +698,16 @@ inline size_t * getRegAddr (unsigned regNum, PTR_CONTEXT regs)
};

return (PTR_size_t)(PTR_BYTE(regs) + OFFSET_OF_REGISTERS[regNum]);
#elif defined(TARGET_AMD64) && defined(TARGET_UNIX) && defined(HOST_UNIX)
_ASSERTE(regNum < 32);
if (regNum < 16)
{
return (size_t *)&regs->Rax + regNum;
}
else
{
return (size_t *)&regs->R16 + (regNum - 16);
}
#elif defined(TARGET_AMD64)
_ASSERTE(regNum < 16);
return (size_t *)&regs->Rax + regNum;
Expand Down
34 changes: 17 additions & 17 deletions src/coreclr/nativeaot/Runtime/amd64/AsmOffsetsCpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@
// NOTE: the offsets MUST be in hex notation WITHOUT the 0x prefix

#ifndef UNIX_AMD64_ABI
PLAT_ASM_SIZEOF(250, ExInfo)
PLAT_ASM_SIZEOF(2d0, ExInfo)
PLAT_ASM_OFFSET(0, ExInfo, m_pPrevExInfo)
PLAT_ASM_OFFSET(8, ExInfo, m_pExContext)
PLAT_ASM_OFFSET(10, ExInfo, m_exception)
PLAT_ASM_OFFSET(18, ExInfo, m_kind)
PLAT_ASM_OFFSET(19, ExInfo, m_passNumber)
PLAT_ASM_OFFSET(1c, ExInfo, m_idxCurClause)
PLAT_ASM_OFFSET(20, ExInfo, m_frameIter)
PLAT_ASM_OFFSET(240, ExInfo, m_notifyDebuggerSP)
PLAT_ASM_OFFSET(2c0, ExInfo, m_notifyDebuggerSP)

PLAT_ASM_OFFSET(0, PInvokeTransitionFrame, m_RIP)
PLAT_ASM_OFFSET(8, PInvokeTransitionFrame, m_FramePointer)
PLAT_ASM_OFFSET(10, PInvokeTransitionFrame, m_pThread)
PLAT_ASM_OFFSET(18, PInvokeTransitionFrame, m_Flags)
PLAT_ASM_OFFSET(20, PInvokeTransitionFrame, m_PreservedRegs)

PLAT_ASM_SIZEOF(220, StackFrameIterator)
PLAT_ASM_SIZEOF(2A0, StackFrameIterator)
PLAT_ASM_OFFSET(10, StackFrameIterator, m_FramePointer)
PLAT_ASM_OFFSET(18, StackFrameIterator, m_ControlPC)
PLAT_ASM_OFFSET(20, StackFrameIterator, m_RegDisplay)
PLAT_ASM_OFFSET(210, StackFrameIterator, m_OriginalControlPC)
PLAT_ASM_OFFSET(218, StackFrameIterator, m_pPreviousTransitionFrame)
PLAT_ASM_OFFSET(290, StackFrameIterator, m_OriginalControlPC)
PLAT_ASM_OFFSET(298, StackFrameIterator, m_pPreviousTransitionFrame)

PLAT_ASM_SIZEOF(100, PAL_LIMITED_CONTEXT)
PLAT_ASM_OFFSET(0, PAL_LIMITED_CONTEXT, IP)
Expand All @@ -56,10 +56,10 @@ PLAT_ASM_OFFSET(0d0, PAL_LIMITED_CONTEXT, Xmm13)
PLAT_ASM_OFFSET(0e0, PAL_LIMITED_CONTEXT, Xmm14)
PLAT_ASM_OFFSET(0f0, PAL_LIMITED_CONTEXT, Xmm15)

PLAT_ASM_SIZEOF(130, REGDISPLAY)
PLAT_ASM_OFFSET(78, REGDISPLAY, SP)
PLAT_ASM_OFFSET(80, REGDISPLAY, IP)
PLAT_ASM_OFFSET(88, REGDISPLAY, SSP)
PLAT_ASM_SIZEOF(1b0, REGDISPLAY)
PLAT_ASM_OFFSET(f8, REGDISPLAY, SP)
PLAT_ASM_OFFSET(100, REGDISPLAY, IP)
PLAT_ASM_OFFSET(108, REGDISPLAY, SSP)

PLAT_ASM_OFFSET(18, REGDISPLAY, pRbx)
PLAT_ASM_OFFSET(20, REGDISPLAY, pRbp)
Expand All @@ -69,32 +69,32 @@ PLAT_ASM_OFFSET(58, REGDISPLAY, pR12)
PLAT_ASM_OFFSET(60, REGDISPLAY, pR13)
PLAT_ASM_OFFSET(68, REGDISPLAY, pR14)
PLAT_ASM_OFFSET(70, REGDISPLAY, pR15)
PLAT_ASM_OFFSET(90, REGDISPLAY, Xmm)
PLAT_ASM_OFFSET(110, REGDISPLAY, Xmm)

#else // !UNIX_AMD64_ABI

PLAT_ASM_SIZEOF(190, ExInfo)
PLAT_ASM_SIZEOF(210, ExInfo)
PLAT_ASM_OFFSET(0, ExInfo, m_pPrevExInfo)
PLAT_ASM_OFFSET(8, ExInfo, m_pExContext)
PLAT_ASM_OFFSET(10, ExInfo, m_exception)
PLAT_ASM_OFFSET(18, ExInfo, m_kind)
PLAT_ASM_OFFSET(19, ExInfo, m_passNumber)
PLAT_ASM_OFFSET(1c, ExInfo, m_idxCurClause)
PLAT_ASM_OFFSET(20, ExInfo, m_frameIter)
PLAT_ASM_OFFSET(188, ExInfo, m_notifyDebuggerSP)
PLAT_ASM_OFFSET(208, ExInfo, m_notifyDebuggerSP)

PLAT_ASM_OFFSET(0, PInvokeTransitionFrame, m_RIP)
PLAT_ASM_OFFSET(8, PInvokeTransitionFrame, m_FramePointer)
PLAT_ASM_OFFSET(10, PInvokeTransitionFrame, m_pThread)
PLAT_ASM_OFFSET(18, PInvokeTransitionFrame, m_Flags)
PLAT_ASM_OFFSET(20, PInvokeTransitionFrame, m_PreservedRegs)

PLAT_ASM_SIZEOF(168, StackFrameIterator)
PLAT_ASM_SIZEOF(1e8, StackFrameIterator)
PLAT_ASM_OFFSET(10, StackFrameIterator, m_FramePointer)
PLAT_ASM_OFFSET(18, StackFrameIterator, m_ControlPC)
PLAT_ASM_OFFSET(20, StackFrameIterator, m_RegDisplay)
PLAT_ASM_OFFSET(158, StackFrameIterator, m_OriginalControlPC)
PLAT_ASM_OFFSET(160, StackFrameIterator, m_pPreviousTransitionFrame)
PLAT_ASM_OFFSET(1d8, StackFrameIterator, m_OriginalControlPC)
PLAT_ASM_OFFSET(1e0, StackFrameIterator, m_pPreviousTransitionFrame)

PLAT_ASM_SIZEOF(50, PAL_LIMITED_CONTEXT)
PLAT_ASM_OFFSET(0, PAL_LIMITED_CONTEXT, IP)
Expand All @@ -110,8 +110,8 @@ PLAT_ASM_OFFSET(38, PAL_LIMITED_CONTEXT, R13)
PLAT_ASM_OFFSET(40, PAL_LIMITED_CONTEXT, R14)
PLAT_ASM_OFFSET(48, PAL_LIMITED_CONTEXT, R15)

PLAT_ASM_SIZEOF(88, REGDISPLAY)
PLAT_ASM_OFFSET(78, REGDISPLAY, SP)
PLAT_ASM_SIZEOF(108, REGDISPLAY)
PLAT_ASM_OFFSET(f8, REGDISPLAY, SP)

PLAT_ASM_OFFSET(18, REGDISPLAY, pRbx)
PLAT_ASM_OFFSET(20, REGDISPLAY, pRbp)
Expand Down
Loading
Loading