From 71bf02d77b2c38cd99e875ab92daa20b94fb777a Mon Sep 17 00:00:00 2001 From: Chris Speciale <26172437+dimensionscape@users.noreply.github.com> Date: Fri, 2 Oct 2026 18:46:32 -0400 Subject: [PATCH] Fix block row counts overflowing with HXCPP_GC_BIG_BLOCKS #1402 made BlockDataInfo's mUsedRows and mFraggedRows uint8_t, which fits the default 32k blocks (254 usable lines) but not big blocks (508). With HXCPP_GC_BIG_BLOCKS the counts wrap, the GC underestimates the live heap, and it ends up collecting on almost every new block. Use uint16_t for both (and for the allocator's mFraggedRows pointer), with static_asserts so they can't drop below IMMIX_USEFUL_LINES again. --- src/hx/gc/Immix.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index 9eb91603e..3310995ec 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef __EMSCRIPTEN__ #include @@ -754,11 +755,11 @@ struct BlockDataInfo HoleRange mRanges[MAX_HOLES]; uint8_t mHoles; - uint8_t mUsedRows; + uint16_t mUsedRows; uint16_t mMaxHoleSize; int mMoveScore; uint16_t mUsedBytes; - uint8_t mFraggedRows; + uint16_t mFraggedRows; bool mPinned; unsigned char mZeroed; bool mReclaimed; @@ -1418,6 +1419,13 @@ struct BlockDataInfo #endif }; +// A block's row counts run up to IMMIX_USEFUL_LINES: 254 with the default 32k blocks, but 508 with +// HXCPP_GC_BIG_BLOCKS' 64k blocks, more than a uint8_t holds. +static_assert(IMMIX_USEFUL_LINES <= std::numeric_limits::max(), + "BlockDataInfo::mUsedRows must hold IMMIX_USEFUL_LINES"); +static_assert(IMMIX_USEFUL_LINES <= std::numeric_limits::max(), + "BlockDataInfo::mFraggedRows must hold IMMIX_USEFUL_LINES"); + static bool SmallestFreeFirst(BlockDataInfo *inA, BlockDataInfo *inB) { return inA->mMaxHoleSize < inB->mMaxHoleSize; @@ -5768,7 +5776,7 @@ class LocalAllocator : public hx::StackContext uint8_t mCurrentHole; uint8_t mCurrentHoles; HoleRange *mCurrentRange; - uint8_t *mFraggedRows; + uint16_t *mFraggedRows; bool mMoreHoles; @@ -6259,7 +6267,7 @@ class LocalAllocator : public hx::StackContext // spaceOversize might have been set to zero for quick-termination of alloc. unsigned char* s{ spaceOversize }; if (s>spaceFirst && mFraggedRows) - *mFraggedRows += static_cast((s - spaceFirst) >> IMMIX_LINE_BITS); + *mFraggedRows += static_cast((s - spaceFirst) >> IMMIX_LINE_BITS); #else #ifdef HXCPP_ALIGN_ALLOC if (!(size_t{ spaceStart } & 0x4)) @@ -6296,7 +6304,7 @@ class LocalAllocator : public hx::StackContext } if (mFraggedRows && spaceEnd > spaceStart) { - *mFraggedRows += static_cast((spaceEnd - spaceStart) >> IMMIX_LINE_BITS); + *mFraggedRows += static_cast((spaceEnd - spaceStart) >> IMMIX_LINE_BITS); } #endif