summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim9
-rw-r--r--compiler/ccgcalls.nim10
-rw-r--r--compiler/ccgexprs.nim179
-rw-r--r--compiler/ccgliterals.nim24
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/ccgtrav.nim23
-rw-r--r--compiler/ccgtypes.nim53
-rw-r--r--compiler/cgen.nim25
-rw-r--r--compiler/commands.nim9
-rw-r--r--compiler/condsyms.nim1
-rw-r--r--compiler/destroyer.nim31
-rw-r--r--compiler/options.nim6
-rw-r--r--compiler/semasgn.nim28
-rw-r--r--compiler/semstmts.nim15
-rw-r--r--compiler/semtypes.nim35
-rw-r--r--compiler/transf.nim8
-rw-r--r--compiler/types.nim15
17 files changed, 330 insertions, 143 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 01e70ce75..a722f63f6 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -627,6 +627,7 @@ type
     mIsPartOf, mAstToStr, mParallel,
     mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
     mNewString, mNewStringOfCap, mParseBiggestFloat,
+    mMove, mWasMoved,
     mReset,
     mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
     mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@@ -1087,9 +1088,9 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
   result.id = getID()
   when debugIds:
     registerId(result)
-  #if result.id == 93289:
+  #if result.id == 77131:
   #  writeStacktrace()
-  #  MessageOut(name.s & " has id: " & toString(result.id))
+  #  echo name.s
 
 proc isMetaType*(t: PType): bool =
   return t.kind in tyMetaTypes or
@@ -1267,14 +1268,14 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
   new(result)
   result.kind = kind
   result.owner = owner
-  result.size = - 1
+  result.size = -1
   result.align = 2            # default alignment
   result.id = getID()
   result.lockLevel = UnspecifiedLockLevel
   when debugIds:
     registerId(result)
   when false:
-    if result.id == 205734:
+    if result.id == 76426:
       echo "KNID ", kind
       writeStackTrace()
 
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 2621574a6..83461350b 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -124,15 +124,19 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     of tyString, tySequence:
       if skipTypes(n.typ, abstractInst).kind == tyVar and
             not compileToCpp(p.module):
-        result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)]
+        var t: TLoc
+        t.r = "(*$1)" % [a.rdLoc]
+        result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
       else:
-        result = "$1$3, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)]
+        result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)]
     of tyArray:
       result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
     of tyPtr, tyRef:
       case lastSon(a.t).kind
       of tyString, tySequence:
-        result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)]
+        var t: TLoc
+        t.r = "(*$1)" % [a.rdLoc]
+        result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenExpr(p, t), dataField(p)]
       of tyArray:
         result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
       else:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index b30d216f2..65cae8866 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -165,7 +165,7 @@ proc canMove(n: PNode): bool =
   #  result = false
 
 proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
-  if dest.storage == OnStack or not usesNativeGC(p.config):
+  if dest.storage == OnStack or not usesWriteBarrier(p.config):
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   elif dest.storage == OnHeap:
     # location is on heap
@@ -255,9 +255,13 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   # tfShallow flag for the built-in string type too! So we check only
   # here for this flag, where it is reasonably safe to do so
   # (for objects, etc.):
-  if needToCopy notin flags or
+  if p.config.selectedGC == gcDestructors:
+    linefmt(p, cpsStmts,
+        "$1.len = $2.len; $1.p = $2.p;$n",
+        rdLoc(dest), rdLoc(src))
+  elif needToCopy notin flags or
       tfShallow in skipTypes(dest.t, abstractVarRange).flags:
-    if dest.storage == OnStack or not usesNativeGC(p.config):
+    if dest.storage == OnStack or not usesWriteBarrier(p.config):
       linefmt(p, cpsStmts,
            "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
            addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest))
@@ -280,17 +284,21 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyRef:
     genRefAssign(p, dest, src, flags)
   of tySequence:
-    if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
+    if p.config.selectedGC == gcDestructors:
+      genGenericAsgn(p, dest, src, flags)
+    elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
       genRefAssign(p, dest, src, flags)
     else:
       linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
               addrLoc(p.config, dest), rdLoc(src),
               genTypeInfo(p.module, dest.t, dest.lode.info))
   of tyString:
-    if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
+    if p.config.selectedGC == gcDestructors:
+      genGenericAsgn(p, dest, src, flags)
+    elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
       genRefAssign(p, dest, src, flags)
     else:
-      if dest.storage == OnStack or not usesNativeGC(p.config):
+      if dest.storage == OnStack or not usesWriteBarrier(p.config):
         linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
       elif dest.storage == OnHeap:
         # we use a temporary to care for the dreaded self assignment:
@@ -453,6 +461,13 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   initLocExpr(p, e.sons[2], b)
   lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
 
+proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr")
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  lineCg(p, cpsStmts, frmt, addrLoc(p.config, a), rdLoc(b))
+
 proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   var a: TLoc
   if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
@@ -889,8 +904,8 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
   of tySequence, tyString:
     linefmt(p, cpsStmts,
       "if ($2-$1 != -1 && " &
-      "(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n",
-      rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p))
+      "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)) #raiseIndexError();$n",
+      rdLoc(a), rdLoc(b), lenExpr(p, arr))
   else: discard
 
 proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
@@ -914,12 +929,12 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   if optBoundsCheck in p.options:
     if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
       linefmt(p, cpsStmts,
-              "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
-              rdLoc(b), rdLoc(a), lenField(p))
+              "if ((NU)($1) > (NU)$2) #raiseIndexError();$n",
+              rdLoc(b), lenExpr(p, a))
     else:
       linefmt(p, cpsStmts,
-              "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
-              rdLoc(b), rdLoc(a), lenField(p))
+              "if ((NU)($1) >= (NU)$2) #raiseIndexError();$n",
+              rdLoc(b), lenExpr(p, a))
   if d.k == locNone: d.storage = OnHeap
   if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
     a.r = ropecg(p.module, "(*$1)", a.r)
@@ -1010,6 +1025,12 @@ proc genEcho(p: BProc, n: PNode) =
 proc gcUsage(conf: ConfigRef; n: PNode) =
   if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
 
+proc strLoc(p: BProc; d: TLoc): Rope =
+  if p.config.selectedGc == gcDestructors:
+    result = addrLoc(p.config, d)
+  else:
+    result = rdLoc(d)
+
 proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
   #   <Nim code>
   #   s = 'Hello ' & name & ', how do you feel?' & 'z'
@@ -1037,13 +1058,14 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[i + 1], a)
     if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
+      add(appends, ropecg(p.module, "#appendChar($1, $2);$n", strLoc(p, tmp), rdLoc(a)))
     else:
       if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 1].strVal))
       else:
-        addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
-      add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
+        add(lens, lenExpr(p, a))
+        add(lens, " + ")
+      add(appends, ropecg(p.module, "#appendString($1, $2);$n", strLoc(p, tmp), rdLoc(a)))
   linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
   add(p.s(cpsStmts), appends)
   if d.k == locNone:
@@ -1076,19 +1098,24 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
     if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
       inc(L)
       add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
-                        rdLoc(dest), rdLoc(a)))
+                        strLoc(p, dest), rdLoc(a)))
     else:
       if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 2].strVal))
       else:
-        addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
+        add(lens, lenExpr(p, a))
+        add(lens, " + ")
       add(appends, ropecg(p.module, "#appendString($1, $2);$n",
-                        rdLoc(dest), rdLoc(a)))
-  initLoc(call, locCall, e, OnHeap)
-  call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
-  genAssignment(p, dest, call, {})
+                        strLoc(p, dest), rdLoc(a)))
+  if p.config.selectedGC == gcDestructors:
+    linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n",
+            addrLoc(p.config, dest), lens, rope(L))
+  else:
+    initLoc(call, locCall, e, OnHeap)
+    call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)])
+    genAssignment(p, dest, call, {})
+    gcUsage(p.config, e)
   add(p.s(cpsStmts), appends)
-  gcUsage(p.config, e)
 
 proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   # seq &= x  -->
@@ -1151,7 +1178,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
     addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
 
   let args = [getTypeDesc(p.module, typ), ti, sizeExpr]
-  if a.storage == OnHeap and usesNativeGC(p.config):
+  if a.storage == OnHeap and usesWriteBarrier(p.config):
     # use newObjRC1 as an optimization
     if canFormAcycle(a.t):
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
@@ -1182,7 +1209,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
               genTypeInfo(p.module, seqtype, dest.lode.info), length]
   var call: TLoc
   initLoc(call, locExpr, dest.lode, OnHeap)
-  if dest.storage == OnHeap and usesNativeGC(p.config):
+  if dest.storage == OnHeap and usesWriteBarrier(p.config):
     if canFormAcycle(dest.t):
       linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
     else:
@@ -1201,10 +1228,16 @@ proc genNewSeq(p: BProc, e: PNode) =
   var a, b: TLoc
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
-  let lenIsZero = optNilSeqs notin p.options and
-    e[2].kind == nkIntLit and e[2].intVal == 0
-  genNewSeqAux(p, a, b.rdLoc, lenIsZero)
-  gcUsage(p.config, e)
+  if p.config.selectedGC == gcDestructors:
+    let seqtype = skipTypes(e.sons[1].typ, abstractVarRange)
+    linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
+      a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
+      getSeqPayloadType(p.module, seqtype))
+  else:
+    let lenIsZero = optNilSeqs notin p.options and
+      e[2].kind == nkIntLit and e[2].intVal == 0
+    genNewSeqAux(p, a, b.rdLoc, lenIsZero)
+    gcUsage(p.config, e)
 
 proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
   let seqtype = skipTypes(e.typ, abstractVarRange)
@@ -1448,7 +1481,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
       putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
     of tyString, tySequence:
       putIntoDest(p, b, e,
-                  "$1$3, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p), dataField(p)], a.storage)
+                  "$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage)
     of tyArray:
       putIntoDest(p, b, e,
                   "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage)
@@ -1492,28 +1525,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)")
     else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)")
   of tyString:
