summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorArne Döring <arne.doering@gmx.net>2020-04-19 07:52:01 +0200
committerGitHub <noreply@github.com>2020-04-19 07:52:01 +0200
commit4005f0d0e40fb57efd8144c065a7ba56d940b572 (patch)
tree7df2d805351ed3c72114d00c773ff7d581337eda /lib/system
parenta8f030fea21894e51c188a5804b0bbf787335f4d (diff)
downloadNim-4005f0d0e40fb57efd8144c065a7ba56d940b572.tar.gz
forward type alignment information to seqs (#12430)
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/alloc.nim17
-rw-r--r--lib/system/assign.nim11
-rw-r--r--lib/system/channels.nim11
-rw-r--r--lib/system/deepcopy.nim5
-rw-r--r--lib/system/gc.nim15
-rw-r--r--lib/system/gc2.nim13
-rw-r--r--lib/system/gc_common.nim7
-rw-r--r--lib/system/gc_ms.nim15
-rw-r--r--lib/system/gc_regions.nim5
-rw-r--r--lib/system/hti.nim1
-rw-r--r--lib/system/mm/boehm.nim6
-rw-r--r--lib/system/mm/go.nim11
-rw-r--r--lib/system/mm/none.nim2
-rw-r--r--lib/system/mmdisp.nim4
-rw-r--r--lib/system/repr.nim4
-rw-r--r--lib/system/seqs_v2.nim16
-rw-r--r--lib/system/sysstr.nim34
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