diff --git a/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp b/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp index a72663eba4b..2dddcbd7e25 100644 --- a/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp @@ -197,8 +197,12 @@ static Bool theMainInitFlag = false; // PRIVATE PROTOTYPES // ---------------------------------------------------------------------------- -/// @todo srj -- make this work for 8 -#define MEM_BOUND_ALIGNMENT 4 +// User data alignment, matches the 8 byte alignment that operator new guarantees on 32 bit MSVC +#define MEM_BOUND_ALIGNMENT 8 +static_assert((MEM_BOUND_ALIGNMENT & (MEM_BOUND_ALIGNMENT-1)) == 0, "MEM_BOUND_ALIGNMENT must be a power of two"); +#ifdef MEMORYPOOL_BOUNDINGWALL +static_assert(WALLSIZE % MEM_BOUND_ALIGNMENT == 0, "WALLSIZE must keep user data aligned"); +#endif static Int roundUpMemBound(Int i); static void *sysAllocate(Int numBytes); @@ -256,6 +260,7 @@ static void* sysAllocateDoNotZero(Int numBytes) void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); if (!p) throw ERROR_OUT_OF_MEMORY; + DEBUG_ASSERTCRASH(((size_t)p & (MEM_BOUND_ALIGNMENT-1)) == 0, ("system allocation is not %d byte aligned", MEM_BOUND_ALIGNMENT)); #ifdef MEMORYPOOL_DEBUG { USE_PERF_TIMER(MemoryPoolDebugging) @@ -481,6 +486,15 @@ class MemoryPoolSingleBlock #endif }; + +// Offset from a block to its user data, padded so that the user data stays aligned +#ifdef MEMORYPOOL_BOUNDINGWALL +static const Int SINGLEBLOCK_USERDATA_OFFSET = (sizeof(MemoryPoolSingleBlock) + WALLSIZE + MEM_BOUND_ALIGNMENT-1) & ~(MEM_BOUND_ALIGNMENT-1); +#else +static const Int SINGLEBLOCK_USERDATA_OFFSET = (sizeof(MemoryPoolSingleBlock) + MEM_BOUND_ALIGNMENT-1) & ~(MEM_BOUND_ALIGNMENT-1); +#endif +static_assert(SINGLEBLOCK_USERDATA_OFFSET % MEM_BOUND_ALIGNMENT == 0, "SINGLEBLOCK_USERDATA_OFFSET must keep user data aligned"); + // ---------------------------------------------------------------------------- class MemoryPoolBlob { @@ -551,11 +565,7 @@ inline void **BlockCheckpointInfo::getStacktraceInfo() { return m_stacktrace; } */ inline void* MemoryPoolSingleBlock::getUserDataNoDbg() { - char* p = ((char*)this) + sizeof(MemoryPoolSingleBlock); - #ifdef MEMORYPOOL_BOUNDINGWALL - p += WALLSIZE; - #endif - return (void*)p; + return ((char*)this) + SINGLEBLOCK_USERDATA_OFFSET; } /** @@ -567,6 +577,7 @@ inline void* MemoryPoolSingleBlock::getUserData() // yes, verify the block in this case for plain debug mode (not intense-verify mode) #ifdef MEMORYPOOL_DEBUG debugVerifyBlock(); + DEBUG_ASSERTCRASH(((size_t)getUserDataNoDbg() & (MEM_BOUND_ALIGNMENT-1)) == 0, ("user data is not %d byte aligned", MEM_BOUND_ALIGNMENT)); #endif return getUserDataNoDbg(); } @@ -577,9 +588,9 @@ inline void* MemoryPoolSingleBlock::getUserData() */ inline /*static*/ Int MemoryPoolSingleBlock::calcRawBlockSize(Int logicalSize) { - Int s = ::roundUpMemBound(logicalSize) + sizeof(MemoryPoolSingleBlock); + Int s = ::roundUpMemBound(logicalSize) + SINGLEBLOCK_USERDATA_OFFSET; #ifdef MEMORYPOOL_BOUNDINGWALL - s += WALLSIZE*2; + s += WALLSIZE; #endif return s; } @@ -922,11 +933,7 @@ void MemoryPoolSingleBlock::initBlock(Int logicalSize, MemoryPoolBlob *owningBlo DEBUG_ASSERTCRASH(pUserData, ("null pUserData")); if (!pUserData) return NULL; - char* p = ((char*)pUserData) - sizeof(MemoryPoolSingleBlock); - #ifdef MEMORYPOOL_BOUNDINGWALL - p -= WALLSIZE; - #endif - MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)p; + MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)(((char*)pUserData) - SINGLEBLOCK_USERDATA_OFFSET); // yes, verify the block in this case for plain debug mode (not intense-verify mode) #ifdef MEMORYPOOL_DEBUG block->debugVerifyBlock(); @@ -1539,7 +1546,7 @@ void MemoryPool::init(MemoryPoolFactory *factory, const char *poolName, Int allo { m_factory = factory; m_poolName = poolName; - m_allocationSize = ::roundUpMemBound(allocationSize); // round up to four-byte boundary + m_allocationSize = ::roundUpMemBound(allocationSize); m_initialAllocationCount = initialAllocationCount; m_overflowAllocationCount = overflowAllocationCount; m_usedBlocksInPool = 0; @@ -1575,7 +1582,7 @@ MemoryPool::~MemoryPool() */ MemoryPoolBlob* MemoryPool::createBlob(Int allocationCount) { - DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%MEM_BOUND_ALIGNMENT==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",MEM_BOUND_ALIGNMENT)); + DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%4==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",4)); MemoryPoolBlob* blob = new (::sysAllocate(sizeof(MemoryPoolBlob))) MemoryPoolBlob; // will throw on failure @@ -2662,7 +2669,7 @@ MemoryPool *MemoryPoolFactory::createMemoryPool(const char *poolName, Int alloca MemoryPool *pool = findMemoryPool(poolName); if (pool) { - DEBUG_ASSERTCRASH(allocationSize == pool->getAllocationSize(), ("pool size mismatch")); + DEBUG_ASSERTCRASH(::roundUpMemBound(allocationSize) == pool->getAllocationSize(), ("pool size mismatch")); return pool; } @@ -3563,7 +3570,7 @@ void* createW3DMemPool(const char *poolName, int allocationSize) ++theLinkTester; preMainInitMemoryManager(); MemoryPool* pool = TheMemoryPoolFactory->createMemoryPool(poolName, allocationSize, 0, 0); - DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == allocationSize, ("bad w3d pool")); + DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool")); return pool; } @@ -3571,7 +3578,7 @@ void* createW3DMemPool(const char *poolName, int allocationSize) void* allocateFromW3DMemPool(void* pool, int allocationSize) { DEBUG_ASSERTCRASH(pool, ("pool is null")); - DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); + DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); return ((MemoryPool*)pool)->allocateBlock("allocateFromW3DMemPool"); } @@ -3579,7 +3586,7 @@ void* allocateFromW3DMemPool(void* pool, int allocationSize) void* allocateFromW3DMemPool(void* pool, int allocationSize, const char* msg, int unused) { DEBUG_ASSERTCRASH(pool, ("pool is null")); - DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); + DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); return ((MemoryPool*)pool)->allocateBlock(msg); } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp index ee9e3dd6157..9dbecec3127 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp @@ -199,8 +199,12 @@ static Bool theMainInitFlag = false; // PRIVATE PROTOTYPES // ---------------------------------------------------------------------------- -/// @todo srj -- make this work for 8 -#define MEM_BOUND_ALIGNMENT 4 +// User data alignment, matches the 8 byte alignment that operator new guarantees on 32 bit MSVC +#define MEM_BOUND_ALIGNMENT 8 +static_assert((MEM_BOUND_ALIGNMENT & (MEM_BOUND_ALIGNMENT-1)) == 0, "MEM_BOUND_ALIGNMENT must be a power of two"); +#ifdef MEMORYPOOL_BOUNDINGWALL +static_assert(WALLSIZE % MEM_BOUND_ALIGNMENT == 0, "WALLSIZE must keep user data aligned"); +#endif static Int roundUpMemBound(Int i); static void *sysAllocateDoNotZero(Int numBytes); @@ -236,6 +240,7 @@ static void* sysAllocateDoNotZero(Int numBytes) void* p = ::GlobalAlloc(GMEM_FIXED, numBytes); if (!p) throw ERROR_OUT_OF_MEMORY; + DEBUG_ASSERTCRASH(((size_t)p & (MEM_BOUND_ALIGNMENT-1)) == 0, ("system allocation is not %d byte aligned", MEM_BOUND_ALIGNMENT)); #ifdef MEMORYPOOL_DEBUG { USE_PERF_TIMER(MemoryPoolDebugging) @@ -461,6 +466,15 @@ class MemoryPoolSingleBlock #endif }; + +// Offset from a block to its user data, padded so that the user data stays aligned +#ifdef MEMORYPOOL_BOUNDINGWALL +static const Int SINGLEBLOCK_USERDATA_OFFSET = (sizeof(MemoryPoolSingleBlock) + WALLSIZE + MEM_BOUND_ALIGNMENT-1) & ~(MEM_BOUND_ALIGNMENT-1); +#else +static const Int SINGLEBLOCK_USERDATA_OFFSET = (sizeof(MemoryPoolSingleBlock) + MEM_BOUND_ALIGNMENT-1) & ~(MEM_BOUND_ALIGNMENT-1); +#endif +static_assert(SINGLEBLOCK_USERDATA_OFFSET % MEM_BOUND_ALIGNMENT == 0, "SINGLEBLOCK_USERDATA_OFFSET must keep user data aligned"); + // ---------------------------------------------------------------------------- class MemoryPoolBlob { @@ -531,11 +545,7 @@ inline void **BlockCheckpointInfo::getStacktraceInfo() { return m_stacktrace; } */ inline void* MemoryPoolSingleBlock::getUserDataNoDbg() { - char* p = ((char*)this) + sizeof(MemoryPoolSingleBlock); - #ifdef MEMORYPOOL_BOUNDINGWALL - p += WALLSIZE; - #endif - return (void*)p; + return ((char*)this) + SINGLEBLOCK_USERDATA_OFFSET; } /** @@ -547,6 +557,7 @@ inline void* MemoryPoolSingleBlock::getUserData() // yes, verify the block in this case for plain debug mode (not intense-verify mode) #ifdef MEMORYPOOL_DEBUG debugVerifyBlock(); + DEBUG_ASSERTCRASH(((size_t)getUserDataNoDbg() & (MEM_BOUND_ALIGNMENT-1)) == 0, ("user data is not %d byte aligned", MEM_BOUND_ALIGNMENT)); #endif return getUserDataNoDbg(); } @@ -557,9 +568,9 @@ inline void* MemoryPoolSingleBlock::getUserData() */ inline /*static*/ Int MemoryPoolSingleBlock::calcRawBlockSize(Int logicalSize) { - Int s = ::roundUpMemBound(logicalSize) + sizeof(MemoryPoolSingleBlock); + Int s = ::roundUpMemBound(logicalSize) + SINGLEBLOCK_USERDATA_OFFSET; #ifdef MEMORYPOOL_BOUNDINGWALL - s += WALLSIZE*2; + s += WALLSIZE; #endif return s; } @@ -903,11 +914,7 @@ void MemoryPoolSingleBlock::initBlock(Int logicalSize, MemoryPoolBlob *owningBlo DEBUG_ASSERTCRASH(pUserData, ("null pUserData")); if (!pUserData) return nullptr; - char* p = ((char*)pUserData) - sizeof(MemoryPoolSingleBlock); - #ifdef MEMORYPOOL_BOUNDINGWALL - p -= WALLSIZE; - #endif - MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)p; + MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)(((char*)pUserData) - SINGLEBLOCK_USERDATA_OFFSET); // yes, verify the block in this case for plain debug mode (not intense-verify mode) #ifdef MEMORYPOOL_DEBUG block->debugVerifyBlock(); @@ -1520,7 +1527,7 @@ void MemoryPool::init(MemoryPoolFactory *factory, const char *poolName, Int allo { m_factory = factory; m_poolName = poolName; - m_allocationSize = ::roundUpMemBound(allocationSize); // round up to four-byte boundary + m_allocationSize = ::roundUpMemBound(allocationSize); m_initialAllocationCount = initialAllocationCount; m_overflowAllocationCount = overflowAllocationCount; m_usedBlocksInPool = 0; @@ -1556,7 +1563,7 @@ MemoryPool::~MemoryPool() */ MemoryPoolBlob* MemoryPool::createBlob(Int allocationCount) { - DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%MEM_BOUND_ALIGNMENT==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",MEM_BOUND_ALIGNMENT)); + DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%4==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",4)); MemoryPoolBlob* blob = new (::sysAllocateDoNotZero(sizeof(MemoryPoolBlob))) MemoryPoolBlob; // will throw on failure @@ -2259,7 +2266,7 @@ void *DynamicMemoryAllocator::allocateBytesDoNotZeroImplementation(Int numBytes #if defined(RTS_DEBUG) // check alignment - if (unsigned(result)&3) + if ((size_t)result & (MEM_BOUND_ALIGNMENT-1)) throw ERROR_OUT_OF_MEMORY; #endif @@ -2662,7 +2669,7 @@ MemoryPool *MemoryPoolFactory::createMemoryPool(const char *poolName, Int alloca MemoryPool *pool = findMemoryPool(poolName); if (pool) { - DEBUG_ASSERTCRASH(allocationSize == pool->getAllocationSize(), ("pool size mismatch")); + DEBUG_ASSERTCRASH(::roundUpMemBound(allocationSize) == pool->getAllocationSize(), ("pool size mismatch")); return pool; } @@ -3562,7 +3569,7 @@ void* createW3DMemPool(const char *poolName, int allocationSize) ++theLinkTester; preMainInitMemoryManager(); MemoryPool* pool = TheMemoryPoolFactory->createMemoryPool(poolName, allocationSize, 0, 0); - DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == allocationSize, ("bad w3d pool")); + DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool")); return pool; } @@ -3570,7 +3577,7 @@ void* createW3DMemPool(const char *poolName, int allocationSize) void* allocateFromW3DMemPool(void* pool, int allocationSize) { DEBUG_ASSERTCRASH(pool, ("pool is null")); - DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); + DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); return ((MemoryPool*)pool)->allocateBlock("allocateFromW3DMemPool"); } @@ -3578,7 +3585,7 @@ void* allocateFromW3DMemPool(void* pool, int allocationSize) void* allocateFromW3DMemPool(void* pool, int allocationSize, const char* msg, int unused) { DEBUG_ASSERTCRASH(pool, ("pool is null")); - DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); + DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == ::roundUpMemBound(allocationSize), ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName())); return ((MemoryPool*)pool)->allocateBlock(msg); }