-    if not p.module.compileToCpp:
-      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
-      else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
-    else:
-      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
-      else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
+    var a: TLoc
+    initLocExpr(p, e.sons[1], a)
+    var x = lenExpr(p, a)
+    if op == mHigh: x = "($1-1)" % [x]
+    putIntoDest(p, d, e, x)
   of tySequence:
+    # we go through a temporary here because people write bullshit code.
     var a, tmp: TLoc
     initLocExpr(p, e[1], a)
     getIntTemp(p, tmp)
-    var frmt: FormatStr
-    if not p.module.compileToCpp:
-      if op == mHigh:
-        frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n"
-      else:
-        frmt = "$1 = ($2 ? $2->Sup.len : 0);$n"
-    else:
-      if op == mHigh:
-        frmt = "$1 = ($2 ? ($2->len-1) : -1);$n"
-      else:
-        frmt = "$1 = ($2 ? $2->len : 0);$n"
-    lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
+    var x = lenExpr(p, a)
+    if op == mHigh: x = "($1-1)" % [x]
+    lineCg(p, cpsStmts, "$1 = $2;$n", tmp.r, x)
     putIntoDest(p, d, e, tmp.r)
   of tyArray:
     # YYY: length(sideeffect) is optimized away incorrectly?
@@ -1522,6 +1546,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   else: internalError(p.config, e.info, "genArrayLen()")
 
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
+  if p.config.selectedGc == gcDestructors:
+    genCall(p, e, d)
+    return
   var a, b, call: TLoc
   assert(d.k == locNone)
   var x = e.sons[1]
@@ -1542,16 +1569,19 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   gcUsage(p.config, e)
 
 proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
-  var a, b, call: TLoc
-  if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr")
-  initLocExpr(p, e.sons[1], a)
-  initLocExpr(p, e.sons[2], b)
+  if p.config.selectedGc == gcDestructors:
+    binaryStmtAddr(p, e, d, "#setLengthStrV2($1, $2);$n")
+  else:
+    var a, b, call: TLoc
+    if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr")
+    initLocExpr(p, e.sons[1], a)
+    initLocExpr(p, e.sons[2], b)
 
-  initLoc(call, locCall, e, OnHeap)
-  call.r = ropecg(p.module, "#setLengthStr($1, $2)", [
-      rdLoc(a), rdLoc(b)])
-  genAssignment(p, a, call, {})
-  gcUsage(p.config, e)
+    initLoc(call, locCall, e, OnHeap)
+    call.r = ropecg(p.module, "#setLengthStr($1, $2)", [
+        rdLoc(a), rdLoc(b)])
+    genAssignment(p, a, call, {})
+    gcUsage(p.config, e)
 
 proc genSwap(p: BProc, e: PNode, d: var TLoc) =
   # swap(a, b) -->
@@ -1803,11 +1833,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
   if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
     initLocExpr(p, e.sons[2], x)
     putIntoDest(p, d, e,
-      ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+      ropecg(p.module, "($1 == 0)", lenExpr(p, x)))
   elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
     initLocExpr(p, e.sons[1], x)
     putIntoDest(p, d, e,
-      ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+      ropecg(p.module, "($1 == 0)", lenExpr(p, x)))
   else:
     binaryExpr(p, e, d, "#eqStrings($1, $2)")
 
@@ -1868,14 +1898,21 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
 
   of mConStrStr: genStrConcat(p, e, d)
   of mAppendStrCh:
-    var dest, b, call: TLoc
-    initLoc(call, locCall, e, OnHeap)
-    initLocExpr(p, e.sons[1], dest)
-    initLocExpr(p, e.sons[2], b)
-    call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
-    genAssignment(p, dest, call, {})
+    if p.config.selectedGC == gcDestructors:
+      binaryStmtAddr(p, e, d, "#nimAddCharV1($1, $2);$n")
+    else:
+      var dest, b, call: TLoc
+      initLoc(call, locCall, e, OnHeap)
+      initLocExpr(p, e.sons[1], dest)
+      initLocExpr(p, e.sons[2], b)
+      call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)])
+      genAssignment(p, dest, call, {})
   of mAppendStrStr: genStrAppend(p, e, d)
-  of mAppendSeqElem: genSeqElemAppend(p, e, d)
+  of mAppendSeqElem:
+    if p.config.selectedGc == gcDestructors:
+      genCall(p, e, d)
+    else:
+      genSeqElemAppend(p, e, d)
   of mEqStr: genStrEquals(p, e, d)
   of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
   of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
@@ -1924,8 +1961,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
      mInSet:
     genSetOp(p, e, d, op)
-  of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit,
-      mParseBiggestFloat:
+  of mCopyStr, mCopyStrLast:
+    genCall(p, e, d)
+  of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat:
     var opr = e.sons[0].sym
     if lfNoDecl notin opr.loc.flags:
       discard cgsym(p.module, $opr.loc.r)
@@ -2522,6 +2560,13 @@ proc genConstExpr(p: BProc, n: PNode): Rope =
       result = genConstSimpleList(p, n)
   of nkObjConstr:
     result = genConstObjConstr(p, n)
+  of nkStrLit..nkTripleStrLit:
+    if p.config.selectedGc == gcDestructors:
+      result = genStringLiteralV2Const(p.module, n)
+    else:
+      var d: TLoc
+      initLocExpr(p, n, d)
+      result = rdLoc(d)
   else:
     var d: TLoc
     initLocExpr(p, n, d)
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index cfe71375e..34677ec06 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -53,20 +53,36 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
 
 proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
   result = getTempName(m)
-  addf(m.s[cfsData], " static const NIM_CHAR $1[$2] = $3;$n",
-       [result, rope(len(s)+1), makeCString(s)])
+  addf(m.s[cfsData], "static const struct {$n" &
+       "  NI cap; void* allocator; NIM_CHAR data[$2];$n" &
+       "} $1 = { $2, NIM_NIL, $3 };$n",
+       [result, rope(len(s)), makeCString(s)])
 
 proc genStringLiteralV2(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
   if id == m.labels:
+    discard cgsym(m, "NimStrPayload")
+    discard cgsym(m, "NimStringV2")
     # string literal not found in the cache:
     let pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
     result = getTempName(m)
-    addf(m.s[cfsData], "static const #NimStringV2 $1 = {$2, $2, $3};$n",
-        [result, rope(len(n.strVal)+1), pureLit])
+    addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
+          [result, rope(len(n.strVal)), pureLit])
   else:
     result = m.tmpBase & rope(id)
 
+proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
+  let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+  var pureLit: Rope
+  if id == m.labels:
+    discard cgsym(m, "NimStrPayload")
+    discard cgsym(m, "NimStringV2")
+    # string literal not found in the cache:
+    pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
+  else:
+    pureLit = m.tmpBase & rope(id)
+  result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit]
+
 # ------ Version selector ---------------------------------------------------
 
 proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a7a2b3fee..69e6558bb 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -16,7 +16,7 @@ const
     # above X strings a hash-switch for strings is generated
 
 proc registerGcRoot(p: BProc, v: PSym) =
-  if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
+  if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and
       containsGarbageCollectedRef(v.loc.t):
     # we register a specialized marked proc here; this has the advantage
     # that it works out of the box for thread local storage then :-)
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 349cf2707..c69bb2c80 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -7,8 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## Generates traversal procs for the C backend. Traversal procs are only an
-## optimization; the GC works without them too.
+## Generates traversal procs for the C backend.
 
 # included from cgen.nim
 
@@ -61,6 +60,7 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
   else:
     result = accessor
 
+proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType)
 proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
   if typ == nil: return
 
@@ -93,8 +93,18 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
     let typ = getUniqueType(typ)
     for i in countup(0, sonsLen(typ) - 1):
       genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
-  of tyRef, tyString, tySequence:
+  of tyRef:
     lineCg(p, cpsStmts, c.visitorFrmt, accessor)
+  of tySequence:
+    if tfHasAsgn notin typ.flags:
+      lineCg(p, cpsStmts, c.visitorFrmt, accessor)
+    elif containsGarbageCollectedRef(typ.lastSon):
+      # destructor based seqs are themselves not traced but their data is, if
+      # they contain a GC'ed type:
+      genTraverseProcSeq(c, accessor, typ)
+  of tyString:
+    if tfHasAsgn notin typ.flags:
+      lineCg(p, cpsStmts, c.visitorFrmt, accessor)
   of tyProc:
     if typ.callConv == ccClosure:
       lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
@@ -107,8 +117,11 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
   var i: TLoc
   getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
   let oldCode = p.s(cpsStmts)
-  lineF(p, cpsStmts, "for ($1 = 0; $1 < ($2 ? $2->$3 : 0); $1++) {$n",
-      [i.r, accessor, lenField(c.p)])
+  var a: TLoc
+  a.r = accessor
+
+  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
+      [i.r, lenExpr(c.p, a)])
   let oldLen = p.s(cpsStmts).len
   genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0])
   if p.s(cpsStmts).len == oldLen:
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index a16255f6e..59fbfc3e1 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -282,7 +282,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyString:
     case detectStrVersion(m)
     of 2:
-      discard cgsym(m, "string")
+      discard cgsym(m, "NimStringV2")
       result = typeNameOrLiteral(m, typ, "NimStringV2")
     else:
       discard cgsym(m, "NimStringDesc")
@@ -324,6 +324,10 @@ proc getForwardStructFormat(m: BModule): string =
   if m.compileToCpp: result = "$1 $2;$n"
   else: result = "typedef $1 $2 $2;$n"
 
+proc seqStar(m: BModule): string =
+  if m.config.selectedGC == gcDestructors: result = ""
+  else: result = "*"
+
 proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
   result = cacheGetType(m.forwTypeCache, sig)
   if result != nil: return
