mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-18 12:52:42 +00:00
make rawAlloc support alignment
This commit is contained in:
@@ -845,17 +845,24 @@ when defined(heaptrack):
|
||||
proc heaptrack_malloc(a: pointer, size: int) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
proc heaptrack_free(a: pointer) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
|
||||
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = MemAlign, extraSize: int = 0): pointer =
|
||||
when defined(nimTypeNames):
|
||||
inc(a.allocCounter)
|
||||
sysAssert(allocInv(a), "rawAlloc: begin")
|
||||
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
||||
var size = roundup(requestedSize, MemAlign)
|
||||
|
||||
# Calculate the actual size we need to allocate
|
||||
# If alignment > MemAlign, we need extra space to ensure we can align the result
|
||||
let alignmentOverhead = if alignment > MemAlign: alignment - 1 + extraSize else: 0
|
||||
let totalSize = requestedSize + alignmentOverhead
|
||||
|
||||
var size = roundup(totalSize, MemAlign)
|
||||
sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small")
|
||||
sysAssert(size >= requestedSize, "insufficient allocated size!")
|
||||
#c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
|
||||
|
||||
if size <= SmallChunkSize-smallChunkOverhead():
|
||||
# Force big chunk allocation for aligned allocations to avoid cell boundary issues
|
||||
if size <= SmallChunkSize-smallChunkOverhead() and alignment <= MemAlign:
|
||||
template fetchSharedCells(tc: PSmallChunk) =
|
||||
# Consumes cells from (potentially) foreign threads from `a.sharedFreeLists[s]`
|
||||
when defined(gcDestructors):
|
||||
@@ -965,6 +972,16 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
inc a.occ, c.size
|
||||
trackSize(c.size)
|
||||
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
||||
|
||||
# Handle alignment if specified
|
||||
if alignment > MemAlign:
|
||||
# We need to ensure that (result + extraSize) is aligned
|
||||
# So find the aligned address for user data, then back up by extraSize
|
||||
let userDataAddr = cast[int](result) + extraSize
|
||||
let alignedUserDataAddr = (userDataAddr + alignment - 1) and not (alignment - 1)
|
||||
# The result should be extraSize bytes before the aligned user data
|
||||
result = cast[pointer](alignedUserDataAddr - extraSize)
|
||||
|
||||
sysAssert(allocInv(a), "rawAlloc: end")
|
||||
when logAlloc: cprintf("var pointer_%p = alloc(%ld) # %p\n", result, requestedSize, addr a)
|
||||
when defined(heaptrack):
|
||||
@@ -1067,7 +1084,12 @@ when not defined(gcDestructors):
|
||||
(cast[ptr FreeCell](p).zeroField >% 1)
|
||||
else:
|
||||
var c = cast[PBigChunk](c)
|
||||
result = p == addr(c.data) and cast[ptr FreeCell](p).zeroField >% 1
|
||||
# For aligned allocations, p might be offset from addr(c.data), but should be within data bounds
|
||||
# Note: We cannot check zeroField/refcount as it may not be initialized yet when called from rawNewObj
|
||||
let dataStart = cast[int](addr(c.data))
|
||||
let dataEnd = dataStart + c.size - bigChunkOverhead()
|
||||
let pAddr = cast[int](p)
|
||||
result = (pAddr >= dataStart) and (pAddr < dataEnd)
|
||||
|
||||
proc prepareForInteriorPointerChecking(a: var MemRegion) {.inline.} =
|
||||
a.minLargeObj = lowGauge(a.root)
|
||||
|
||||
@@ -458,9 +458,12 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||
collectCT(gch)
|
||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||
# Use alignment from typ.base if available, otherwise use MemAlign
|
||||
let alignment = if typ.base != nil: max(typ.base.align, MemAlign) else: MemAlign
|
||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell), alignment, sizeof(Cell)))
|
||||
#gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small"
|
||||
gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||
# Check that the user data (after the Cell header) is properly aligned
|
||||
gcAssert((cast[int](cellToUsr(res)) and (alignment-1)) == 0, "newObj: 2")
|
||||
# now it is buffered in the ZCT
|
||||
res.typ = typ
|
||||
setFrameInfo(res)
|
||||
@@ -508,9 +511,12 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline, raise
|
||||
collectCT(gch)
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||
# Use alignment from typ.base if available, otherwise use MemAlign
|
||||
let alignment = if typ.base != nil: max(typ.base.align, MemAlign) else: MemAlign
|
||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell), alignment, sizeof(Cell)))
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
||||
sysAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||
# Check that the user data (after the Cell header) is properly aligned
|
||||
sysAssert((cast[int](cellToUsr(res)) and (alignment-1)) == 0, "newObj: 2")
|
||||
# now it is buffered in the ZCT
|
||||
res.typ = typ
|
||||
setFrameInfo(res)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
discard """
|
||||
ccodeCheck: "\\i @'NIM_ALIGN(128) NI mylocal1' .*"
|
||||
matrix: "--mm:refc -d:useGcAssert; --mm:orc"
|
||||
targets: "c cpp"
|
||||
output: "align ok"
|
||||
"""
|
||||
@@ -67,3 +68,46 @@ block: # bug #22419
|
||||
|
||||
f()()
|
||||
|
||||
|
||||
type Xxx = object
|
||||
v {.align: 128.}: byte
|
||||
|
||||
type Yyy = object
|
||||
v: byte
|
||||
v2: Xxx
|
||||
|
||||
for i in 0..<3:
|
||||
let x = new Yyy
|
||||
# echo "addr v2.v:", cast[uint](addr x.v2.v)
|
||||
doAssert cast[uint](addr x.v2.v) mod 128 == 0
|
||||
|
||||
let m = new Yyy
|
||||
m.v2.v = 42
|
||||
doAssert m.v2.v == 42
|
||||
m.v = 7
|
||||
doAssert m.v == 7
|
||||
|
||||
|
||||
type
|
||||
MyType16 = object
|
||||
a {.align(16).}: int
|
||||
|
||||
|
||||
var x: array[10, ref MyType16]
|
||||
for q in 0..500:
|
||||
for i in 0..<x.len:
|
||||
new x[i]
|
||||
x[i].a = q
|
||||
doAssert(cast[int](x[i]) mod alignof(MyType16) == 0)
|
||||
|
||||
type
|
||||
MyType32 = object
|
||||
a{.align(32).}: int
|
||||
|
||||
var y: array[10, ref MyType32]
|
||||
for q in 0..500:
|
||||
for i in 0..<y.len:
|
||||
new y[i]
|
||||
y[i].a = q
|
||||
doAssert(cast[int](y[i]) mod alignof(MyType32) == 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user