summary refs log tree commit diff stats
path: root/compiler/injectdestructors.nim
diff options
context:
space:
mode:
authorcooldome <cdome@bk.ru>2020-01-17 11:44:06 +0000
committerGitHub <noreply@github.com>2020-01-17 11:44:06 +0000
commitf51613e262a18f6f56119d73f4c1431c8ebf6d3a (patch)
tree9b5894d7fdbb48972d5f4355deddd5dd972657d1 /compiler/injectdestructors.nim
parent76269074014b672582bc630ff393a95e5e21dcec (diff)
downloadNim-f51613e262a18f6f56119d73f4c1431c8ebf6d3a.tar.gz
make sink operator optional (#13068)
* make sink operator optional

* bug fix, add changelog entry

* Trigger build

* fix one regression

* fix test

* Trigger build

* fix typos
Diffstat (limited to 'compiler/injectdestructors.nim')
-rw-r--r--compiler/injectdestructors.nim60
1 files changed, 23 insertions, 37 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 127cc7723..27171ced6 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -230,6 +230,10 @@ proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
   addrExp.add(dest)
   result = newTree(nkCall, newSymNode(op), addrExp)
 
+proc genDestroy(c: Con; dest: PNode): PNode =
+  let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
+  result = genOp(c, t, attachedDestructor, dest, nil)
+
 when false:
   proc preventMoveRef(dest, ri: PNode): bool =
     let lhs = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
@@ -248,18 +252,17 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
 
 proc genSink(c: var Con; dest, ri: PNode): PNode =
   if isFirstWrite(dest, c): # optimize sink call into a bitwise memcopy
-    result = newTree(nkFastAsgn, dest)
+    result = newTree(nkFastAsgn, dest, ri)
   else:
     let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
-    let k = if t.attachedOps[attachedSink] != nil: attachedSink
-            else: attachedAsgn
-    if t.attachedOps[k] != nil:
-      result = genOp(c, t, k, dest, ri)
+    if t.attachedOps[attachedSink] != nil:
+      result = genOp(c, t, attachedSink, dest, ri)
+      result.add ri
     else:
-      # in rare cases only =destroy exists but no sink or assignment
-      # (see Pony object in tmove_objconstr.nim)
-      # we generate a fast assignment in this case:
-      result = newTree(nkFastAsgn, dest)
+      # the default is to use combination of `=destroy(dest)` and
+      # and copyMem(dest, source). This is efficient.
+      let snk = newTree(nkFastAsgn, dest, ri)
+      result = newTree(nkStmtList, genDestroy(c, dest), snk)
 
 proc genCopyNoCheck(c: Con; dest, ri: PNode): PNode =
   let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
@@ -273,10 +276,6 @@ proc genCopy(c: var Con; dest, ri: PNode): PNode =
     checkForErrorPragma(c, t, ri, "=")
   result = genCopyNoCheck(c, dest, ri)
 
-proc genDestroy(c: Con; dest: PNode): PNode =
-  let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink})
-  result = genOp(c, t, attachedDestructor, dest, nil)
-
 proc addTopVar(c: var Con; v: PNode) =
   c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
 
@@ -298,8 +297,6 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
 
 proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   # generate: (let tmp = v; reset(v); tmp)
-  # XXX: Strictly speaking we can only move if there is a ``=sink`` defined
-  # or if no ``=sink`` is defined and also no assignment.
   if not hasDestructor(n.typ):
     result = copyTree(n)
   else:
@@ -440,9 +437,7 @@ proc ensureDestruction(arg: PNode; c: var Con): PNode =
     # This was already done in the sink parameter handling logic.
     result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
     let tmp = getTemp(c, arg.typ, arg.info)
-    var sinkExpr = genSink(c, tmp, arg)
-    sinkExpr.add arg
-    result.add sinkExpr
+    result.add genSink(c, tmp, arg)
     result.add tmp
     c.destroys.add genDestroy(c, tmp)
   else:
@@ -598,8 +593,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
             if ri.kind == nkEmpty and c.inLoop > 0:
               ri = genDefaultCall(v.typ, c, v.info)
             if ri.kind != nkEmpty:
-              let r = moveOrCopy(v, ri, c)
-              result.add r
+              result.add moveOrCopy(v, ri, c)
         else: # keep the var but transform 'ri':
           var v = copyNode(n)
           var itCopy = copyNode(it)
@@ -667,8 +661,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
     if isUnpackedTuple(dest):
       result = newTree(nkFastAsgn, dest, p(ri, c, consumed))
     else:
-      result = genSink(c, dest, ri)
-      result.add p(ri, c, consumed)
+      result = genSink(c, dest, p(ri, c, consumed))
   of nkBracketExpr:
     if isUnpackedTuple(ri[0]):
       # unpacking of tuple: take over elements
@@ -677,7 +670,6 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
         not aliases(dest, ri):
       # Rule 3: `=sink`(x, z); wasMoved(z)
       var snk = genSink(c, dest, ri)
-      snk.add ri
       result = newTree(nkStmtList, snk, genWasMoved(ri, c))
     else:
       result = genCopy(c, dest, ri)
@@ -686,24 +678,21 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
     # array constructor
     if ri.len > 0 and isDangerousSeq(ri.typ):
       result = genCopy(c, dest, ri)
+      result.add p(ri, c, consumed)
     else:
-      result = genSink(c, dest, ri)
-    result.add p(ri, c, consumed)
+      result = genSink(c, dest, p(ri, c, consumed))
   of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
-    result = genSink(c, dest, ri)
-    result.add p(ri, c, consumed)
+    result = genSink(c, dest, p(ri, c, consumed))
   of nkSym:
     if isSinkParam(ri.sym):
       # Rule 3: `=sink`(x, z); wasMoved(z)
       sinkParamIsLastReadCheck(c, ri)
-      var snk = genSink(c, dest, ri)
-      snk.add ri
+      let snk = genSink(c, dest, ri)
       result = newTree(nkStmtList, snk, genWasMoved(ri, c))
     elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
         isLastRead(ri, c) and canBeMoved(c, dest.typ):
       # Rule 3: `=sink`(x, z); wasMoved(z)
-      var snk = genSink(c, dest, ri)
-      snk.add ri
+      let snk = genSink(c, dest, ri)
       result = newTree(nkStmtList, snk, genWasMoved(ri, c))
     else:
       result = genCopy(c, dest, ri)
@@ -716,8 +705,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
         copyRi[1] = result[^1]
         result[^1] = copyRi
     else:
-      result = genSink(c, dest, ri)
-      result.add p(ri, c, sinkArg)
+      result = genSink(c, dest, p(ri, c, sinkArg))
   of nkObjDownConv, nkObjUpConv:
     when false:
       result = moveOrCopy(dest, ri[0], c)
@@ -725,16 +713,14 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       copyRi[0] = result[^1]
       result[^1] = copyRi
     else:
-      result = genSink(c, dest, ri)
-      result.add p(ri, c, sinkArg)
+      result = genSink(c, dest, p(ri, c, sinkArg))
   of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt:
     handleNested(ri): moveOrCopy(dest, node, c)
   else:
     if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c) and
         canBeMoved(c, dest.typ):
       # Rule 3: `=sink`(x, z); wasMoved(z)
-      var snk = genSink(c, dest, ri)
-      snk.add ri
+      let snk = genSink(c, dest, ri)
       result = newTree(nkStmtList, snk, genWasMoved(ri, c))
     else:
       result = genCopy(c, dest, ri)