@@ -355,8 +359,11 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
       result = getTypeForward(m, t, hashType(t))
       pushType(m, t)
   of tySequence:
-    result = getTypeForward(m, t, hashType(t)) & "*"
-    pushType(m, t)
+    if m.config.selectedGC == gcDestructors:
+      result = getTypeDescAux(m, t, check)
+    else:
+      result = getTypeForward(m, t, hashType(t)) & seqStar(m)
+      pushType(m, t)
   else:
     result = getTypeDescAux(m, t, check)
 
@@ -487,7 +494,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
       if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
         addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
             [getTypeDescAux(m, fieldType.elemType, check), sname])
-      elif fieldType.kind in {tySequence, tyOpt}:
+      elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
         # we need to use a weak dependency here for trecursive_table.
         addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
       elif field.bitsize != 0:
@@ -601,6 +608,15 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
       result = if result.kind == tyGenericInst: result.sons[1]
                else: result.elemType
 
+proc getSeqPayloadType(m: BModule; t: PType): Rope =
+  result = getTypeForward(m, t, hashType(t)) & "_Content"
+  when false:
+    var check = initIntSet()
+    # XXX remove this duplication:
+    appcg(m, m.s[cfsSeqTypes],
+      "struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE]; };$n",
+      [getTypeDescAux(m, t.sons[0], check), result])
+
 proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
   # returns only the type's name
   var t = origTyp.skipTypes(irrelevantForBackend)
@@ -641,7 +657,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
     of tySequence:
       # no restriction! We have a forward declaration for structs
       let name = getTypeForward(m, et, hashType et)
-      result = name & "*" & star
+      result = name & seqStar(m) & star
       m.typeCache[sig] = result
       pushType(m, et)
     else:
@@ -705,20 +721,29 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
             [structOrUnion(t), result])
       m.forwTypeCache[sig] = result
     assert(cacheGetType(m.typeCache, sig) == nil)
-    m.typeCache[sig] = result & "*"
+    m.typeCache[sig] = result & seqStar(m)
     if not isImportedType(t):
       if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
         const
           cppSeq = "struct $2 : #TGenericSeq {$n"
           cSeq = "struct $2 {$n" &
                  "  #TGenericSeq Sup;$n"
-        appcg(m, m.s[cfsSeqTypes],
-            (if m.compileToCpp: cppSeq else: cSeq) &
-            "  $1 data[SEQ_DECL_SIZE];$n" &
+        if m.config.selectedGC == gcDestructors:
+          appcg(m, m.s[cfsTypes],
+            "typedef struct{ NI cap;void* allocator;$1 data[SEQ_DECL_SIZE];}$2_Content;$n" &
+            "struct $2 {$n" &
+            "  NI len; $2_Content* p;$n" &
             "};$n", [getTypeDescAux(m, t.sons[0], check), result])
+        else:
+          appcg(m, m.s[cfsSeqTypes],
+              (if m.compileToCpp: cppSeq else: cSeq) &
+              "  $1 data[SEQ_DECL_SIZE];$n" &
+              "};$n", [getTypeDescAux(m, t.sons[0], check), result])
+      elif m.config.selectedGC == gcDestructors:
+        internalError(m.config, "cannot map the empty seq type to a C type")
       else:
         result = rope("TGenericSeq")
-    add(result, "*")
+    add(result, seqStar(m))
   of tyArray:
     var n: BiggestInt = lengthOrd(m.config, t)
     if n <= 0: n = 1   # make an array of at least one element
@@ -1177,7 +1202,13 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
     else:
       let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
-  of tySequence, tyRef, tyOptAsRef:
+  of tySequence:
+    if tfHasAsgn notin t.flags:
+      genTypeInfoAux(m, t, t, result, info)
+      if m.config.selectedGC >= gcMarkAndSweep:
+        let markerProc = genTraverseProc(m, origType, sig)
+        addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
+  of tyRef, tyOptAsRef:
     genTypeInfoAux(m, t, t, result, info)
     if m.config.selectedGC >= gcMarkAndSweep:
       let markerProc = genTraverseProc(m, origType, sig)
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 01a930de6..2cb431ff9 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -230,22 +230,31 @@ proc getTempName(m: BModule): Rope =
   result = m.tmpBase & rope(m.labels)
   inc m.labels
 
+proc rdLoc(a: TLoc): Rope =
+  # 'read' location (deref if indirect)
+  result = a.r
+  if lfIndirect in a.flags: result = "(*$1)" % [result]
+
 proc lenField(p: BProc): Rope =
   result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
 
+proc lenExpr(p: BProc; a: TLoc): Rope =
+  if p.config.selectedGc == gcDestructors:
+    result = rdLoc(a) & ".len"
+  else:
+    result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
+
 proc dataField(p: BProc): Rope =
-  result = rope"->data"
+  if p.config.selectedGc == gcDestructors:
+    result = rope".p->data"
+  else:
+    result = rope"->data"
 
 include ccgliterals
 include ccgtypes
 
 # ------------------------------ Manager of temporaries ------------------
 
-proc rdLoc(a: TLoc): Rope =
-  # 'read' location (deref if indirect)
-  result = a.r
-  if lfIndirect in a.flags: result = "(*$1)" % [result]
-
 proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
   result = a.r
   if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray:
@@ -325,7 +334,9 @@ proc resetLoc(p: BProc, loc: var TLoc) =
 
 proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
   let typ = loc.t
-  if not isComplexValueType(typ):
+  if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
+    linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", rdLoc(loc))
+  elif not isComplexValueType(typ):
     linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc),
       getTypeDesc(p.module, typ))
   else:
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 1e5384f16..f7c8cf9f2 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -215,7 +215,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
     of "refc":         result = conf.selectedGC == gcRefc
     of "v2":           result = conf.selectedGC == gcV2
     of "markandsweep": result = conf.selectedGC == gcMarkAndSweep
-    of "generational": result = conf.selectedGC == gcGenerational
+    of "generational": result = false
+    of "destructors":  result = conf.selectedGC == gcDestructors
     of "go":           result = conf.selectedGC == gcGo
     of "none":         result = conf.selectedGC == gcNone
     of "stack", "regions": result = conf.selectedGC == gcRegions
@@ -436,9 +437,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "markandsweep":
       conf.selectedGC = gcMarkAndSweep
       defineSymbol(conf.symbols, "gcmarkandsweep")
-    of "generational":
-      conf.selectedGC = gcGenerational
-      defineSymbol(conf.symbols, "gcgenerational")
+    of "destructors":
+      conf.selectedGC = gcDestructors
+      defineSymbol(conf.symbols, "gcdestructors")
     of "go":
       conf.selectedGC = gcGo
       defineSymbol(conf.symbols, "gogc")
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index ba1c42a74..0cf264ac3 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -74,6 +74,7 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimNoZeroTerminator")
   defineSymbol("nimNotNil")
   defineSymbol("nimVmExportFixed")
+  defineSymbol("nimNewRuntime")
   defineSymbol("nimIncrSeqV3")
   defineSymbol("nimAshr")
   defineSymbol("nimNoNilSeqs")
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index 0395728c2..bd735560a 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -100,12 +100,12 @@ Rule      Pattern                 Transformed into
                                   finally: `=destroy`(x)
 1.2       var x: sink T; stmts    var x: sink T; stmts; ensureEmpty(x)
 2         x = f()                 `=sink`(x, f())
-3         x = lastReadOf z        `=sink`(x, z)
+3         x = lastReadOf z        `=sink`(x, z); wasMoved(z)
 4.1       y = sinkParam           `=sink`(y, sinkParam)
 4.2       x = y                   `=`(x, y) # a copy
 5.1       f_sink(g())             f_sink(g())
 5.2       f_sink(y)               f_sink(copy y); # copy unless we can see it's the last read
-5.3       f_sink(move y)          f_sink(y); reset(y) # explicit moves empties 'y'
+5.3       f_sink(move y)          f_sink(y); wasMoved(y) # explicit moves empties 'y'
 5.4       f_noSink(g())           var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp)
 
 Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
@@ -258,8 +258,10 @@ proc registerDropBit(c: var Con; s: PSym) =
   c.toDropBit[s.id] = result
   # generate:
   #  if not sinkParam_AliveBit: `=destroy`(sinkParam)
-  c.destroys.add newTree(nkIfStmt,
-    newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s)))
+  let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink})
+  if t.destructor != nil:
+    c.destroys.add newTree(nkIfStmt,
+      newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s)))
 
 proc p(n: PNode; c: var Con): PNode
 
@@ -282,6 +284,11 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode =
     newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
   result.add n
 
+proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
+  result = newNodeI(nkCall, n.info)
+  result.add(newSymNode(createMagic(c.graph, magicname, m)))
+  result.add n
+
 proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
   if ri.kind in constrExprs:
     result = genSink(c, ri.typ, dest)
@@ -290,8 +297,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
     recurse(ri, ri2)
     result.add ri2
   elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
-    result = genSink(c, ri.typ, dest)
-    result.add p(ri, c)
+    # Rule 3: `=sink`(x, z); wasMoved(z)
+    var snk = genSink(c, ri.typ, dest)
+    snk.add p(ri, c)
+    result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
   elif ri.kind == nkSym and isSinkParam(ri.sym):
     result = genSink(c, ri.typ, dest)
     result.add destructiveMoveSink(ri, c)
@@ -313,11 +322,9 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
     result.add newTree(nkAsgn, tmp, p(n, c))
   result.add tmp
 
-proc genReset(n: PNode; c: var Con): PNode =
-  result = newNodeI(nkCall, n.info)
-  result.add(newSymNode(createMagic(c.graph, "reset", mReset)))
-  # The mReset builtin does not take the address:
-  result.add n
+proc genWasMoved(n: PNode; c: var Con): PNode =
+  # The mWasMoved builtin does not take the address.
+  result = genMagicCall(n, c, "wasMoved", mWasMoved)
 
 proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   # generate: (let tmp = v; reset(v); tmp)
