scoped memory management (#14790)
* fixes the regressions * closes #13936 * scope based memory management implemented * enabled tcontrolflow.nim test case * final cleanups
This commit is contained in:
parent
695154970d
commit
1854d29781
17 changed files with 611 additions and 477 deletions
|
|
@ -644,7 +644,33 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
|||
pl.add(~"];$n")
|
||||
line(p, cpsStmts, pl)
|
||||
|
||||
proc notYetAlive(n: PNode): bool {.inline.} =
|
||||
let r = getRoot(n)
|
||||
result = r != nil and r.loc.lode == nil
|
||||
|
||||
proc isInactiveDestructorCall(p: BProc, e: PNode): bool =
|
||||
#[ Consider this example.
|
||||
|
||||
var :tmpD_3281815
|
||||
try:
|
||||
if true:
|
||||
return
|
||||
let args_3280013 =
|
||||
wasMoved_3281816(:tmpD_3281815)
|
||||
`=_3280036`(:tmpD_3281815, [1])
|
||||
:tmpD_3281815
|
||||
finally:
|
||||
`=destroy_3280027`(args_3280013)
|
||||
|
||||
We want to return early but the 'finally' section is traversed before
|
||||
the 'let args = ...' statement. We exploit this to generate better
|
||||
code for 'return'. ]#
|
||||
result = e.len == 2 and e[0].kind == nkSym and
|
||||
e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr)
|
||||
|
||||
proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
||||
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, e):
|
||||
return
|
||||
if e[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
|
||||
genClosureCall(p, nil, e, d)
|
||||
elif e[0].kind == nkSym and sfInfixCall in e[0].sym.flags:
|
||||
|
|
|
|||
|
|
@ -2066,10 +2066,14 @@ proc skipAddr(n: PNode): PNode =
|
|||
|
||||
proc genWasMoved(p: BProc; n: PNode) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n[1].skipAddr, a)
|
||||
resetLoc(p, a)
|
||||
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
|
||||
let n1 = n[1].skipAddr
|
||||
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
|
||||
discard
|
||||
else:
|
||||
initLocExpr(p, n1, a)
|
||||
resetLoc(p, a)
|
||||
#linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||
# [addrLoc(p.config, a), getTypeDesc(p.module, a.t)])
|
||||
|
||||
proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||
var a: TLoc
|
||||
|
|
@ -2593,10 +2597,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
|||
else:
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skTemp:
|
||||
if sym.loc.r == nil:
|
||||
# we now support undeclared 'skTemp' variables for easier
|
||||
# transformations in other parts of the compiler:
|
||||
assignLocalVar(p, n)
|
||||
when false:
|
||||
# this is more harmful than helpful.
|
||||
if sym.loc.r == nil:
|
||||
# we now support undeclared 'skTemp' variables for easier
|
||||
# transformations in other parts of the compiler:
|
||||
assignLocalVar(p, n)
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
#echo renderTree(p.prc.ast, {renderIds})
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
|||
|
||||
var stack = newSeq[tuple[fin: PNode, inExcept: bool, label: Natural]](0)
|
||||
|
||||
inc p.withinBlockLeaveActions
|
||||
for i in 1..howManyTrys:
|
||||
let tryStmt = p.nestedTryStmts.pop
|
||||
if p.config.exc == excSetjmp:
|
||||
|
|
@ -217,6 +218,8 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
|||
if finallyStmt != nil:
|
||||
genStmts(p, finallyStmt[0])
|
||||
|
||||
dec p.withinBlockLeaveActions
|
||||
|
||||
# push old elements again:
|
||||
for i in countdown(howManyTrys-1, 0):
|
||||
p.nestedTryStmts.add(stack[i])
|
||||
|
|
@ -861,10 +864,10 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
|
|||
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||
|
||||
proc branchHasTooBigRange(b: PNode): bool =
|
||||
for i in 0..<b.len-1:
|
||||
for it in b:
|
||||
# last son is block
|
||||
if (b[i].kind == nkRange) and
|
||||
b[i][1].intVal - b[i][0].intVal > RangeExpandLimit:
|
||||
if (it.kind == nkRange) and
|
||||
it[1].intVal - it[0].intVal > RangeExpandLimit:
|
||||
return true
|
||||
|
||||
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
|
|
@ -988,9 +991,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
|||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
p.nestedTryStmts.add((fin, false, 0.Natural))
|
||||
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t[0], d)
|
||||
endBlock(p)
|
||||
if t.kind == nkHiddenTryStmt:
|
||||
lineCg(p, cpsStmts, "try {$n", [])
|
||||
expr(p, t[0], d)
|
||||
lineCg(p, cpsStmts, "}$n", [])
|
||||
else:
|
||||
startBlock(p, "try {$n")
|
||||
expr(p, t[0], d)
|
||||
endBlock(p)
|
||||
|
||||
# First pass: handle Nim based exceptions:
|
||||
lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1])
|
||||
|
|
@ -1335,13 +1343,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
|||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
|
||||
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
p.nestedTryStmts.add((fin, quirkyExceptions, 0.Natural))
|
||||
expr(p, t[0], d)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
endBlock(p)
|
||||
lineCg(p, cpsStmts, "}$n", [])
|
||||
startBlock(p, "else {$n")
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
genRestoreFrameAfterException(p)
|
||||
|
|
|
|||
|
|
@ -1561,7 +1561,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
|
|||
if sfSystemModule in m.module.flags:
|
||||
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC != gcNone:
|
||||
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
|
||||
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
|
||||
|
||||
if m.s[cfsInitProc].len > 0:
|
||||
|
|
@ -1666,6 +1666,10 @@ proc genInitCode(m: BModule) =
|
|||
writeSection(preInitProc, cpsInit, m.hcrOn)
|
||||
writeSection(preInitProc, cpsStmts)
|
||||
prc.addf("}$N", [])
|
||||
when false:
|
||||
m.initProc.blocks[0].sections[cpsLocals].add m.preInitProc.s(cpsLocals)
|
||||
m.initProc.blocks[0].sections[cpsInit].prepend m.preInitProc.s(cpsInit)
|
||||
m.initProc.blocks[0].sections[cpsStmts].prepend m.preInitProc.s(cpsStmts)
|
||||
|
||||
# add new scope for following code, because old vcc compiler need variable
|
||||
# be defined at the top of the block
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ type
|
|||
# requires 'T x = T()' to become 'T x; x = T()'
|
||||
# (yes, C++ is weird like that)
|
||||
withinTryWithExcept*: int # required for goto based exception handling
|
||||
withinBlockLeaveActions*: int # complex to explain
|
||||
sigConflicts*: CountTable[string]
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -229,8 +229,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
|||
a[0][2] = newSymNode(symbol, a[0][2].info)
|
||||
|
||||
elif a.len == 1:
|
||||
# count number of ``except: body`` blocks
|
||||
inc catchAllExcepts
|
||||
# count number of ``except: body`` blocks
|
||||
inc catchAllExcepts
|
||||
|
||||
else:
|
||||
# support ``except KeyError, ValueError, ... : body``
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
## This module implements threadpool's ``spawn``.
|
||||
|
||||
import ast, types, idents, magicsys, msgs, options, modulegraphs,
|
||||
lowerings, liftdestructors
|
||||
lowerings, liftdestructors, renderer
|
||||
from trees import getMagic, getRoot
|
||||
|
||||
proc callProc(a: PNode): PNode =
|
||||
|
|
@ -321,7 +321,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: P
|
|||
result = newNodeI(nkStmtList, n.info)
|
||||
|
||||
if n.kind notin nkCallKinds:
|
||||
localError(g.config, n.info, "'spawn' takes a call expression")
|
||||
localError(g.config, n.info, "'spawn' takes a call expression; got " & $n)
|
||||
return
|
||||
if optThreadAnalysis in g.config.globalOptions:
|
||||
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue