diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2018-03-31 20:27:08 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-03-31 20:27:08 +0200 |
commit | 455dd3613559ef43fc7609580d7658ceaa7a36fe (patch) | |
tree | f4f169f57d4d5debae1b8eb95911168d7def7408 | |
parent | 61f00da4bcb5f6e18588ee37acc066154c91b109 (diff) | |
download | Nim-455dd3613559ef43fc7609580d7658ceaa7a36fe.tar.gz |
destructors: first version of 'sink' parameter logic
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/destroyer.nim | 78 |
2 files changed, 33 insertions, 47 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 68bf95772..a28a7e7e3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -453,8 +453,6 @@ type nfPreventCg # this node should be ignored by the codegen nfBlockArg # this a stmtlist appearing in a call (e.g. a do block) nfFromTemplate # a top-level node returned from a template - nfPreventDestructor # prevent destructor injectsion for the node - # (but not necessarily its children) TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 9acc89be4..8c2e0dbc3 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -112,8 +112,6 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently not allowed as a local variable. ``move`` builtin needs to be implemented. - -XXX Think about nfPreventDestructor logic. ]## import @@ -305,7 +303,6 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = m.add n result.add m result.add tmp - incl result.flags, nfPreventDestructor message(n.info, hintPerformance, "passing '$1' to a sink parameter introduces an implicit copy; " & "use 'move($1)' to prevent it" % $n) @@ -333,39 +330,6 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = result.add v result.add genReset(n, c) result.add tempAsNode - incl result.flags, nfPreventDestructor - -proc handleSinkParams(n: PNode; c: var Con) = - # first pass: introduce copies for stuff passed to - # 'sink' parameters. Introduce destructor guards for - # 'sink' parameters. - assert n.kind in nkCallKinds - # Rule 5.2: Compensate for 'sink' parameters with copies - # at the callsite (unless of course we can prove its the - # last read): - let parameters = n.typ - let L = if parameters != nil: parameters.len else: 0 - for i in 1 ..< L: - let t = parameters[i] - if t.kind == tySink: - if n[i].kind in constrExprs: - incl(n[i].flags, nfPreventDestructor) - elif n[i].kind == nkSym and isHarmlessVar(n[i].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(n[i], c) - when false: - # XXX we need to find a way to compute "all paths consume 'x'" - c.symsNoDestructors.incl n[i].sym.id - # however, not emiting the copy operation is correct here. - elif n[i].kind == nkSym and isSinkParam(n[i].sym): - # mark the sink parameter as used: - n.sons[i] = destructiveMoveSink(n[i], c) - else: - # an object that is not temporary but passed to a 'sink' parameter - # results in a copy. - n.sons[i] = passCopyToSink(n[i], c) proc p(n: PNode; c: var Con): PNode = case n.kind @@ -401,21 +365,45 @@ proc p(n: PNode; c: var Con): PNode = varSection.add itCopy result.add varSection of nkCallKinds: - if n.typ != nil and hasDestructor(n.typ) and nfPreventDestructor notin n.flags: + let parameters = n.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 == nkObjConstr: + 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) + + if n.typ != nil and hasDestructor(n.typ): discard "produce temp creation" result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = getTemp(c, n.typ, n.info) - var m = genSink(n.typ, tmp) - var call = copyNode(n) - recurse(n, call) - m.add call - result.add m + var sinkExpr = genSink(n.typ, tmp) + sinkExpr.add n + result.add sinkExpr result.add tmp c.destroys.add genDestroy(n.typ, tmp) else: - result = copyNode(n) - recurse(n, result) - #handleSinkParams(result, c) + result = n of nkAsgn, nkFastAsgn: if hasDestructor(n[0].typ): result = moveOrCopy(n[0], n[1], c) |