@@ -334,7 +341,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   add(v, vpart)
 
   result.add v
-  result.add genReset(n, c)
+  result.add genWasMoved(n, c)
   result.add tempAsNode
 
 proc p(n: PNode; c: var Con): PNode =
diff --git a/compiler/options.nim b/compiler/options.nim
index 1873d9d5b..04b14c65f 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -104,8 +104,8 @@ type
     cmdJsonScript             # compile a .json build file
   TStringSeq* = seq[string]
   TGCMode* = enum             # the selected GC
-    gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc,
-    gcV2, gcGenerational
+    gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcDestructors,
+    gcRefc, gcV2
 
   IdeCmd* = enum
     ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod,
@@ -373,7 +373,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool =
     else: discard
 
 proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
-proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
+proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
 
 template compilationCachePresent*(conf: ConfigRef): untyped =
   conf.symbolFiles in {v2Sf, writeOnlySf}
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index a05ef7a28..8b2e20efc 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -197,13 +197,10 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   case t.kind
   of tyNone, tyEmpty, tyVoid: discard
   of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
-      tyPtr, tyString, tyRef, tyOpt:
+      tyPtr, tyRef, tyOpt:
     defaultOp(c, t, body, x, y)
-  of tyArray, tySequence:
+  of tyArray:
     if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}:
-      if t.kind == tySequence:
-        # XXX add 'nil' handling here
-        body.add newSeqCall(c.c, x, y)
       let i = declareCounter(c, body, firstOrd(c.c.config, t))
       let whileLoop = genWhileLoop(c, i, x)
       let elemType = t.lastSon
@@ -213,6 +210,27 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       body.add whileLoop
     else:
       defaultOp(c, t, body, x, y)
+  of tySequence:
+    # note that tfHasAsgn is propagated so we need the check on
+    # 'selectedGC' here to determine if we have the new runtime.
+    if c.c.config.selectedGC == gcDestructors:
+      discard considerOverloadedOp(c, t, body, x, y)
+    elif tfHasAsgn in t.flags:
+      body.add newSeqCall(c.c, x, y)
+      let i = declareCounter(c, body, firstOrd(c.c.config, t))
+      let whileLoop = genWhileLoop(c, i, x)
+      let elemType = t.lastSon
+      liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
+                                                  y.at(i, elemType))
+      addIncStmt(c, whileLoop.sons[1], i)
+      body.add whileLoop
+    else:
+      defaultOp(c, t, body, x, y)
+  of tyString:
+    if tfHasAsgn in t.flags:
+      discard considerOverloadedOp(c, t, body, x, y)
+    else:
+      defaultOp(c, t, body, x, y)
   of tyObject, tyDistinct:
     if not considerOverloadedOp(c, t, body, x, y):
       if t.sons[0] != nil:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 170ac799e..3a1278137 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1056,8 +1056,8 @@ proc checkForMetaFields(c: PContext; n: PNode) =
     case t.kind
     of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyLent, tyPtr, tyRef,
        tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink:
-      let start = int ord(t.kind in {tyGenericInvocation, tyGenericInst})
-      for i in start ..< t.sons.len:
+      let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
+      for i in start ..< t.len:
         checkMeta(t.sons[i])
     else:
       checkMeta(t)
@@ -1376,7 +1376,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
         elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
         else: break
-      if obj.kind in {tyObject, tyDistinct}:
+      if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
         if obj.destructor.isNil:
           obj.destructor = s
         else:
@@ -1398,7 +1398,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         if t.kind == tyGenericBody: t = t.lastSon
         elif t.kind == tyGenericInvocation: t = t.sons[0]
         else: break
-      if t.kind in {tyObject, tyDistinct, tyEnum}:
+      if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
         if t.deepCopy.isNil: t.deepCopy = s
         else:
           localError(c.config, n.info, errGenerated,
@@ -1427,7 +1427,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         elif objB.kind in {tyGenericInvocation, tyGenericInst}:
           objB = objB.sons[0]
         else: break
-      if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
+      if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB):
         let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink)
         if opr[].isNil:
           opr[] = s
@@ -1592,7 +1592,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
         localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
           ("'" & proto.name.s & "' from " & c.config$proto.info))
-    if sfForward notin proto.flags:
+    if sfForward notin proto.flags and proto.magic == mNone:
       wrongRedefinition(c, n.info, proto.name.s)
     excl(proto.flags, sfForward)
     closeScope(c)         # close scope with wrong parameter symbols
@@ -1658,7 +1658,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         openScope(c)
         n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
         closeScope(c)
-        fixupInstantiatedSymbols(c, s)
+        if s.magic == mNone:
+          fixupInstantiatedSymbols(c, s)
         if s.kind == skMethod: semMethodPrototype(c, s, n)
       if sfImportc in s.flags:
         # so we just ignore the body after semantic checking for importc:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 99f2cf20d..1669a7707 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -145,9 +145,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
     localError(c.config, n.info, errXExpectsOneTypeParam % "set")
     addSonSkipIntLit(result, errorType(c))
 
-proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
-                  prev: PType): PType =
-  result = newOrPrevType(kind, prev, c)
+proc semContainerArg(c: PContext; n: PNode, kindStr: string; result: PType) =
   if sonsLen(n) == 2:
     var base = semTypeNode(c, n.sons[1], nil)
     if base.kind == tyVoid:
@@ -157,6 +155,11 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
     localError(c.config, n.info, errXExpectsOneTypeParam % kindStr)
     addSonSkipIntLit(result, errorType(c))
 
+proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
+                  prev: PType): PType =
+  result = newOrPrevType(kind, prev, c)
+  semContainerArg(c, n, kindStr, result)
+
 proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyVarargs, prev, c)
   if sonsLen(n) == 2 or sonsLen(n) == 3:
@@ -1507,7 +1510,24 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     of mRange: result = semRange(c, n, prev)
     of mSet: result = semSet(c, n, prev)
     of mOrdinal: result = semOrdinal(c, n, prev)
-    of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
+    of mSeq:
+      if c.config.selectedGc == gcDestructors:
+        let s = c.graph.sysTypes[tySequence]
+        assert s != nil
+        assert prev == nil
+        result = copyType(s, s.owner, keepId=false)
+        # XXX figure out why this has children already...
+        result.sons.setLen 0
+        result.n = nil
+        if c.config.selectedGc == gcDestructors:
+          result.flags = {tfHasAsgn}
+        else:
+          result.flags = {}
+        semContainerArg(c, n, "seq", result)
+      else:
+        result = semContainer(c, n, tySequence, "seq", prev)
+        if c.config.selectedGc == gcDestructors:
+          incl result.flags, tfHasAsgn
     of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
     of mVarargs: result = semVarargs(c, n, prev)
     of mTypeDesc, mTypeTy:
@@ -1687,6 +1707,9 @@ proc processMagicType(c: PContext, m: PSym) =
   of mString:
     setMagicType(c.config, m, tyString, c.config.target.ptrSize)
     rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
+    when false:
+      if c.config.selectedGc == gcDestructors:
+        incl m.typ.flags, tfHasAsgn
   of mCstring:
     setMagicType(c.config, m, tyCString, c.config.target.ptrSize)
     rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
@@ -1726,6 +1749,10 @@ proc processMagicType(c: PContext, m: PSym) =
     setMagicType(c.config, m, tySet, 0)
   of mSeq:
     setMagicType(c.config, m, tySequence, 0)
+    if c.config.selectedGc == gcDestructors:
+      incl m.typ.flags, tfHasAsgn
+    assert c.graph.sysTypes[tySequence] == nil
+    c.graph.sysTypes[tySequence] = m.typ
   of mOpt:
     setMagicType(c.config, m, tyOpt, 0)
   of mOrdinal:
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 3a276dc38..84297aa6a 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -1050,8 +1050,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     when useEffectSystem: trackTopLevelStmt(g, module, result)
     #if n.info ?? "temp.nim":
     #  echo renderTree(result, {renderIds})
-    if c.needsDestroyPass:
-      result = injectDestructorCalls(g, module, result)
+    #if c.needsDestroyPass:
+    #  result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
 proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
@@ -1063,6 +1063,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     liftDefer(c, result)
     # expressions are not to be injected with destructor calls as that
     # the list of top level statements needs to be collected before.
-    if c.needsDestroyPass:
-      result = injectDestructorCalls(g, module, result)
+    #if c.needsDestroyPass:
+    #  result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/types.nim b/compiler/types.nim
index 80624502c..674819bc5 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -278,6 +278,8 @@ proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
 proc isGCRef(t: PType): bool =
   result = t.kind in GcTypeKinds or
     (t.kind == tyProc and t.callConv == ccClosure)
+  if result and t.kind in {tyString, tySequence} and tfHasAsgn in t.flags:
+    result = false
 
 proc containsGarbageCollectedRef*(typ: PType): bool =
   # returns true if typ contains a reference, sequence or string (all the
@@ -1339,14 +1341,23 @@ proc computeSizeAux(conf: ConfigRef; typ: PType, a: var BiggestInt): BiggestInt
     if typ.callConv == ccClosure: result = 2 * conf.target.ptrSize
     else: result = conf.target.ptrSize
     a = conf.target.ptrSize
-  of tyString, tyNil:
+  of tyString:
+    if tfHasAsgn in typ.flags:
+      result = conf.target.ptrSize * 2
+    else:
+      result = conf.target.ptrSize
+  of tyNil:
     result = conf.target.ptrSize
     a = result
   of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray:
     let base = typ.lastSon
     if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion):
       result = szIllegalRecursion
-    else: result = conf.target.ptrSize
+    else:
+      if typ.kind == tySequence and tfHasAsgn in typ.flags:
+        result = conf.target.ptrSize * 2
+      else:
+        result = conf.target.ptrSize
     a = result
   of tyArray:
     let elemSize = computeSizeAux(conf, typ.sons[1], a)