summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/arc.nim22
-rw-r--r--lib/system/assign.nim136
-rw-r--r--lib/system/cellseqs_v2.nim6
-rw-r--r--lib/system/cyclebreaker.nim14
-rw-r--r--lib/system/deepcopy.nim52
-rw-r--r--lib/system/hti.nim2
-rw-r--r--lib/system/mm/malloc.nim6
-rw-r--r--lib/system/orc.nim24
-rw-r--r--lib/system/seqs_v2.nim14
-rw-r--r--lib/system/seqs_v2_reimpl.nim17
10 files changed, 190 insertions, 103 deletions
diff --git a/lib/system/arc.nim b/lib/system/arc.nim
index 7fe17d3ea..68376cdab 100644
--- a/lib/system/arc.nim
+++ b/lib/system/arc.nim
@@ -59,12 +59,6 @@ type
 
   Cell = ptr RefHeader
 
-template `+!`(p: pointer, s: int): pointer =
-  cast[pointer](cast[int](p) +% s)
-
-template `-!`(p: pointer, s: int): pointer =
-  cast[pointer](cast[int](p) -% s)
-
 template head(p: pointer): Cell =
   cast[Cell](cast[int](p) -% sizeof(RefHeader))
 
@@ -132,6 +126,14 @@ proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
   when traceCollector:
     cprintf("[INCREF] %p\n", head(p))
 
+proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} =
+  # This is only used by the old RTTI mechanism and we know
+  # that 'dest[]' is nil and needs no destruction. Which is really handy
+  # as we cannot destroy the object reliably if it's an object of unknown
+  # compile-time type.
+  dest[] = src
+  if src != nil: nimIncRef src
+
 when not defined(nimscript) and defined(nimArcDebug):
   proc deallocatedRefId*(p: pointer): int =
     ## Returns the ref's ID if the ref was already deallocated. This
@@ -165,10 +167,10 @@ template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x))
 #proc dispose*(x: pointer) = nimRawDispose(x)
 
 proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
-  let d = cast[ptr PNimType](p)[].destructor
+  let d = cast[ptr PNimTypeV2](p)[].destructor
   if d != nil: cast[DestructorProc](d)(p)
   when false:
-    cstderr.rawWrite cast[ptr PNimType](p)[].name
+    cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name
     cstderr.rawWrite "\n"
     if d == nil:
       cstderr.rawWrite "bah, nil\n"
@@ -226,11 +228,11 @@ template tearDownForeignThreadGc* =
   ## With ``--gc:arc`` a nop.
   discard
 
-proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} =
+proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} =
   proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
 
   result = strstr(obj.name, subclass) != nil
 
-proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} =
+proc chckObj(obj: PNimTypeV2, subclass: cstring) {.compilerRtl.} =
   # checks if obj is of type subclass:
   if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion")
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index ff4ac021e..d332124cd 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+include seqs_v2_reimpl
+
 proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.}
 
 proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.}
@@ -38,6 +40,20 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
   #  echo "ugh memory corruption! ", n.kind
   #  quit 1
 
+template deepSeqAssignImpl(operation, additionalArg) {.dirty.} =
+  var d = cast[ptr NimSeqV2Reimpl](dest)
+  var s = cast[ptr NimSeqV2Reimpl](src)
+  d.len = s.len
+  let elem = mt.base
+  d.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(s.len, elem.size, elem.align))
+
+  let bs = elem.size
+  let ba = elem.align
+  let headerSize = align(sizeof(NimSeqPayloadBase), ba)
+
+  for i in 0..d.len-1:
+    operation(d.p +! (headerSize+i*bs), s.p +! (headerSize+i*bs), mt.base, additionalArg)
+
 proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
   var
     d = cast[ByteAddress](dest)
@@ -45,38 +61,46 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
   sysAssert(mt != nil, "genericAssignAux 2")
   case mt.kind
   of tyString:
-    var x = cast[PPointer](dest)
-    var s2 = cast[PPointer](s)[]
-    if s2 == nil or shallow or (
-        cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
-      unsureAsgnRef(x, s2)
+    when defined(nimSeqsV2):
+      var x = cast[ptr NimStringV2](dest)
+      var s2 = cast[ptr NimStringV2](s)[]
+      nimAsgnStrV2(x[], s2)
     else:
-      unsureAsgnRef(x, copyString(cast[NimString](s2)))
+      var x = cast[PPointer](dest)
+      var s2 = cast[PPointer](s)[]
+      if s2 == nil or shallow or (
+          cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
+        unsureAsgnRef(x, s2)
+      else:
+        unsureAsgnRef(x, copyString(cast[NimString](s2)))
   of tySequence:
-    var s2 = cast[PPointer](src)[]
-    var seq = cast[PGenericSeq](s2)
-    var x = cast[PPointer](dest)
-    if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
-      # this can happen! nil sequences are allowed
-      unsureAsgnRef(x, s2)
-      return
-    sysAssert(dest != nil, "genericAssignAux 3")
-    if ntfNoRefs in mt.base.flags:
-      var ss = nimNewSeqOfCap(mt, seq.len)
-      cast[PGenericSeq](ss).len = seq.len
-      unsureAsgnRef(x, ss)
-      var dst = cast[ByteAddress](cast[PPointer](dest)[])
-      copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)),
-              cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)),
-              seq.len *% mt.base.size)
+    when defined(nimSeqsV2):
+      deepSeqAssignImpl(genericAssignAux, shallow)
     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 +% 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)
+      var s2 = cast[PPointer](src)[]
+      var seq = cast[PGenericSeq](s2)
+      var x = cast[PPointer](dest)
+      if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
+        # this can happen! nil sequences are allowed
+        unsureAsgnRef(x, s2)
+        return
+      sysAssert(dest != nil, "genericAssignAux 3")
+      if ntfNoRefs in mt.base.flags:
+        var ss = nimNewSeqOfCap(mt, seq.len)
+        cast[PGenericSeq](ss).len = seq.len
+        unsureAsgnRef(x, ss)
+        var dst = cast[ByteAddress](cast[PPointer](dest)[])
+        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 +% 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
     # don't use recursion here on the PNimType because the subtype
@@ -87,14 +111,19 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
     genericAssignAux(dest, src, mt.node, shallow)
     # we need to copy m_type field for tyObject, as it could be empty for
     # sequence reallocations:
-    var pint = cast[ptr PNimType](dest)
-    # We need to copy the *static* type not the dynamic type:
-    #   if p of TB:
-    #     var tbObj = TB(p)
-    #     tbObj of TC # needs to be false!
-    #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
-    chckObjAsgn(cast[ptr PNimType](src)[], mt)
-    pint[] = mt # cast[ptr PNimType](src)[]
+    when defined(nimSeqsV2):
+      var pint = cast[ptr PNimTypeV2](dest)
+      #chckObjAsgn(cast[ptr PNimTypeV2](src)[].typeInfoV2, mt)
+      pint[] = cast[PNimTypeV2](mt.typeInfoV2)
+    else:
+      var pint = cast[ptr PNimType](dest)
+      # We need to copy the *static* type not the dynamic type:
+      #   if p of TB:
+      #     var tbObj = TB(p)
+      #     tbObj of TC # needs to be false!
+      #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
+      chckObjAsgn(cast[ptr PNimType](src)[], mt)
+      pint[] = mt # cast[ptr PNimType](src)[]
   of tyTuple:
     genericAssignAux(dest, src, mt.node, shallow)
   of tyArray, tyArrayConstr:
@@ -175,8 +204,12 @@ proc objectInit(dest: pointer, typ: PNimType) =
   of tyObject:
     # iterate over any structural type
     # here we have to init the type field:
-    var pint = cast[ptr PNimType](dest)
-    pint[] = typ
+    when defined(nimSeqsV2):
+      var pint = cast[ptr PNimTypeV2](dest)
+      pint[] = cast[PNimTypeV2](typ.typeInfoV2)
+    else:
+      var pint = cast[ptr PNimType](dest)
+      pint[] = typ
     objectInitAux(dest, typ.node)
   of tyTuple:
     objectInitAux(dest, typ.node)
@@ -204,15 +237,34 @@ proc genericReset(dest: pointer, mt: PNimType) =
   var d = cast[ByteAddress](dest)
   sysAssert(mt != nil, "genericReset 2")
   case mt.kind
-  of tyString, tyRef, tySequence:
+  of tyRef:
     unsureAsgnRef(cast[PPointer](dest), nil)
