ARC: yet another bugfix (#12871)
This commit is contained in:
parent
56cf3403b4
commit
b8152b29e8
2 changed files with 52 additions and 25 deletions
|
|
@ -277,12 +277,13 @@ proc sinkParamIsLastReadCheck(c: var Con, s: PNode) =
|
||||||
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
|
||||||
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
"` is already consumed at " & toFileLineCol(c. graph.config, s.info))
|
||||||
|
|
||||||
type ProcessMode = enum
|
type
|
||||||
|
ProcessMode = enum
|
||||||
normal
|
normal
|
||||||
consumed
|
consumed
|
||||||
sinkArg
|
sinkArg
|
||||||
|
|
||||||
proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode
|
proc p(n: PNode; c: var Con; mode: ProcessMode): PNode
|
||||||
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode
|
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode
|
||||||
|
|
||||||
proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':'
|
proc isClosureEnv(n: PNode): bool = n.kind == nkSym and n.sym.name.s[0] == ':'
|
||||||
|
|
@ -295,14 +296,14 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
|
||||||
result.add genWasMoved(tmp, c)
|
result.add genWasMoved(tmp, c)
|
||||||
if hasDestructor(n.typ):
|
if hasDestructor(n.typ):
|
||||||
var m = genCopy(c, tmp, n)
|
var m = genCopy(c, tmp, n)
|
||||||
m.add p(n, c)
|
m.add p(n, c, normal)
|
||||||
result.add m
|
result.add m
|
||||||
if isLValue(n) and not isClosureEnv(n):
|
if isLValue(n) and not isClosureEnv(n):
|
||||||
message(c.graph.config, n.info, hintPerformance,
|
message(c.graph.config, 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)
|
||||||
else:
|
else:
|
||||||
result.add newTree(nkAsgn, tmp, p(n, c))
|
result.add newTree(nkAsgn, tmp, p(n, c, normal))
|
||||||
result.add tmp
|
result.add tmp
|
||||||
|
|
||||||
proc isDangerousSeq(t: PType): bool {.inline.} =
|
proc isDangerousSeq(t: PType): bool {.inline.} =
|
||||||
|
|
@ -330,7 +331,7 @@ template handleNested(n: untyped, processCall: untyped) =
|
||||||
if n.len == 0: return n
|
if n.len == 0: return n
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in 0..<n.len-1:
|
for i in 0..<n.len-1:
|
||||||
result.add p(n[i], c)
|
result.add p(n[i], c, normal)
|
||||||
template node: untyped = n[^1]
|
template node: untyped = n[^1]
|
||||||
result.add processCall
|
result.add processCall
|
||||||
of nkBlockStmt, nkBlockExpr:
|
of nkBlockStmt, nkBlockExpr:
|
||||||
|
|
@ -344,34 +345,34 @@ template handleNested(n: untyped, processCall: untyped) =
|
||||||
var branch = copyNode(son)
|
var branch = copyNode(son)
|
||||||
if son.kind in {nkElifBranch, nkElifExpr}:
|
if son.kind in {nkElifBranch, nkElifExpr}:
|
||||||
template node: untyped = son[1]
|
template node: untyped = son[1]
|
||||||
branch.add p(son[0], c) #The condition
|
branch.add p(son[0], c, normal) #The condition
|
||||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
branch.add if node.typ == nil: p(node, c, normal) #noreturn
|
||||||
else: processCall
|
else: processCall
|
||||||
else:
|
else:
|
||||||
template node: untyped = son[0]
|
template node: untyped = son[0]
|
||||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
branch.add if node.typ == nil: p(node, c, normal) #noreturn
|
||||||
else: processCall
|
else: processCall
|
||||||
result.add branch
|
result.add branch
|
||||||
of nkCaseStmt:
|
of nkCaseStmt:
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
result.add p(n[0], c)
|
result.add p(n[0], c, normal)
|
||||||
for i in 1..<n.len:
|
for i in 1..<n.len:
|
||||||
var branch: PNode
|
var branch: PNode
|
||||||
if n[i].kind == nkOfBranch:
|
if n[i].kind == nkOfBranch:
|
||||||
branch = n[i] # of branch conditions are constants
|
branch = n[i] # of branch conditions are constants
|
||||||
template node: untyped = n[i][^1]
|
template node: untyped = n[i][^1]
|
||||||
branch[^1] = if node.typ == nil: p(node, c) #noreturn
|
branch[^1] = if node.typ == nil: p(node, c, normal) #noreturn
|
||||||
else: processCall
|
else: processCall
|
||||||
elif n[i].kind in {nkElifBranch, nkElifExpr}:
|
elif n[i].kind in {nkElifBranch, nkElifExpr}:
|
||||||
branch = copyNode(n[i])
|
branch = copyNode(n[i])
|
||||||
branch.add p(n[i][0], c) #The condition
|
branch.add p(n[i][0], c, normal) #The condition
|
||||||
template node: untyped = n[i][1]
|
template node: untyped = n[i][1]
|
||||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
branch.add if node.typ == nil: p(node, c, normal) #noreturn
|
||||||
else: processCall
|
else: processCall
|
||||||
else:
|
else:
|
||||||
branch = copyNode(n[i])
|
branch = copyNode(n[i])
|
||||||
template node: untyped = n[i][0]
|
template node: untyped = n[i][0]
|
||||||
branch.add if node.typ == nil: p(node, c) #noreturn
|
branch.add if node.typ == nil: p(node, c, normal) #noreturn
|
||||||
else: processCall
|
else: processCall
|
||||||
result.add branch
|
result.add branch
|
||||||
of nkWhen: # This should be a "when nimvm" node.
|
of nkWhen: # This should be a "when nimvm" node.
|
||||||
|
|
@ -436,7 +437,7 @@ 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 p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
proc p(n: PNode; c: var Con; mode: ProcessMode): PNode =
|
||||||
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt, nkWhen}:
|
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt, nkWhen}:
|
||||||
handleNested(n): p(node, c, mode)
|
handleNested(n): p(node, c, mode)
|
||||||
elif mode == sinkArg:
|
elif mode == sinkArg:
|
||||||
|
|
@ -476,14 +477,29 @@ proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
||||||
else:
|
else:
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkBracket, nkObjConstr, nkTupleConstr, nkClosure:
|
of nkBracket, nkObjConstr, nkTupleConstr, nkClosure:
|
||||||
|
# Let C(x) be the construction, 'x' the vector of arguments.
|
||||||
|
# C(x) either owns 'x' or it doesn't.
|
||||||
|
# If C(x) owns its data, we must consume C(x).
|
||||||
|
# If it doesn't own the data, it's harmful to destroy it (double frees etc).
|
||||||
|
# We have the freedom to choose whether it owns it or not so we are smart about it
|
||||||
|
# and we say, "if passed to a sink we demand C(x) to own its data"
|
||||||
|
# otherwise we say "C(x) is just some temporary storage, it doesn't own anything,
|
||||||
|
# don't destroy it"
|
||||||
|
# but if C(x) is a ref it MUST own its data since we must destroy it
|
||||||
|
# so then we have no choice but to use 'sinkArg'.
|
||||||
|
let isRefConstr = n.kind == nkObjConstr and n.typ.skipTypes(abstractInst).kind == tyRef
|
||||||
|
let m = if isRefConstr: sinkArg
|
||||||
|
elif mode == normal: normal
|
||||||
|
else: sinkArg
|
||||||
|
|
||||||
result = copyTree(n)
|
result = copyTree(n)
|
||||||
for i in ord(n.kind in {nkObjConstr, nkClosure})..<n.len:
|
for i in ord(n.kind in {nkObjConstr, nkClosure})..<n.len:
|
||||||
let m = if mode == normal: normal
|
|
||||||
else: sinkArg
|
|
||||||
if n[i].kind == nkExprColonExpr:
|
if n[i].kind == nkExprColonExpr:
|
||||||
result[i][1] = p(n[i][1], c, m)
|
result[i][1] = p(n[i][1], c, m)
|
||||||
else:
|
else:
|
||||||
result[i] = p(n[i], c, m)
|
result[i] = p(n[i], c, m)
|
||||||
|
if mode == normal and isRefConstr:
|
||||||
|
result = ensureDestruction(result, c)
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
let parameters = n[0].typ
|
let parameters = n[0].typ
|
||||||
let L = if parameters != nil: parameters.len else: 0
|
let L = if parameters != nil: parameters.len else: 0
|
||||||
|
|
@ -537,7 +553,7 @@ proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
||||||
var itCopy = copyNode(it)
|
var itCopy = copyNode(it)
|
||||||
for j in 0..<it.len-1:
|
for j in 0..<it.len-1:
|
||||||
itCopy.add it[j]
|
itCopy.add it[j]
|
||||||
itCopy.add p(it[^1], c)
|
itCopy.add p(it[^1], c, normal)
|
||||||
v.add itCopy
|
v.add itCopy
|
||||||
result.add v
|
result.add v
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
|
|
@ -557,13 +573,13 @@ proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
||||||
of nkRaiseStmt:
|
of nkRaiseStmt:
|
||||||
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
|
||||||
if n[0].kind in nkCallKinds:
|
if n[0].kind in nkCallKinds:
|
||||||
let call = p(n[0], c)
|
let call = p(n[0], c, normal)
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
result.add call
|
result.add call
|
||||||
else:
|
else:
|
||||||
let tmp = getTemp(c, n[0].typ, n.info)
|
let tmp = getTemp(c, n[0].typ, n.info)
|
||||||
var m = genCopyNoCheck(c, tmp, n[0])
|
var m = genCopyNoCheck(c, tmp, n[0])
|
||||||
m.add p(n[0], c)
|
m.add p(n[0], c, normal)
|
||||||
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
result = newTree(nkStmtList, genWasMoved(tmp, c), m)
|
||||||
var toDisarm = n[0]
|
var toDisarm = n[0]
|
||||||
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
|
||||||
|
|
@ -579,8 +595,8 @@ proc p(n: PNode; c: var Con; mode: ProcessMode = normal): PNode =
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
inc c.inLoop
|
inc c.inLoop
|
||||||
result.add p(n[0], c)
|
result.add p(n[0], c, normal)
|
||||||
result.add p(n[1], c)
|
result.add p(n[1], c, normal)
|
||||||
dec c.inLoop
|
dec c.inLoop
|
||||||
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
|
||||||
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
|
||||||
|
|
@ -733,7 +749,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||||
|
|
||||||
#if optNimV2 in c.graph.config.globalOptions:
|
#if optNimV2 in c.graph.config.globalOptions:
|
||||||
# injectDefaultCalls(n, c)
|
# injectDefaultCalls(n, c)
|
||||||
let body = p(n, c)
|
let body = p(n, c, normal)
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
if c.topLevelVars.len > 0:
|
if c.topLevelVars.len > 0:
|
||||||
result.add c.topLevelVars
|
result.add c.topLevelVars
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,16 @@ proc inheritanceBug(param: string) =
|
||||||
s[0] = B(more: "a" & param)
|
s[0] = B(more: "a" & param)
|
||||||
s[1] = B(more: "a" & param)
|
s[1] = B(more: "a" & param)
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
PAsyncHttpServer = ref object
|
||||||
|
value: string
|
||||||
|
|
||||||
|
proc serve(server: PAsyncHttpServer) = discard
|
||||||
|
|
||||||
|
proc leakObjConstr =
|
||||||
|
serve(PAsyncHttpServer(value: "asdas"))
|
||||||
|
|
||||||
let startMem = getOccupiedMem()
|
let startMem = getOccupiedMem()
|
||||||
take3()
|
take3()
|
||||||
tlazyList()
|
tlazyList()
|
||||||
|
|
@ -89,4 +99,5 @@ inheritanceBug("whatever")
|
||||||
mkManyLeaks()
|
mkManyLeaks()
|
||||||
tsimpleClosureIterator()
|
tsimpleClosureIterator()
|
||||||
tleakingNewStmt()
|
tleakingNewStmt()
|
||||||
|
leakObjConstr()
|
||||||
echo getOccupiedMem() - startMem
|
echo getOccupiedMem() - startMem
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue