diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-10-10 21:00:45 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-10-10 21:00:54 +0200 |
commit | 0803b532f44fc7b0039e31187af76e36828ca89d (patch) | |
tree | fe140126c06fb696ca90d9806408f72fa50cb475 /compiler | |
parent | 6620b5dc8d231dfd846072aa060f414e5e2e3838 (diff) | |
download | Nim-0803b532f44fc7b0039e31187af76e36828ca89d.tar.gz |
fixes #9263
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/destroyer.nim | 142 |
1 files changed, 80 insertions, 62 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 599d97c22..56cc02171 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -282,8 +282,6 @@ template recurse(n, dest) = proc isSinkParam(s: PSym): bool {.inline.} = result = s.kind == skParam and s.typ.kind == tySink -const constrExprs = nkCallKinds+{nkObjConstr} - proc destructiveMoveSink(n: PNode; c: var Con): PNode = # generate: (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam) result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -299,39 +297,6 @@ proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = 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, dest.typ, dest, ri) - # watch out and no not transform 'ri' twice if it's a call: - let ri2 = copyNode(ri) - recurse(ri, ri2) - result.add ri2 - elif ri.kind == nkSym and ri.sym.kind != skParam and isHarmlessVar(ri.sym, c): - # Rule 3: `=sink`(x, z); wasMoved(z) - var snk = genSink(c, dest.typ, dest, ri) - 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, dest.typ, dest, ri) - result.add destructiveMoveSink(ri, c) - else: - result = genCopy(c, dest.typ, dest, ri) - result.add p(ri, c) - -proc passCopyToSink(n: PNode; c: var Con): PNode = - result = newNodeIT(nkStmtListExpr, n.info, n.typ) - let tmp = getTemp(c, n.typ, n.info) - if hasDestructor(n.typ): - var m = genCopy(c, n.typ, tmp, n) - m.add p(n, c) - result.add m - message(c.graph.config, n.info, hintPerformance, - ("passing '$1' to a sink parameter introduces an implicit copy; " & - "use 'move($1)' to prevent it") % $n) - else: - result.add newTree(nkAsgn, tmp, p(n, c)) - result.add tmp - proc genWasMoved(n: PNode; c: var Con): PNode = # The mWasMoved builtin does not take the address. result = genMagicCall(n, c, "wasMoved", mWasMoved) @@ -355,6 +320,83 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = result.add genWasMoved(n, c) result.add tempAsNode +proc passCopyToSink(n: PNode; c: var Con): PNode = + result = newNodeIT(nkStmtListExpr, n.info, n.typ) + let tmp = getTemp(c, n.typ, n.info) + if hasDestructor(n.typ): + var m = genCopy(c, n.typ, tmp, n) + m.add p(n, c) + result.add m + message(c.graph.config, n.info, hintPerformance, + ("passing '$1' to a sink parameter introduces an implicit copy; " & + "use 'move($1)' to prevent it") % $n) + else: + result.add newTree(nkAsgn, tmp, p(n, c)) + result.add tmp + +proc pArg(arg: PNode; c: var Con; isSink: bool): PNode = + if isSink: + if arg.kind in nkCallKinds: + # recurse but skip the call expression in order to prevent + # destructor injections: Rule 5.1 is different from rule 5.4! + let a = copyNode(arg) + recurse(arg, a) + result = a + elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}: + discard "object construction to sink parameter: nothing to do" + result = arg + elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isHarmlessVar(arg.sym, c): + # if x is a variable and it its last read we eliminate its + # destructor invokation, but don't. We need to reset its memory + # to disable its destructor which we have not elided: + result = destructiveMoveVar(arg, c) + elif arg.kind == nkSym and isSinkParam(arg.sym): + # mark the sink parameter as used: + result = destructiveMoveSink(arg, c) + else: + # an object that is not temporary but passed to a 'sink' parameter + # results in a copy. + result = passCopyToSink(arg, c) + else: + result = p(arg, c) + +proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = + case ri.kind + of nkCallKinds: + result = genSink(c, dest.typ, dest, ri) + # watch out and no not transform 'ri' twice if it's a call: + let ri2 = copyNode(ri) + let parameters = ri[0].typ + let L = if parameters != nil: parameters.len else: 0 + ri2.add ri[0] + for i in 1..<ri.len: + ri2.add pArg(ri[i], c, i < L and parameters[i].kind == tySink) + #recurse(ri, ri2) + result.add ri2 + of nkObjConstr: + result = genSink(c, dest.typ, dest, ri) + let ri2 = copyTree(ri) + for i in 1..<ri.len: + # everything that is passed to an object constructor is consumed, + # so these all act like 'sink' parameters: + ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true) + result.add ri2 + of nkSym: + if ri.sym.kind != skParam and isHarmlessVar(ri.sym, c): + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = genSink(c, dest.typ, dest, ri) + snk.add p(ri, c) + result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) + elif isSinkParam(ri.sym): + result = genSink(c, dest.typ, dest, ri) + result.add destructiveMoveSink(ri, c) + else: + result = genCopy(c, dest.typ, dest, ri) + result.add p(ri, c) + else: + result = genCopy(c, dest.typ, dest, ri) + result.add p(ri, c) + proc p(n: PNode; c: var Con): PNode = case n.kind of nkVarSection, nkLetSection: @@ -392,31 +434,7 @@ proc p(n: PNode; c: var Con): PNode = let parameters = n[0].typ let L = if parameters != nil: parameters.len else: 0 for i in 1 ..< n.len: - let arg = n[i] - if i < L and parameters[i].kind == tySink: - if arg.kind in nkCallKinds: - # recurse but skip the call expression in order to prevent - # destructor injections: Rule 5.1 is different from rule 5.4! - let a = copyNode(arg) - recurse(arg, a) - n.sons[i] = a - elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}: - discard "object construction to sink parameter: nothing to do" - elif arg.kind == nkSym and isHarmlessVar(arg.sym, c): - # if x is a variable and it its last read we eliminate its - # destructor invokation, but don't. We need to reset its memory - # to disable its destructor which we have not elided: - n.sons[i] = destructiveMoveVar(arg, c) - elif arg.kind == nkSym and isSinkParam(arg.sym): - # mark the sink parameter as used: - n.sons[i] = destructiveMoveSink(arg, c) - else: - # an object that is not temporary but passed to a 'sink' parameter - # results in a copy. - n.sons[i] = passCopyToSink(arg, c) - else: - n.sons[i] = p(arg, c) - + n.sons[i] = pArg(n[i], c, i < L and parameters[i].kind == tySink) if n.typ != nil and hasDestructor(n.typ): discard "produce temp creation" result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -442,7 +460,7 @@ proc p(n: PNode; c: var Con): PNode = recurse(n, result) proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = - when defined(nimDebugDestroys): + when false: # defined(nimDebugDestroys): echo "injecting into ", n var c: Con c.owner = owner @@ -477,7 +495,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = result.add body when defined(nimDebugDestroys): - if owner.name.s == "main" or true: + if owner.name.s == "test1": # or true: echo "------------------------------------" echo owner.name.s, " transformed to: " echo result |