+  of tyString:
+    when defined(nimSeqsV2):
+      var s = cast[ptr NimStringV2](dest)
+      frees(s[])
+      zeroMem(dest, mt.size)
+    else:
+      unsureAsgnRef(cast[PPointer](dest), nil)
+  of tySequence:
+    when defined(nimSeqsV2):
+      var s = cast[ptr NimSeqV2Reimpl](dest)
+      if s.p != nil:
+        deallocShared(s.p)
+      zeroMem(dest, mt.size)
+    else:
+      unsureAsgnRef(cast[PPointer](dest), nil)
   of tyTuple:
     genericResetAux(dest, mt.node)
   of tyObject:
     genericResetAux(dest, mt.node)
     # also reset the type field for tyObject, for correct branch switching!
-    var pint = cast[ptr PNimType](dest)
-    pint[] = nil
+    when defined(nimSeqsV2):
+      var pint = cast[ptr PNimTypeV2](dest)
+      pint[] = nil
+    else:
+      var pint = cast[ptr PNimType](dest)
+      pint[] = nil
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
       genericReset(cast[pointer](d +% i *% mt.base.size), mt.base)
diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim
index b2ae41d73..fdd9e3099 100644
--- a/lib/system/cellseqs_v2.nim
+++ b/lib/system/cellseqs_v2.nim
@@ -10,13 +10,13 @@
 # Cell seqs for cyclebreaker and cyclicrefs_v2.
 
 type
-  CellTuple = (PT, PNimType)
+  CellTuple = (PT, PNimTypeV2)
   CellArray = ptr UncheckedArray[CellTuple]
   CellSeq = object
     len, cap: int
     d: CellArray
 
-proc add(s: var CellSeq, c: PT; t: PNimType) {.inline.} =
+proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} =
   if s.len >= s.cap:
     s.cap = s.cap * 3 div 2
     when defined(useMalloc):
@@ -51,6 +51,6 @@ proc deinit(s: var CellSeq) =
   s.len = 0
   s.cap = 0
 
-proc pop(s: var CellSeq): (PT, PNimType) =
+proc pop(s: var CellSeq): (PT, PNimTypeV2) =
   result = s.d[s.len-1]
   dec s.len
diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim
index 3d01eeb9d..c4d802a92 100644
--- a/lib/system/cyclebreaker.nim
+++ b/lib/system/cyclebreaker.nim
@@ -78,14 +78,14 @@ type
   GcEnv = object
     traceStack: CellSeq
 
-proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} =
+proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
   when false:
     cprintf("[Trace] desc: %p %p\n", desc, p)
     cprintf("[Trace] trace: %p\n", desc.traceImpl)
   if desc.traceImpl != nil:
     cast[TraceProc](desc.traceImpl)(p, addr(j))
 
-proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} =
+proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} =
   let p = cast[ptr pointer](q)
   when traceCollector:
     cprintf("[Trace] raw: %p\n", p)
@@ -101,11 +101,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
     cprintf("[TraceDyn] deref: %p\n", p[])
   if p[] != nil:
     var j = cast[ptr GcEnv](env)
-    j.traceStack.add(p, cast[ptr PNimType](p[])[])
+    j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[])
 
 var markerGeneration: int
 
-proc breakCycles(s: Cell; desc: PNimType) =
+proc breakCycles(s: Cell; desc: PNimTypeV2) =
   let markerColor = if (markerGeneration and 1) == 0: colRed
                     else: colYellow
   atomicInc markerGeneration
@@ -147,7 +147,7 @@ proc thinout*[T](x: ref T) {.inline.} =
   ## and thus would keep the graph from being freed are `nil`'ed.
   ## This is a form of cycle collection that works well with Nim's ARC
   ## and its associated cost model.
-  proc getDynamicTypeInfo[T](x: T): PNimType {.magic: "GetTypeInfo", noSideEffect, locks: 0.}
+  proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect, locks: 0.}
 
   breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[]))
 
@@ -158,7 +158,7 @@ proc thinout*[T: proc](x: T) {.inline.} =
     """.}
 
   let p = rawEnv(x)
-  breakCycles(head(p), cast[ptr PNimType](p)[])
+  breakCycles(head(p), cast[ptr PNimTypeV2](p)[])
 
 proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
   if p != nil:
@@ -171,7 +171,7 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
       # According to Lins it's correct to do nothing else here.
       #cprintf("[DeCREF] %p\n", p)
 
-proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} =
+proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
   if p != nil:
     var cell = head(p)
     if (cell.rc and not rcMask) == 0:
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index 801821d26..5905b5785 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -90,27 +90,35 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
   sysAssert(mt != nil, "genericDeepCopyAux 2")
   case mt.kind
   of tyString:
-    var x = cast[PPointer](dest)
-    var s2 = cast[PPointer](s)[]
-    if s2 == nil:
-      unsureAsgnRef(x, s2)
+    when defined(nimSeqsV2):
+      var x = cast[ptr NimStringV2](dest)
+      var s2 = cast[ptr NimStringV2](s)[]
+      nimAsgnStrV2(x[], s2)
     else:
-      unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
+      var x = cast[PPointer](dest)
+      var s2 = cast[PPointer](s)[]
+      if s2 == nil:
+        unsureAsgnRef(x, s2)
+      else:
+        unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
   of tySequence:
-    var s2 = cast[PPointer](src)[]
-    var seq = cast[PGenericSeq](s2)
-    var x = cast[PPointer](dest)
-    if s2 == nil:
-      unsureAsgnRef(x, s2)
-      return
-    sysAssert(dest != nil, "genericDeepCopyAux 3")
-    unsureAsgnRef(x, newSeq(mt, seq.len))
-    var dst = cast[ByteAddress](cast[PPointer](dest)[])
-    for i in 0..seq.len-1:
-      genericDeepCopyAux(
-        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)
+    when defined(nimSeqsV2):
+      deepSeqAssignImpl(genericDeepCopyAux, tab)
+    else:
+      var s2 = cast[PPointer](src)[]
+      var seq = cast[PGenericSeq](s2)
+      var x = cast[PPointer](dest)
+      if s2 == nil:
+        unsureAsgnRef(x, s2)
+        return
+      sysAssert(dest != nil, "genericDeepCopyAux 3")
+      unsureAsgnRef(x, newSeq(mt, seq.len))
+      var dst = cast[ByteAddress](cast[PPointer](dest)[])
+      for i in 0..seq.len-1:
+        genericDeepCopyAux(
+          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
     # sequence reallocations:
@@ -151,7 +159,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
             sysAssert realType == mt, " types do differ"
           # this version should work for any possible GC:
           let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base
-          let z = newObj(mt, typ.size)
+          let z = when defined(nimSeqsV2): nimNewObj(typ.size) else: newObj(mt, typ.size)
           unsureAsgnRef(cast[PPointer](dest), z)
           tab.put(s2, z)
           genericDeepCopyAux(z, s2, typ, tab)
@@ -168,11 +176,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
     copyMem(dest, src, mt.size)
 
 proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
-  GC_disable()
+  when not defined(nimSeqsV2): GC_disable()
   var tab = initPtrTable()
   genericDeepCopyAux(dest, src, mt, tab)
   deinit tab
-  GC_enable()
+  when not defined(nimSeqsV2): GC_enable()
 
 proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
   # also invoked for 'string'
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index b77f7ccde..3dbcd7615 100644
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -98,6 +98,8 @@ type
     finalizer*: pointer # the finalizer for the type
     marker*: proc (p: pointer, op: int) {.nimcall, benign, tags: [], raises: [].} # marker proc for GC
     deepcopy: proc (p: pointer): pointer {.nimcall, benign, tags: [], raises: [].}
+    when defined(nimSeqsV2):
+      typeInfoV2*: pointer
     when defined(nimTypeNames):
       name: cstring
       nextType: ptr TNimType
diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim
index 3dad98e93..2ba5c0fec 100644
--- a/lib/system/mm/malloc.nim
+++ b/lib/system/mm/malloc.nim
@@ -65,8 +65,10 @@ proc growObj(old: pointer, newsize: int): pointer =
 proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
 proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
 
-proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-  dest[] = src
+when not defined(gcDestructors):
+  proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
 proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
   dest[] = src
 proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
diff --git a/lib/system/orc.nim b/lib/system/orc.nim
index 7500ba374..4ba462c1f 100644
--- a/lib/system/orc.nim
+++ b/lib/system/orc.nim
@@ -53,7 +53,7 @@ type
     toFree: CellSeq
     freed, touched: int
 
-proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} =
+proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
   if desc.traceImpl != nil:
     var p = s +! sizeof(RefHeader)
     cast[TraceProc](desc.traceImpl)(p, addr(j))
@@ -65,7 +65,7 @@ else:
     let p = s +! sizeof(RefHeader)
     cprintf("[%s] name %s RC %ld\n", str, p, s.rc shr rcShift)
 
-proc free(s: Cell; desc: PNimType) {.inline.} =
+proc free(s: Cell; desc: PNimTypeV2) {.inline.} =
   when traceCollector:
     cprintf("[From ] %p rc %ld color %ld\n", s, s.rc shr rcShift, s.color)
   let p = s +! sizeof(RefHeader)
@@ -89,7 +89,7 @@ proc free(s: Cell; desc: PNimType) {.inline.} =
 
   nimRawDispose(p)
 
-proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} =
+proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} =
   let p = cast[ptr pointer](q)
   if p[] != nil:
     var j = cast[ptr GcEnv](env)
@@ -99,7 +99,7 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
   let p = cast[ptr pointer](q)
   if p[] != nil:
     var j = cast[ptr GcEnv](env)
-    j.traceStack.add(head p[], cast[ptr PNimType](p[])[])
+    j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[])
 
 var
   roots {.threadvar.}: CellSeq
@@ -115,7 +115,7 @@ proc unregisterCycle(s: Cell) =
   roots.d[idx][0].rootIdx = idx
   dec roots.len
 
-proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) =
+proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
   proc scanBlack(s: Cell) =
     setColor(s, colBlack)
@@ -135,7 +135,7 @@ proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) =
       t.setColor colBlack
       trace(t, desc, j)
 
-proc markGray(s: Cell; desc: PNimType; j: var GcEnv) =
+proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
   proc markGray(s: Cell) =
     if s.color != colGray:
@@ -163,7 +163,7 @@ proc markGray(s: Cell; desc: PNimType; j: var GcEnv) =
         inc j.touched
         trace(t, desc, j)
 
-proc scan(s: Cell; desc: PNimType; j: var GcEnv) =
+proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
   proc scan(s: Cell) =
     if s.color == colGray:
@@ -226,7 +226,7 @@ when false:
     cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n",
       msg, s, s.rootIdx, s.rc shr rcShift, s.color)
 
-proc collectWhite(s: Cell; desc: PNimType; j: var GcEnv) =
+proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
   proc collectWhite(s: Cell) =
     if s.color == colWhite and not buffered(s):
@@ -315,7 +315,7 @@ proc collectCycles() =
   when false:
     cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold)
 
-proc registerCycle(s: Cell; desc: PNimType) =
+proc registerCycle(s: Cell; desc: PNimTypeV2) =
   if roots.len >= rootsThreshold:
     collectCycles()
   if roots.d == nil: init(roots)
@@ -334,7 +334,7 @@ proc GC_enableMarkAndSweep() =
 proc GC_disableMarkAndSweep() =
   rootsThreshold = high(int)
 
-proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimType) {.noinline.} =
+proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} =
   if isDestroyAction:
     if (s.rc and isCycleCandidate) != 0:
       s.rc = s.rc and not isCycleCandidate
@@ -356,9 +356,9 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
     else:
       dec cell.rc, rcIncrement
     #if cell.color == colPurple:
-    rememberCycle(result, cell, cast[ptr PNimType](p)[])
+    rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[])
 
-proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} =
+proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
   if p != nil:
     var cell = head(p)
     if (cell.rc and not rcMask) == 0:
diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index 3c94a03f9..111299fff 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -22,7 +22,8 @@ type
     cap: int
     data: UncheckedArray[T]
 
-  NimSeqV2*[T] = object
+  NimSeqV2*[T] = object # \
+    # if you change this implementation, also change seqs_v2_reimpl.nim!
     len: int
     p: ptr NimSeqPayload[T]
 
@@ -40,12 +41,15 @@ proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises
   else:
     result = nil
 
+template `+!`(p: pointer, s: int): pointer =
+  cast[pointer](cast[int](p) +% s)
+
+template `-!`(p: pointer, s: int): pointer =
+  cast[pointer](cast[int](p) -% s)
+
 proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
-    noSideEffect, raises: [].} =
+    noSideEffect, raises: [], compilerRtl.} =
   {.noSideEffect.}:
-    template `+!`(p: pointer, s: int): pointer =
-      cast[pointer](cast[int](p) +% s)
-
     let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign)
     if addlen <= 0:
       result = p
diff --git a/lib/system/seqs_v2_reimpl.nim b/lib/system/seqs_v2_reimpl.nim
new file mode 100644
index 000000000..750f78c0d
--- /dev/null
+++ b/lib/system/seqs_v2_reimpl.nim
@@ -0,0 +1,17 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2020 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type
+  NimSeqPayloadReimpl = object
+    cap: int
+    data: pointer
+
+  NimSeqV2Reimpl = object
+    len: int
+    p: ptr NimSeqPayloadReimpl