mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-08 22:47:27 +00:00
forward type alignment information to seqs (#12430)
This commit is contained in:
@@ -1301,9 +1301,10 @@ proc genNewSeq(p: BProc, e: PNode) =
|
||||
initLocExpr(p, e[2], b)
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
let seqtype = skipTypes(e[1].typ, abstractVarRange)
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
[a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
[a.rdLoc, b.rdLoc,
|
||||
getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
else:
|
||||
let lenIsZero = optNilSeqs notin p.options and
|
||||
e[2].kind == nkIntLit and e[2].intVal == 0
|
||||
@@ -1316,9 +1317,10 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
initLocExpr(p, e[1], a)
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
getSeqPayloadType(p.module, seqtype),
|
||||
])
|
||||
else:
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
@@ -1425,7 +1427,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
let l = intLiteral(n.len)
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
let seqtype = n.typ
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
[rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
else:
|
||||
@@ -1456,7 +1458,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
let L = toInt(lengthOrd(p.config, n[1].typ))
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
let seqtype = n.typ
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
|
||||
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
|
||||
[rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon),
|
||||
getSeqPayloadType(p.module, seqtype)])
|
||||
else:
|
||||
@@ -2224,9 +2226,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
|
||||
of mAlignOf:
|
||||
let t = e[1].typ.skipTypes({tyTypeDesc})
|
||||
if not p.module.compileToCpp:
|
||||
p.module.includeHeader("<stdalign.h>")
|
||||
putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
|
||||
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)])
|
||||
of mOffsetOf:
|
||||
var dotExpr: PNode
|
||||
block findDotExpr:
|
||||
|
||||
@@ -999,11 +999,14 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
|
||||
let nameHcr = tiNameForHcr(m, name)
|
||||
|
||||
var size: Rope
|
||||
if tfIncompleteStruct in typ.flags: size = rope"void*"
|
||||
else: size = getTypeDesc(m, origType)
|
||||
if tfIncompleteStruct in typ.flags:
|
||||
size = rope"void*"
|
||||
else:
|
||||
size = getTypeDesc(m, origType)
|
||||
m.s[cfsTypeInit3].addf(
|
||||
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
|
||||
[nameHcr, size, rope(nimtypeKind), base])
|
||||
"$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n",
|
||||
[nameHcr, size, rope(nimtypeKind), base]
|
||||
)
|
||||
# compute type flags for GC optimization
|
||||
var flags = 0
|
||||
if not containsGarbageCollectedRef(typ): flags = flags or 1
|
||||
@@ -1313,10 +1316,7 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
|
||||
let traceImpl = genHook(m, t, info, attachedTrace)
|
||||
let disposeImpl = genHook(m, t, info, attachedDispose)
|
||||
|
||||
m.s[cfsTypeInit3].addf("$1.destructor = (void*)$2; $1.size = sizeof($3);$n" &
|
||||
"$1.name = $4;$n" &
|
||||
"$1.traceImpl = (void*)$5;$n" &
|
||||
"$1.disposeImpl = (void*)$6;$n", [
|
||||
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6;", [
|
||||
name, destroyImpl, getTypeDesc(m, t), typeName,
|
||||
traceImpl, disposeImpl])
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimnomagic64")
|
||||
defineSymbol("nimNewShiftOps")
|
||||
defineSymbol("nimHasCursor")
|
||||
defineSymbol("nimAlignPragma")
|
||||
defineSymbol("nimHasExceptionsQuery")
|
||||
defineSymbol("nimHasIsNamedTuple")
|
||||
defineSymbol("nimHashOrdinalFixed")
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
## what this module allows you to do.
|
||||
##
|
||||
## Note that even though ``Any`` and its operations hide the nasty low level
|
||||
## details from its clients, it remains inherently unsafe! Also, Nim's
|
||||
## details from its clients, it remains inherently unsafe! Also, Nim's
|
||||
## runtime type information will evolve and may eventually be deprecated.
|
||||
## As an alternative approach to programmatically understanding and
|
||||
## manipulating types, consider using the `macros <macros.html>`_ package to
|
||||
## work with the types' AST representation at compile time. See, for example,
|
||||
## the `getTypeImpl proc<macros.html#getTypeImpl,NimNode>`_. As an alternative
|
||||
## the `getTypeImpl proc<macros.html#getTypeImpl,NimNode>`_. As an alternative
|
||||
## approach to storing arbitrary types at runtime, consider using generics.
|
||||
##
|
||||
##
|
||||
##
|
||||
|
||||
{.push hints: off.}
|
||||
|
||||
@@ -98,7 +98,7 @@ else:
|
||||
proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
|
||||
proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.
|
||||
importCompilerProc.}
|
||||
proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.}
|
||||
proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.}
|
||||
proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
|
||||
proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
|
||||
@@ -180,7 +180,7 @@ proc extendSeq*(x: Any) =
|
||||
## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
|
||||
assert x.rawType.kind == tySequence
|
||||
var y = cast[ptr PGenSeq](x.value)[]
|
||||
var z = incrSeq(y, x.rawType.base.size)
|
||||
var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align)
|
||||
# 'incrSeq' already freed the memory for us and copied over the RC!
|
||||
# So we simply copy the raw pointer into 'x.value':
|
||||
cast[ppointer](x.value)[] = z
|
||||
@@ -195,6 +195,9 @@ proc skipRange(x: PNimType): PNimType {.inline.} =
|
||||
result = x
|
||||
if result.kind == tyRange: result = result.base
|
||||
|
||||
proc align(address, alignment: int): int =
|
||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||
|
||||
proc `[]`*(x: Any, i: int): Any =
|
||||
## accessor for an any `x` that represents an array or a sequence.
|
||||
case x.rawType.kind
|
||||
@@ -209,7 +212,7 @@ proc `[]`*(x: Any, i: int): Any =
|
||||
var bs = x.rawType.base.size
|
||||
if i >=% cast[PGenSeq](s).len:
|
||||
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
|
||||
return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
|
||||
return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
|
||||
else: assert false
|
||||
|
||||
proc `[]=`*(x: Any, i: int, y: Any) =
|
||||
@@ -228,7 +231,7 @@ proc `[]=`*(x: Any, i: int, y: Any) =
|
||||
if i >=% cast[PGenSeq](s).len:
|
||||
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
|
||||
assert y.rawType == x.rawType.base
|
||||
genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
|
||||
genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
|
||||
else: assert false
|
||||
|
||||
proc len*(x: Any): int =
|
||||
|
||||
@@ -477,7 +477,6 @@ typedef char* NCSTRING;
|
||||
#define ALLOC_0(size) calloc(1, size)
|
||||
#define DL_ALLOC_0(size) dlcalloc(1, size)
|
||||
|
||||
#define GenericSeqSize sizeof(TGenericSeq)
|
||||
#define paramCount() cmdCount
|
||||
|
||||
// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
|
||||
@@ -546,8 +545,10 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, ""
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define NIM_ALIGN(x) __declspec(align(x))
|
||||
# define NIM_ALIGNOF(x) __alignof(x)
|
||||
#else
|
||||
# define NIM_ALIGN(x) __attribute__((aligned(x)))
|
||||
# define NIM_ALIGNOF(x) __alignof__(x)
|
||||
#endif
|
||||
|
||||
/* ---------------- platform specific includes ----------------------- */
|
||||
|
||||
@@ -93,8 +93,7 @@ else:
|
||||
when useNSGetEnviron:
|
||||
var gEnv = NSGetEnviron()[]
|
||||
var i = 0
|
||||
while true:
|
||||
if gEnv[i] == nil: break
|
||||
while gEnv[i] != nil:
|
||||
add environment, $gEnv[i]
|
||||
inc(i)
|
||||
envComputed = true
|
||||
|
||||
@@ -514,6 +514,7 @@ when not defined(js) and not defined(nimSeqsV2):
|
||||
len, reserved: int
|
||||
when defined(gogc):
|
||||
elemSize: int
|
||||
elemAlign: int
|
||||
PGenericSeq {.exportc.} = ptr TGenericSeq
|
||||
# len and space without counting the terminating zero:
|
||||
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
|
||||
@@ -1123,6 +1124,13 @@ elif hostOS != "standalone":
|
||||
var programResult* {.compilerproc, exportc: "nim_program_result".}: int
|
||||
## deprecated, prefer ``quit``
|
||||
|
||||
proc align(address, alignment: int): int =
|
||||
if alignment == 0: # Actually, this is illegal. This branch exists to actively
|
||||
# hide problems.
|
||||
result = address
|
||||
else:
|
||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||
|
||||
when defined(nimdoc):
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
|
||||
## Stops the program immediately with an exit code.
|
||||
@@ -1698,6 +1706,7 @@ when not defined(js) and defined(nimV2):
|
||||
TNimType {.compilerproc.} = object
|
||||
destructor: pointer
|
||||
size: int
|
||||
align: int
|
||||
name: cstring
|
||||
traceImpl: pointer
|
||||
disposeImpl: pointer
|
||||
@@ -1709,7 +1718,6 @@ when notJSnotNims and defined(nimSeqsV2):
|
||||
|
||||
{.pop.}
|
||||
|
||||
|
||||
when notJSnotNims:
|
||||
proc writeStackTrace*() {.tags: [], gcsafe, raises: [].}
|
||||
## Writes the current stack trace to ``stderr``. This is only works
|
||||
@@ -1988,8 +1996,8 @@ proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} =
|
||||
result = if x < 0: -x else: x
|
||||
{.pop.}
|
||||
|
||||
|
||||
when not defined(js):
|
||||
|
||||
proc likelyProc(val: bool): bool {.importc: "NIM_LIKELY", nodecl, noSideEffect.}
|
||||
proc unlikelyProc(val: bool): bool {.importc: "NIM_UNLIKELY", nodecl, noSideEffect.}
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ type
|
||||
data: TrunkBuckets
|
||||
|
||||
type
|
||||
AlignType = BiggestFloat
|
||||
FreeCell {.final, pure.} = object
|
||||
next: ptr FreeCell # next free cell in chunk (overlaid with refcount)
|
||||
when not defined(gcDestructors):
|
||||
@@ -68,16 +67,20 @@ type
|
||||
freeList: ptr FreeCell
|
||||
free: int # how many bytes remain
|
||||
acc: int # accumulator for small object allocation
|
||||
when defined(cpu32):
|
||||
align: int
|
||||
data: AlignType # start of usable memory
|
||||
when defined(nimAlignPragma):
|
||||
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
|
||||
else:
|
||||
data: UncheckedArray[byte]
|
||||
|
||||
BigChunk = object of BaseChunk # not necessarily > PageSize!
|
||||
next, prev: PBigChunk # chunks of the same (or bigger) size
|
||||
data: AlignType # start of usable memory
|
||||
when defined(nimAlignPragma):
|
||||
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
|
||||
else:
|
||||
data: UncheckedArray[byte]
|
||||
|
||||
template smallChunkOverhead(): untyped = sizeof(SmallChunk)-sizeof(AlignType)
|
||||
template bigChunkOverhead(): untyped = sizeof(BigChunk)-sizeof(AlignType)
|
||||
template smallChunkOverhead(): untyped = sizeof(SmallChunk)
|
||||
template bigChunkOverhead(): untyped = sizeof(BigChunk)
|
||||
|
||||
# ------------- chunk table ---------------------------------------------------
|
||||
# We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk
|
||||
|
||||
@@ -66,17 +66,16 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
|
||||
cast[PGenericSeq](ss).len = seq.len
|
||||
unsureAsgnRef(x, ss)
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
copyMem(cast[pointer](dst +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize),
|
||||
seq.len * mt.base.size)
|
||||
copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)),
|
||||
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)),
|
||||
seq.len *% mt.base.size)
|
||||
else:
|
||||
unsureAsgnRef(x, newSeq(mt, seq.len))
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
for i in 0..seq.len-1:
|
||||
genericAssignAux(
|
||||
cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
|
||||
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
|
||||
mt.base, shallow)
|
||||
of tyObject:
|
||||
var it = mt.base
|
||||
|
||||
@@ -214,7 +214,7 @@ when not usesDestructors:
|
||||
x[] = nil
|
||||
else:
|
||||
var ss = cast[NimString](s2)
|
||||
var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize))
|
||||
var ns = cast[NimString](alloc(t.region, GenericSeqSize + ss.len+1))
|
||||
copyMem(ns, ss, ss.len+1 + GenericSeqSize)
|
||||
x[] = ns
|
||||
else:
|
||||
@@ -239,7 +239,7 @@ when not usesDestructors:
|
||||
else:
|
||||
sysAssert(dest != nil, "dest == nil")
|
||||
if mode == mStore:
|
||||
x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize)
|
||||
x[] = alloc0(t.region, align(GenericSeqSize, mt.base.align) +% seq.len *% mt.base.size)
|
||||
else:
|
||||
unsureAsgnRef(x, newSeq(mt, seq.len))
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
@@ -248,9 +248,9 @@ when not usesDestructors:
|
||||
dstseq.reserved = seq.len
|
||||
for i in 0..seq.len-1:
|
||||
storeAux(
|
||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i*% mt.base.size),
|
||||
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +%
|
||||
i *% mt.base.size),
|
||||
mt.base, t, mode)
|
||||
if mode != mStore: dealloc(t.region, s2)
|
||||
of tyObject:
|
||||
@@ -452,4 +452,3 @@ proc ready*[TMsg](c: var Channel[TMsg]): bool =
|
||||
## new messages.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
result = q.ready
|
||||
|
||||
|
||||
@@ -108,9 +108,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
|
||||
var dst = cast[ByteAddress](cast[PPointer](dest)[])
|
||||
for i in 0..seq.len-1:
|
||||
genericDeepCopyAux(
|
||||
cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
|
||||
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
|
||||
mt.base, tab)
|
||||
of tyObject:
|
||||
# we need to copy m_type field for tyObject, as it could be empty for
|
||||
|
||||
@@ -339,8 +339,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||
var s = cast[PGenericSeq](d)
|
||||
if s != nil:
|
||||
for i in 0..s.len-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||
GenericSeqSize), cell.typ.base, op)
|
||||
forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op)
|
||||
else: discard
|
||||
|
||||
proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
|
||||
@@ -444,7 +443,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = len * typ.base.size + GenericSeqSize
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
@@ -480,7 +479,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
let size = len * typ.base.size + GenericSeqSize
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObjRC1(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
@@ -495,11 +494,13 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||
sysAssert(allocInv(gch.region), "growObj begin")
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||
var elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
var elemSize,elemAlign = 1
|
||||
if ol.typ.kind != tyString:
|
||||
elemSize = ol.typ.base.size
|
||||
elemAlign = ol.typ.base.align
|
||||
incTypeSize ol.typ, newsize
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize
|
||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||
zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)),
|
||||
newsize-oldsize)
|
||||
|
||||
@@ -291,8 +291,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||
var s = cast[PGenericSeq](d)
|
||||
if s != nil:
|
||||
for i in 0..s.len-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||
GenericSeqSize), cell.typ.base, op)
|
||||
forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op)
|
||||
else: discard
|
||||
|
||||
{.push stackTrace: off, profiler:off.}
|
||||
@@ -359,7 +358,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||
let size = addInt(align(GenericSeqSize, typ.base.align), mulInt(len, typ.base.size))
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
@@ -378,11 +377,13 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||
var elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
var elemSize, elemAlign = 1
|
||||
if ol.typ.kind != tyString:
|
||||
elemSize = ol.typ.base.size
|
||||
elemAlign = ol.typ.base.align
|
||||
incTypeSize ol.typ, newsize
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize
|
||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||
newsize-oldsize)
|
||||
|
||||
@@ -78,8 +78,11 @@ template decTypeSize(cell, t) =
|
||||
when defined(nimTypeNames):
|
||||
if t.kind in {tyString, tySequence}:
|
||||
let cap = cast[PGenericSeq](cellToUsr(cell)).space
|
||||
let size = if t.kind == tyString: cap+1+GenericSeqSize
|
||||
else: cap * t.base.size + GenericSeqSize
|
||||
let size =
|
||||
if t.kind == tyString:
|
||||
cap + 1 + GenericSeqSize
|
||||
else:
|
||||
align(GenericSeqSize, t.base.align) + cap * t.base.size
|
||||
atomicDec t.sizes, size+sizeof(Cell)
|
||||
else:
|
||||
atomicDec t.sizes, t.base.size+sizeof(Cell)
|
||||
|
||||
@@ -259,8 +259,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||
var s = cast[PGenericSeq](d)
|
||||
if s != nil:
|
||||
for i in 0..s.len-1:
|
||||
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||
GenericSeqSize), cell.typ.base, op)
|
||||
forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op)
|
||||
else: discard
|
||||
|
||||
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||
@@ -308,14 +307,14 @@ when not defined(nimSeqsV2):
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = len * typ.base.size + GenericSeqSize
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
let size = len * typ.base.size + GenericSeqSize
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
@@ -329,11 +328,13 @@ when not defined(nimSeqsV2):
|
||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||
|
||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||
var elemSize = 1
|
||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||
var elemSize, elemAlign = 1
|
||||
if ol.typ.kind != tyString:
|
||||
elemSize = ol.typ.base.size
|
||||
elemAlign = ol.typ.base.align
|
||||
incTypeSize ol.typ, newsize
|
||||
|
||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize
|
||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(Cell)),
|
||||
newsize-oldsize)
|
||||
|
||||
@@ -321,7 +321,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
let size = roundup(len * typ.base.size + GenericSeqSize, MemAlign)
|
||||
let size = roundup(align(GenericSeqSize, typ.base.align) + len * typ.base.size, MemAlign)
|
||||
result = rawNewSeq(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
@@ -348,7 +348,8 @@ proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer =
|
||||
result = rawNewSeq(sh.region[], typ,
|
||||
roundup(newsize, MemAlign))
|
||||
let elemSize = if typ.kind == tyString: 1 else: typ.base.size
|
||||
let oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||
let elemAlign = if typ.kind == tyString: 1 else: typ.base.align
|
||||
let oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize
|
||||
zeroMem(result +! oldsize, newsize-oldsize)
|
||||
copyMem(result, old, oldsize)
|
||||
dealloc(sh.region[], old, roundup(oldsize, MemAlign))
|
||||
|
||||
@@ -90,6 +90,7 @@ type
|
||||
when defined(gcHooks):
|
||||
head*: pointer
|
||||
size*: int
|
||||
align*: int
|
||||
kind: TNimKind
|
||||
flags: set[TNimTypeFlag]
|
||||
base*: ptr TNimType
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
|
||||
|
||||
proc boehmGCinit {.importc: "GC_init", boehmGC.}
|
||||
proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
|
||||
proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
|
||||
@@ -96,6 +98,7 @@ proc initGC() =
|
||||
proc boehmgc_finalizer(obj: pointer, typedFinalizer: (proc(x: pointer) {.cdecl.})) =
|
||||
typedFinalizer(obj)
|
||||
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
if ntfNoRefs in typ.flags: result = allocAtomic(size)
|
||||
else: result = alloc(size)
|
||||
@@ -103,7 +106,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
boehmRegisterFinalizer(result, boehmgc_finalizer, typ.finalizer, nil, nil)
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, len * typ.base.size + GenericSeqSize)
|
||||
result = newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
{.pop.}
|
||||
@@ -135,4 +138,3 @@ proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||
proc deallocOsPages() {.inline.} = discard
|
||||
|
||||
include "system/cellsets"
|
||||
|
||||
|
||||
@@ -101,28 +101,32 @@ proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
writebarrierptr(addr(result), newObj(typ, size))
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
writebarrierptr(addr(result), newObj(typ, len * typ.base.size + GenericSeqSize))
|
||||
writebarrierptr(addr(result), newObj(typ, align(GenericSeqSize, typ.base.align) + len * typ.base.size))
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
cast[PGenericSeq](result).elemSize = typ.base.size
|
||||
cast[PGenericSeq](result).elemAlign = typ.base.align
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
writebarrierptr(addr(result), newSeq(typ, len))
|
||||
|
||||
proc nimNewSeqOfCap(typ: PNimType, cap: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, cap * typ.base.size + GenericSeqSize)
|
||||
result = newObj(typ, align(GenericSeqSize, typ.base.align) + cap * typ.base.size)
|
||||
cast[PGenericSeq](result).len = 0
|
||||
cast[PGenericSeq](result).reserved = cap
|
||||
cast[PGenericSeq](result).elemSize = typ.base.size
|
||||
cast[PGenericSeq](result).elemAlign = typ.base.align
|
||||
|
||||
proc typedMemMove(dest: pointer, src: pointer, size: uint) {.importc: "typedmemmove", dynlib: goLib.}
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer =
|
||||
# the Go GC doesn't have a realloc
|
||||
let old = cast[PGenericSeq](old)
|
||||
var metadataOld = cast[PGenericSeq](old)
|
||||
if metadataOld.elemSize == 0:
|
||||
metadataOld.elemSize = 1
|
||||
let oldsize = cast[PGenericSeq](old).len * cast[PGenericSeq](old).elemSize + GenericSeqSize
|
||||
|
||||
let oldsize = align(GenericSeqSize, old.elemAlign) + old.len * old.elemSize
|
||||
writebarrierptr(addr(result), goMalloc(newsize.uint))
|
||||
typedMemMove(result, old, oldsize.uint)
|
||||
|
||||
@@ -149,4 +153,3 @@ proc alloc0(r: var MemRegion, size: int): pointer =
|
||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||
proc deallocOsPages() {.inline.} = discard
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
result = newObj(typ, len * typ.base.size + GenericSeqSize)
|
||||
result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
{.pop.}
|
||||
|
||||
@@ -46,7 +46,7 @@ const
|
||||
PageSize = 1 shl PageShift
|
||||
PageMask = PageSize-1
|
||||
|
||||
MemAlign = 8 # also minimal allocatable memory block
|
||||
MemAlign = 16 # also minimal allocatable memory block
|
||||
|
||||
BitsPerPage = PageSize div MemAlign
|
||||
UnitsPerPage = BitsPerPage div (sizeof(int)*8)
|
||||
@@ -108,7 +108,7 @@ when not declared(nimNewSeqOfCap) and not defined(nimSeqsV2):
|
||||
let s = cap * typ.base.size # newStr already adds GenericSeqSize
|
||||
result = newStr(typ, s, ntfNoRefs notin typ.base.flags)
|
||||
else:
|
||||
let s = cap * typ.base.size + GenericSeqSize
|
||||
let s = align(GenericSeqSize, typ.base.align) + cap * typ.base.size
|
||||
when declared(newObjNoInit):
|
||||
result = if ntfNoRefs in typ.base.flags: newObjNoInit(typ, s) else: newObj(typ, s)
|
||||
else:
|
||||
|
||||
@@ -172,7 +172,7 @@ when not defined(useNimRtl):
|
||||
|
||||
template payloadPtr(x: untyped): untyped = cast[PGenericSeq](x).p
|
||||
else:
|
||||
const payloadOffset = GenericSeqSize
|
||||
const payloadOffset = GenericSeqSize ## the payload offset always depends on the alignment of the member type.
|
||||
template payloadPtr(x: untyped): untyped = x
|
||||
|
||||
proc reprSequence(result: var string, p: pointer, typ: PNimType,
|
||||
@@ -185,7 +185,7 @@ when not defined(useNimRtl):
|
||||
var bs = typ.base.size
|
||||
for i in 0..cast[PGenericSeq](p).len-1:
|
||||
if i > 0: add result, ", "
|
||||
reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + payloadOffset + i*bs),
|
||||
reprAux(result, cast[pointer](cast[ByteAddress](payloadPtr(p)) + align(payloadOffset, typ.align) + i*bs),
|
||||
typ.base, cl)
|
||||
add result, "]"
|
||||
|
||||
|
||||
@@ -31,27 +31,27 @@ const nimSeqVersion {.core.} = 2
|
||||
|
||||
# XXX make code memory safe for overflows in '*'
|
||||
|
||||
proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
|
||||
proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises: [].} =
|
||||
# we have to use type erasure here as Nim does not support generic
|
||||
# compilerProcs. Oh well, this will all be inlined anyway.
|
||||
if cap > 0:
|
||||
var p = cast[ptr NimSeqPayloadBase](allocShared0(cap * elemSize + sizeof(NimSeqPayloadBase)))
|
||||
var p = cast[ptr NimSeqPayloadBase](allocShared0(align(sizeof(NimSeqPayloadBase), elemAlign) + cap * elemSize))
|
||||
p.cap = cap
|
||||
result = p
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
|
||||
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
|
||||
noSideEffect, raises: [].} =
|
||||
{.noSideEffect.}:
|
||||
template `+!`(p: pointer, s: int): pointer =
|
||||
cast[pointer](cast[int](p) +% s)
|
||||
|
||||
const headerSize = sizeof(NimSeqPayloadBase)
|
||||
let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign)
|
||||
if addlen <= 0:
|
||||
result = p
|
||||
elif p == nil:
|
||||
result = newSeqPayload(len+addlen, elemSize)
|
||||
result = newSeqPayload(len+addlen, elemSize, elemAlign)
|
||||
else:
|
||||
# Note: this means we cannot support things that have internal pointers as
|
||||
# they get reallocated here. This needs to be documented clearly.
|
||||
@@ -87,7 +87,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
|
||||
if newLen <= oldLen: return
|
||||
var xu = cast[ptr NimSeqV2[T]](addr x)
|
||||
if xu.p == nil or xu.p.cap < newLen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)))
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newLen
|
||||
for i in oldLen .. newLen-1:
|
||||
xu.p.data[i] = value
|
||||
@@ -102,7 +102,7 @@ proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffec
|
||||
let oldLen = x.len
|
||||
var xu = cast[ptr NimSeqV2[T]](addr x)
|
||||
if xu.p == nil or xu.p.cap < oldLen+1:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T)))
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T), alignof(T)))
|
||||
xu.len = oldLen+1
|
||||
# .nodestroy means `xu.p.data[oldLen] = value` is compiled into a
|
||||
# copyMem(). This is fine as know by construction that
|
||||
@@ -119,5 +119,5 @@ proc setLen[T](s: var seq[T], newlen: Natural) =
|
||||
if newlen <= oldLen: return
|
||||
var xu = cast[ptr NimSeqV2[T]](addr s)
|
||||
if xu.p == nil or xu.p.cap < newlen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T)))
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newlen
|
||||
|
||||
@@ -245,7 +245,7 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||
|
||||
# ----------------- sequences ----------------------------------------------
|
||||
|
||||
proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} =
|
||||
proc incrSeq(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} =
|
||||
# increments the length by one:
|
||||
# this is needed for supporting ``add``;
|
||||
#
|
||||
@@ -255,18 +255,16 @@ proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} =
|
||||
result = seq
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = cast[PGenericSeq](growObj(result, elemSize * r +
|
||||
GenericSeqSize))
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r))
|
||||
result.reserved = r
|
||||
inc(result.len)
|
||||
|
||||
proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerproc.} =
|
||||
proc incrSeqV2(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} =
|
||||
# incrSeq version 2
|
||||
result = seq
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = cast[PGenericSeq](growObj(result, elemSize * r +
|
||||
GenericSeqSize))
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r))
|
||||
result.reserved = r
|
||||
|
||||
template `+!`(p: pointer, s: int): pointer =
|
||||
@@ -283,21 +281,19 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} =
|
||||
when defined(nimIncrSeqV3):
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
result.len = s.len
|
||||
copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size)
|
||||
copyMem(result +! align(GenericSeqSize, typ.base.align), s +! align(GenericSeqSize, typ.base.align), s.len * typ.base.size)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
else:
|
||||
result = cast[PGenericSeq](growObj(result, typ.base.size * r +
|
||||
GenericSeqSize))
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, typ.base.align) + typ.base.size * r))
|
||||
result.reserved = r
|
||||
|
||||
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericSeq {.
|
||||
compilerRtl, inl.} =
|
||||
result = seq
|
||||
if result.space < newLen:
|
||||
let r = max(resize(result.space), newLen)
|
||||
result = cast[PGenericSeq](growObj(result, elemSize * r +
|
||||
GenericSeqSize))
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r))
|
||||
result.reserved = r
|
||||
elif newLen < result.len:
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
@@ -307,8 +303,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
when false: # compileOption("gc", "v2"):
|
||||
for i in newLen..result.len-1:
|
||||
let len0 = gch.tempStack.len
|
||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
||||
GenericSeqSize +% (i*%elemSize)),
|
||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waPush)
|
||||
let len1 = gch.tempStack.len
|
||||
for i in len0 ..< len1:
|
||||
@@ -318,7 +313,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
if ntfNoRefs notin extGetCellType(result).base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
||||
GenericSeqSize +% (i*%elemSize)),
|
||||
align(GenericSeqSize, elemAlign) +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
@@ -327,7 +322,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +%
|
||||
zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +%
|
||||
(newLen*%elemSize)), (result.len-%newLen) *% elemSize)
|
||||
result.len = newLen
|
||||
|
||||
@@ -339,10 +334,11 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
else:
|
||||
when defined(nimIncrSeqV3):
|
||||
let elemSize = typ.base.size
|
||||
let elemAlign = typ.base.align
|
||||
if s.space < newLen:
|
||||
let r = max(resize(s.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize)
|
||||
copyMem(result +! align(GenericSeqSize, elemAlign), s +! align(GenericSeqSize, elemAlign), s.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
elif newLen < s.len:
|
||||
@@ -354,7 +350,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
if ntfNoRefs notin typ.base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
||||
GenericSeqSize +% (i*%elemSize)),
|
||||
align(GenericSeqSize, elemAlign) +% (i*%elemSize)),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
@@ -363,7 +359,7 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +%
|
||||
zeroMem(cast[pointer](cast[ByteAddress](result) +% align(GenericSeqSize, elemAlign) +%
|
||||
(newLen*%elemSize)), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
|
||||
17
tests/collections/thardalignmentconstraint.nim
Normal file
17
tests/collections/thardalignmentconstraint.nim
Normal file
@@ -0,0 +1,17 @@
|
||||
discard """
|
||||
disabled: true
|
||||
"""
|
||||
|
||||
# does not yet work
|
||||
|
||||
{.passC: "-march=native".}
|
||||
|
||||
type
|
||||
m256d {.importc: "__m256d", header: "immintrin.h".} = object
|
||||
|
||||
proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".}
|
||||
|
||||
for _ in 1..1000:
|
||||
var x = newSeq[m256d](1)
|
||||
x[0] = set1(1.0) # test if operation causes segfault
|
||||
doAssert (cast[uint](x[0].addr) and 31) == 0
|
||||
Reference in New Issue
Block a user