destructors/dfa: more documentation
This commit is contained in:
parent
a59f5e5a9d
commit
3e922d0fec
2 changed files with 39 additions and 7 deletions
|
|
@ -98,9 +98,16 @@ Rule Pattern Transformed into
|
||||||
---- ------- ----------------
|
---- ------- ----------------
|
||||||
1.1 var x: T; stmts var x: T; try stmts
|
1.1 var x: T; stmts var x: T; try stmts
|
||||||
finally: `=destroy`(x)
|
finally: `=destroy`(x)
|
||||||
1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x)
|
|
||||||
2 x = f() `=sink`(x, f())
|
2 x = f() `=sink`(x, f())
|
||||||
3 x = lastReadOf z `=sink`(x, z); wasMoved(z)
|
3 x = lastReadOf z `=sink`(x, z); wasMoved(z)
|
||||||
|
3.2 x = path z; body ``x = bitwiseCopy(path z);``
|
||||||
|
do not emit `=destroy(x)`. Note: body
|
||||||
|
must not mutate ``z`` nor ``x``. All
|
||||||
|
assignments to ``x`` must be of the form
|
||||||
|
``path z`` but the ``z`` can differ.
|
||||||
|
Neither ``z`` nor ``x`` can have the
|
||||||
|
flag ``sfAddrTaken`` to ensure no other
|
||||||
|
aliasing is going on.
|
||||||
4.1 y = sinkParam `=sink`(y, sinkParam)
|
4.1 y = sinkParam `=sink`(y, sinkParam)
|
||||||
4.2 x = y `=`(x, y) # a copy
|
4.2 x = y `=`(x, y) # a copy
|
||||||
5.1 f_sink(g()) f_sink(g())
|
5.1 f_sink(g()) f_sink(g())
|
||||||
|
|
@ -108,10 +115,33 @@ Rule Pattern Transformed into
|
||||||
5.3 f_sink(move y) f_sink(y); wasMoved(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)
|
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
|
Rule 3.2 describes a "cursor" variable, a variable that is only used as a
|
||||||
not allowed as a local variable.
|
view into some data structure. Rule 3.2 applies to value based
|
||||||
|
datatypes like strings and sequences and also ``ref`` cursors. We
|
||||||
|
seek to allow most forms of "scan" loops like::
|
||||||
|
|
||||||
``move`` builtin needs to be implemented.
|
var x = it
|
||||||
|
# scan loop:
|
||||||
|
while x != nil:
|
||||||
|
x.foo = value
|
||||||
|
x = x.next
|
||||||
|
|
||||||
|
The difference is that ``s[i] = y`` needs to be turned into a ``mut(s)``
|
||||||
|
for seqs and ``r.field = y`` is NOT turned into ``mut(r)`` as it doesn't
|
||||||
|
mutate the ``r`` itself. So the above loop is turned into something like::
|
||||||
|
|
||||||
|
use it
|
||||||
|
def x
|
||||||
|
L1:
|
||||||
|
fork L2
|
||||||
|
use value
|
||||||
|
use x
|
||||||
|
def x
|
||||||
|
L2:
|
||||||
|
|
||||||
|
Which means that ``x`` is detected as a "cursor". Rule 3.2 is not yet
|
||||||
|
implemented and requires either DFA changes or a different analysis.
|
||||||
|
Write-tracking also helps to compute this.
|
||||||
]##
|
]##
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,8 @@
|
||||||
## make this easier to handle: There are only 2 different branching
|
## make this easier to handle: There are only 2 different branching
|
||||||
## instructions: 'goto X' is an unconditional goto, 'fork X'
|
## instructions: 'goto X' is an unconditional goto, 'fork X'
|
||||||
## is a conditional goto (either the next instruction or 'X' can be
|
## is a conditional goto (either the next instruction or 'X' can be
|
||||||
## taken). Exhaustive case statements could be translated
|
## taken). Exhaustive case statements are translated
|
||||||
## so that the last branch is transformed into an 'else' branch, but
|
## so that the last branch is transformed into an 'else' branch.
|
||||||
## this is currently not done.
|
|
||||||
## ``return`` and ``break`` are all covered by 'goto'.
|
## ``return`` and ``break`` are all covered by 'goto'.
|
||||||
##
|
##
|
||||||
## Control flow through exception handling:
|
## Control flow through exception handling:
|
||||||
|
|
@ -596,6 +595,9 @@ proc genCall(c: var Con; n: PNode) =
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
gen(c, n[i])
|
gen(c, n[i])
|
||||||
if t != nil and i < t.len and t.sons[i].kind == tyVar:
|
if t != nil and i < t.len and t.sons[i].kind == tyVar:
|
||||||
|
# XXX This is wrong! Pass by var is a 'might def', not a 'must def'
|
||||||
|
# like the other defs we emit. This is not good enough for a move
|
||||||
|
# optimizer.
|
||||||
genDef(c, n[i])
|
genDef(c, n[i])
|
||||||
# every call can potentially raise:
|
# every call can potentially raise:
|
||||||
if c.inTryStmt > 0 and canRaise(n[0]):
|
if c.inTryStmt > 0 and canRaise(n[0]):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue