destructors: first version of 'sink' parameter logic
This commit is contained in:
parent
61f00da4bc
commit
455dd36135
2 changed files with 33 additions and 47 deletions
|
|
@ -453,8 +453,6 @@ type
|
||||||
nfPreventCg # this node should be ignored by the codegen
|
nfPreventCg # this node should be ignored by the codegen
|
||||||
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
nfBlockArg # this a stmtlist appearing in a call (e.g. a do block)
|
||||||
nfFromTemplate # a top-level node returned from a template
|
nfFromTemplate # a top-level node returned from a template
|
||||||
nfPreventDestructor # prevent destructor injectsion for the node
|
|
||||||
# (but not necessarily its children)
|
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: beyond that)
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,6 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
|
||||||
not allowed as a local variable.
|
not allowed as a local variable.
|
||||||
|
|
||||||
``move`` builtin needs to be implemented.
|
``move`` builtin needs to be implemented.
|
||||||
|
|
||||||
XXX Think about nfPreventDestructor logic.
|
|
||||||
]##
|
]##
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
@ -305,7 +303,6 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||||
m.add n
|
m.add n
|
||||||
result.add m
|
result.add m
|
||||||
result.add tmp
|
result.add tmp
|
||||||
incl result.flags, nfPreventDestructor
|
|
||||||
message(n.info, hintPerformance,
|
message(n.info, hintPerformance,
|
||||||
"passing '$1' to a sink parameter introduces an implicit copy; " &
|
"passing '$1' to a sink parameter introduces an implicit copy; " &
|
||||||
"use 'move($1)' to prevent it" % $n)
|
"use 'move($1)' to prevent it" % $n)
|
||||||
|
|
@ -333,39 +330,6 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
|
||||||
result.add v
|
result.add v
|
||||||
result.add genReset(n, c)
|
result.add genReset(n, c)
|
||||||
result.add tempAsNode
|
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 =
|
proc p(n: PNode; c: var Con): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -401,21 +365,45 @@ proc p(n: PNode; c: var Con): PNode =
|
||||||
varSection.add itCopy
|
varSection.add itCopy
|
||||||
result.add varSection
|
result.add varSection
|
||||||
of nkCallKinds:
|
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"
|
discard "produce temp creation"
|
||||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||||
let tmp = getTemp(c, n.typ, n.info)
|
let tmp = getTemp(c, n.typ, n.info)
|
||||||
var m = genSink(n.typ, tmp)
|
var sinkExpr = genSink(n.typ, tmp)
|
||||||
var call = copyNode(n)
|
sinkExpr.add n
|
||||||
recurse(n, call)
|
result.add sinkExpr
|
||||||
m.add call
|
|
||||||
result.add m
|
|
||||||
result.add tmp
|
result.add tmp
|
||||||
c.destroys.add genDestroy(n.typ, tmp)
|
c.destroys.add genDestroy(n.typ, tmp)
|
||||||
else:
|
else:
|
||||||
result = copyNode(n)
|
result = n
|
||||||
recurse(n, result)
|
|
||||||
#handleSinkParams(result, c)
|
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
if hasDestructor(n[0].typ):
|
if hasDestructor(n[0].typ):
|
||||||
result = moveOrCopy(n[0], n[1], c)
|
result = moveOrCopy(n[0], n[1], c)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue