From 98c67dff7f493c94a15bad425b2c9caeb1670572 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 4 Mar 2026 16:14:13 +0800 Subject: [PATCH] fixes #25566; `{.align.}` pragma where each 16-byte-aligned (#25570) fixes #25566 (cherry picked from commit 8e2547a5e2a616380b71cdcbc922770fa11aafb8) --- doc/manual.md | 2 +- lib/system/alloc.nim | 4 +++- lib/system/cellsets.nim | 16 ++++++++++++++++ lib/system/gc.nim | 4 ++-- lib/system/mmdisp.nim | 15 --------------- tests/align/talign.nim | 1 - tests/align/talign2.nim | 10 ++++++++++ 7 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 tests/align/talign2.nim diff --git a/doc/manual.md b/doc/manual.md index 556fba538b..55fdd83a33 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -7906,7 +7906,7 @@ alignment requirement of the type are ignored. main() ``` -This pragma has no effect on the JS backend. +This pragma has no effect on the JavaScript backend and may significantly increase memory usage with the `--mm:refc` option. Noalias pragma diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 1c2706120e..c40f808b88 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -104,6 +104,8 @@ type zeroField: int # 0 means cell is not used (overlaid with typ field) # 1 means cell is manually managed pointer # otherwise a PNimType is stored in there + when sizeof(int) == 4: # 32-bit only + headerAlignPad: array[8, byte] # so addr(data) ≡ 8 (mod 16) else: alignment: int @@ -854,7 +856,7 @@ proc bigChunkAlignOffset(alignment: int): int {.inline.} = if alignment == 0: result = 0 else: - result = align(sizeof(BigChunk) + sizeof(Cell), alignment) - sizeof(BigChunk) - sizeof(Cell) + result = align(sizeof(BigChunk) + sizeof(FreeCell), alignment) - sizeof(BigChunk) - sizeof(FreeCell) proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = 0): pointer = when defined(nimTypeNames): diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index f68bfc9703..5348773107 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -48,7 +48,23 @@ when defined(gcOrc) or defined(gcArc) or defined(gcAtomicArc): when not declaredInScope(PageShift): include bitmasks +else: + type + RefCount = int + Cell {.pure.} = object + refcount: RefCount # the refcount and some flags + typ: PNimType + + when trackAllocationSource: + filename: cstring + line: int + when useCellIds: + id: int + when (not trackAllocationSource) and (not useCellIds) and sizeof(int) == 4: # 32-bit only + headerAlignPad: array[8, byte] # so addr(data) ≡ 8 (mod 16) + + PCell = ptr Cell type PPageDesc = ptr PageDesc diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 861e0704f5..8cc9c63878 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -460,7 +460,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = collectCT(gch) # Use alignment from typ.base if available, otherwise use MemAlign let alignment = if typ.kind == tyRef and typ.base != nil and - typ.base.align >= MemAlign: typ.base.align else: 0 + typ.base.align > 16: typ.base.align else: 0 var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell), alignment)) #gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small" # Check that the user data (after the Cell header) is properly aligned @@ -517,7 +517,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline, raise # Use alignment from typ.base if available, otherwise use MemAlign let alignment = if typ.kind == tyRef and typ.base != nil and - typ.base.align >= MemAlign: typ.base.align else: 0 + typ.base.align > 16: typ.base.align else: 0 var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell), alignment)) sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc") # Check that the user data (after the Cell header) is properly aligned diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index ce935ff8af..7fd61e0dc3 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -38,21 +38,6 @@ type PByte = ptr ByteArray PString = ptr string -when not defined(nimV2): - type - RefCount = int - - Cell {.pure.} = object - refcount: RefCount # the refcount and some flags - typ: PNimType - when trackAllocationSource: - filename: cstring - line: int - when useCellIds: - id: int - - PCell = ptr Cell - when declared(IntsPerTrunk): discard else: diff --git a/tests/align/talign.nim b/tests/align/talign.nim index 6397e31214..e1cb1539b2 100644 --- a/tests/align/talign.nim +++ b/tests/align/talign.nim @@ -168,4 +168,3 @@ for q in 0..100: new topArr[i] topArr[i].m.di.b = q doAssert(cast[uint](addr topArr[i].m.di) mod uint(alignof(DeepInner)) == 0) - diff --git a/tests/align/talign2.nim b/tests/align/talign2.nim new file mode 100644 index 0000000000..528ae4d134 --- /dev/null +++ b/tests/align/talign2.nim @@ -0,0 +1,10 @@ +discard """ + matrix: "--mm:refc -d:useGcAssert -d:useSysAssert; --mm:orc" +""" + +block: + type U = object + d {.align: 16.}: int8 + var e: seq[ref U] + for i in 0 ..< 10000: e.add(new U) + doAssert getTotalMem() <= 1052672 * 2 \ No newline at end of file