parent
f25384adc8
commit
38d82795da
5 changed files with 75 additions and 36 deletions
|
|
@ -222,14 +222,14 @@ proc initialized(code: ControlFlowGraph; pc: int,
|
||||||
inc pc
|
inc pc
|
||||||
return pc
|
return pc
|
||||||
|
|
||||||
proc isCursor(n: PNode; c: Con): bool =
|
proc isCursor(n: PNode): bool =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
sfCursor in n.sym.flags
|
sfCursor in n.sym.flags
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
isCursor(n[1], c)
|
isCursor(n[1])
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
isCursor(n[0], c)
|
isCursor(n[0])
|
||||||
else:
|
else:
|
||||||
false
|
false
|
||||||
|
|
||||||
|
|
@ -528,23 +528,19 @@ proc cycleCheck(n: PNode; c: var Con) =
|
||||||
message(c.graph.config, n.info, warnCycleCreated, msg)
|
message(c.graph.config, n.info, warnCycleCreated, msg)
|
||||||
break
|
break
|
||||||
|
|
||||||
proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; ri, res: PNode) =
|
proc pVarTopLevel(v: PNode; c: var Con; s: var Scope; res: PNode) =
|
||||||
# move the variable declaration to the top of the frame:
|
# move the variable declaration to the top of the frame:
|
||||||
s.vars.add v.sym
|
s.vars.add v.sym
|
||||||
if isUnpackedTuple(v):
|
if isUnpackedTuple(v):
|
||||||
if c.inLoop > 0:
|
if c.inLoop > 0:
|
||||||
# unpacked tuple needs reset at every loop iteration
|
# unpacked tuple needs reset at every loop iteration
|
||||||
res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info))
|
res.add newTree(nkFastAsgn, v, genDefaultCall(v.typ, c, v.info))
|
||||||
elif sfThread notin v.sym.flags:
|
elif sfThread notin v.sym.flags and sfCursor notin v.sym.flags:
|
||||||
# do not destroy thread vars for now at all for consistency.
|
# do not destroy thread vars for now at all for consistency.
|
||||||
if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2)
|
if sfGlobal in v.sym.flags and s.parent == nil: #XXX: Rethink this logic (see tarcmisc.test2)
|
||||||
c.graph.globalDestructors.add c.genDestroy(v)
|
c.graph.globalDestructors.add c.genDestroy(v)
|
||||||
else:
|
else:
|
||||||
s.final.add c.genDestroy(v)
|
s.final.add c.genDestroy(v)
|
||||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
|
||||||
res.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = true)
|
|
||||||
elif ri.kind != nkEmpty:
|
|
||||||
res.add moveOrCopy(v, ri, c, s, isDecl = true)
|
|
||||||
|
|
||||||
proc processScope(c: var Con; s: var Scope; ret: PNode): PNode =
|
proc processScope(c: var Con; s: var Scope; ret: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, ret.info)
|
result = newNodeI(nkStmtList, ret.info)
|
||||||
|
|
@ -744,7 +740,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||||
nkCallKinds + nkLiterals:
|
nkCallKinds + nkLiterals:
|
||||||
result = p(n, c, s, consumed)
|
result = p(n, c, s, consumed)
|
||||||
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
|
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
|
||||||
isLastRead(n, c) and not (n.kind == nkSym and isCursor(n, c)):
|
isLastRead(n, c) and not (n.kind == nkSym and isCursor(n)):
|
||||||
# Sinked params can be consumed only once. We need to reset the memory
|
# Sinked params can be consumed only once. We need to reset the memory
|
||||||
# to disable the destructor which we have not elided
|
# to disable the destructor which we have not elided
|
||||||
result = destructiveMoveVar(n, c, s)
|
result = destructiveMoveVar(n, c, s)
|
||||||
|
|
@ -850,17 +846,16 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||||
if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
|
if it.kind == nkVarTuple and hasDestructor(c, ri.typ):
|
||||||
let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner)
|
let x = lowerTupleUnpacking(c.graph, it, c.idgen, c.owner)
|
||||||
result.add p(x, c, s, consumed)
|
result.add p(x, c, s, consumed)
|
||||||
elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c):
|
elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ):
|
||||||
for j in 0..<it.len-2:
|
for j in 0..<it.len-2:
|
||||||
let v = it[j]
|
let v = it[j]
|
||||||
if v.kind == nkSym:
|
if v.kind == nkSym:
|
||||||
if sfCompileTime in v.sym.flags: continue
|
if sfCompileTime in v.sym.flags: continue
|
||||||
pVarTopLevel(v, c, s, ri, result)
|
pVarTopLevel(v, c, s, result)
|
||||||
else:
|
if ri.kind != nkEmpty:
|
||||||
if ri.kind == nkEmpty and c.inLoop > 0:
|
result.add moveOrCopy(v, ri, c, s, isDecl = v.kind == nkSym)
|
||||||
ri = genDefaultCall(v.typ, c, v.info)
|
elif ri.kind == nkEmpty and c.inLoop > 0:
|
||||||
if ri.kind != nkEmpty:
|
result.add moveOrCopy(v, genDefaultCall(v.typ, c, v.info), c, s, isDecl = v.kind == nkSym)
|
||||||
result.add moveOrCopy(v, ri, c, s, isDecl = false)
|
|
||||||
else: # keep the var but transform 'ri':
|
else: # keep the var but transform 'ri':
|
||||||
var v = copyNode(n)
|
var v = copyNode(n)
|
||||||
var itCopy = copyNode(it)
|
var itCopy = copyNode(it)
|
||||||
|
|
@ -870,8 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
|
||||||
v.add itCopy
|
v.add itCopy
|
||||||
result.add v
|
result.add v
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and
|
if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda}:
|
||||||
not isCursor(n[0], c):
|
|
||||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||||
cycleCheck(n, c)
|
cycleCheck(n, c)
|
||||||
assert n[1].kind notin {nkAsgn, nkFastAsgn}
|
assert n[1].kind notin {nkAsgn, nkFastAsgn}
|
||||||
|
|
@ -1003,6 +997,14 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
|
||||||
if sameLocation(dest, ri):
|
if sameLocation(dest, ri):
|
||||||
# rule (self-assignment-removal):
|
# rule (self-assignment-removal):
|
||||||
result = newNodeI(nkEmpty, dest.info)
|
result = newNodeI(nkEmpty, dest.info)
|
||||||
|
elif isCursor(dest):
|
||||||
|
case ri.kind:
|
||||||
|
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
|
||||||
|
template process(child, s): untyped = moveOrCopy(dest, child, c, s, isDecl)
|
||||||
|
# We know the result will be a stmt so we use that fact to optimize
|
||||||
|
handleNestedTempl(ri, process, willProduceStmt = true)
|
||||||
|
else:
|
||||||
|
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
|
||||||
else:
|
else:
|
||||||
case ri.kind
|
case ri.kind
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
|
@ -1038,7 +1040,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, isDecl = false): PNod
|
||||||
let snk = c.genSink(dest, ri, isDecl)
|
let snk = c.genSink(dest, ri, isDecl)
|
||||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||||
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
|
||||||
isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri, c):
|
isLastRead(ri, c) and canBeMoved(c, dest.typ) and not isCursor(ri):
|
||||||
# Rule 3: `=sink`(x, z); wasMoved(z)
|
# Rule 3: `=sink`(x, z); wasMoved(z)
|
||||||
let snk = c.genSink(dest, ri, isDecl)
|
let snk = c.genSink(dest, ri, isDecl)
|
||||||
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ discard """
|
||||||
Section: local
|
Section: local
|
||||||
Param: Str
|
Param: Str
|
||||||
Param: Bool
|
Param: Bool
|
||||||
Param: Floats2'''
|
Param: Floats2
|
||||||
|
destroy Foo
|
||||||
|
destroy Foo
|
||||||
|
'''
|
||||||
cmd: '''nim c --gc:arc $file'''
|
cmd: '''nim c --gc:arc $file'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -123,4 +126,36 @@ when isMainModule:
|
||||||
for p in cfg.params(s):
|
for p in cfg.params(s):
|
||||||
echo " Param: " & p
|
echo " Param: " & p
|
||||||
|
|
||||||
|
# bug #16437
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object
|
||||||
|
FooRef = ref Foo
|
||||||
|
|
||||||
|
Bar = ref object
|
||||||
|
f: FooRef
|
||||||
|
|
||||||
|
proc `=destroy`(o: var Foo) =
|
||||||
|
echo "destroy Foo"
|
||||||
|
|
||||||
|
proc testMe(x: Bar) =
|
||||||
|
var c = (if x != nil: x.f else: nil)
|
||||||
|
assert c != nil
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
var b = Bar(f: FooRef())
|
||||||
|
testMe(b)
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
proc testMe2(x: Bar) =
|
||||||
|
var c: FooRef
|
||||||
|
c = (if x != nil: x.f else: nil)
|
||||||
|
assert c != nil
|
||||||
|
|
||||||
|
proc main2 =
|
||||||
|
var b = Bar(f: FooRef())
|
||||||
|
testMe2(b)
|
||||||
|
|
||||||
|
main2()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,18 @@ discard """
|
||||||
nimout: '''--expandArc: main
|
nimout: '''--expandArc: main
|
||||||
|
|
||||||
var
|
var
|
||||||
|
x_cursor
|
||||||
:tmpD
|
:tmpD
|
||||||
:tmpD_1
|
|
||||||
:tmpD_2
|
|
||||||
try:
|
try:
|
||||||
var x_cursor = ("hi", 5)
|
x_cursor = ("hi", 5)
|
||||||
x_cursor = if cond:
|
if cond:
|
||||||
:tmpD = ("different", 54)
|
x_cursor = ("different", 54) else:
|
||||||
:tmpD else:
|
x_cursor = ("string here", 80)
|
||||||
:tmpD_1 = ("string here", 80)
|
|
||||||
:tmpD_1
|
|
||||||
echo [
|
echo [
|
||||||
:tmpD_2 = `$`(x_cursor)
|
:tmpD = `$`(x_cursor)
|
||||||
:tmpD_2]
|
:tmpD]
|
||||||
finally:
|
finally:
|
||||||
`=destroy`(:tmpD_2)
|
`=destroy`(:tmpD)
|
||||||
-- end of expandArc ------------------------
|
-- end of expandArc ------------------------
|
||||||
--expandArc: sio
|
--expandArc: sio
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,12 +63,13 @@ result.value = move lvalue
|
||||||
--expandArc: tt
|
--expandArc: tt
|
||||||
|
|
||||||
var
|
var
|
||||||
|
it_cursor
|
||||||
a
|
a
|
||||||
:tmpD
|
:tmpD
|
||||||
:tmpD_1
|
:tmpD_1
|
||||||
:tmpD_2
|
:tmpD_2
|
||||||
try:
|
try:
|
||||||
var it_cursor = x
|
it_cursor = x
|
||||||
a = (
|
a = (
|
||||||
wasMoved(:tmpD)
|
wasMoved(:tmpD)
|
||||||
`=copy`(:tmpD, it_cursor.key)
|
`=copy`(:tmpD, it_cursor.key)
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,21 @@ discard """
|
||||||
cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
|
cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
|
||||||
nimout: '''--expandArc: traverse
|
nimout: '''--expandArc: traverse
|
||||||
|
|
||||||
var it_cursor = root
|
var
|
||||||
|
it_cursor
|
||||||
|
jt_cursor
|
||||||
|
it_cursor = root
|
||||||
block :tmp:
|
block :tmp:
|
||||||
while (
|
while (
|
||||||
not (it_cursor == nil)):
|
not (it_cursor == nil)):
|
||||||
echo [it_cursor.s]
|
echo [it_cursor.s]
|
||||||
it_cursor = it_cursor.ri
|
it_cursor = it_cursor.ri
|
||||||
var jt_cursor = root
|
jt_cursor = root
|
||||||
block :tmp_1:
|
block :tmp_1:
|
||||||
while (
|
while (
|
||||||
not (jt_cursor == nil)):
|
not (jt_cursor == nil)):
|
||||||
let ri_1_cursor = jt_cursor.ri
|
var ri_1_cursor
|
||||||
|
ri_1_cursor = jt_cursor.ri
|
||||||
echo [jt_cursor.s]
|
echo [jt_cursor.s]
|
||||||
jt_cursor = ri_1_cursor
|
jt_cursor = ri_1_cursor
|
||||||
-- end of expandArc ------------------------'''
|
-- end of expandArc ------------------------'''
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue