forward type alignment information to seqs (#12430)

This commit is contained in:
Arne Döring 2020-04-19 07:52:01 +02:00 • committed by GitHub
commit 4005f0d0e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 152 additions and 114 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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))

View file

@ -90,6 +90,7 @@ type
when defined(gcHooks):
head*: pointer
size*: int
align*: int
kind: TNimKind
flags: set[TNimTypeFlag]
base*: ptr TNimType

View file

@ -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"

View file

@ -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

View file

@ -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.}

View file

@ -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:

View file

@ -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, "]"

View file

@ -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

View file

@ -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