diff options
author | Arne Döring <arne.doering@gmx.net> | 2020-04-19 07:52:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-19 07:52:01 +0200 |
commit | 4005f0d0e40fb57efd8144c065a7ba56d940b572 (patch) | |
tree | 7df2d805351ed3c72114d00c773ff7d581337eda /lib/system | |
parent | a8f030fea21894e51c188a5804b0bbf787335f4d (diff) | |
download | Nim-4005f0d0e40fb57efd8144c065a7ba56d940b572.tar.gz |
forward type alignment information to seqs (#12430)
Diffstat (limited to 'lib/system')
-rw-r--r-- | lib/system/alloc.nim | 17 | ||||
-rw-r--r-- | lib/system/assign.nim | 11 | ||||
-rw-r--r-- | lib/system/channels.nim | 11 | ||||
-rw-r--r-- | lib/system/deepcopy.nim | 5 | ||||
-rw-r--r-- | lib/system/gc.nim | 15 | ||||
-rw-r--r-- | lib/system/gc2.nim | 13 | ||||
-rw-r--r-- | lib/system/gc_common.nim | 7 | ||||
-rw-r--r-- | lib/system/gc_ms.nim | 15 | ||||
-rw-r--r-- | lib/system/gc_regions.nim | 5 | ||||
-rw-r--r-- | lib/system/hti.nim | 1 | ||||
-rw-r--r-- | lib/system/mm/boehm.nim | 6 | ||||
-rw-r--r-- | lib/system/mm/go.nim | 11 | ||||
-rw-r--r-- | lib/system/mm/none.nim | 2 | ||||
-rw-r--r-- | lib/system/mmdisp.nim | 4 | ||||
-rw-r--r-- | lib/system/repr.nim | 4 | ||||
-rw-r--r-- | lib/system/seqs_v2.nim | 16 | ||||
-rw-r--r-- | lib/system/sysstr.nim | 34 |
17 files changed, 93 insertions, 84 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 95d5ae7ee..7ace0d536 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -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 diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 39ff9d743..eed7bc6db 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -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 diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 65398d65c..5966d9fee 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -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 - diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 66a65cd34..801821d26 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -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 diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 15f316ccc..690230767 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -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) diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index 4da9b4f94..09388b6e8 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -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) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index ff2b6ad6a..d75ada791 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -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) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index a026b404b..a3b163a67 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -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) diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim index 7dab50072..4f802c812 100644 --- a/lib/system/gc_regions.nim +++ b/lib/system/gc_regions.nim @@ -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)) diff --git a/lib/system/hti.nim b/lib/system/hti.nim index c20f132fb..63c1a5448 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -90,6 +90,7 @@ type when defined(gcHooks): head*: pointer size*: int + align*: int kind: TNimKind flags: set[TNimTypeFlag] base*: ptr TNimType diff --git a/lib/system/mm/boehm.nim b/lib/system/mm/boehm.nim index a8b0e17b4..b1afe59fc 100644 --- a/lib/system/mm/boehm.nim +++ b/lib/system/mm/boehm.nim @@ -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" - diff --git a/lib/system/mm/go.nim b/lib/system/mm/go.nim index 8e8558bea..b6d5a1a44 100644 --- a/lib/system/mm/go.nim +++ b/lib/system/mm/go.nim @@ -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 - diff --git a/lib/system/mm/none.nim b/lib/system/mm/none.nim index 0079daac3..7818a0805 100644 --- a/lib/system/mm/none.nim +++ b/lib/system/mm/none.nim @@ -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.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 2c3394df9..1cdf37604 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -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: diff --git a/lib/system/repr.nim b/lib/system/repr.nim index cc5ba2fee..526839aa2 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -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, "]" diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 3bd5e291b..097ab269c 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -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 diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 853397e0a..dbf9bcf06 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -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 |