mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 06:20:38 +00:00
ARC: solves phase ordering problems (#12654)
This commit is contained in:
@@ -228,7 +228,7 @@ type
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # 39 flags!
|
||||
TSymFlag* = enum # 40 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
@@ -285,7 +285,7 @@ type
|
||||
# destruction for --newruntime.
|
||||
sfTemplateParam # symbol is a template parameter
|
||||
sfCursor # variable/field is a cursor, see RFC 177 for details
|
||||
|
||||
sfInjectDestructors # whether the proc needs the 'injectdestructors' transformation
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import
|
||||
nversion, nimsets, msgs, bitsets, idents, types,
|
||||
ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
|
||||
rodutils, renderer, cgendata, ccgmerge, aliases,
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf, enumtostr
|
||||
lowerings, tables, sets, ndi, lineinfos, pathutils, transf, enumtostr,
|
||||
injectdestructors
|
||||
|
||||
when not defined(leanCompiler):
|
||||
import spawn, semparallel
|
||||
@@ -531,7 +532,7 @@ proc assignGlobalVar(p: BProc, n: PNode) =
|
||||
var decl: Rope = nil
|
||||
var td = getTypeDesc(p.module, s.loc.t)
|
||||
if s.constraint.isNil:
|
||||
if s.alignment > 0:
|
||||
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
|
||||
decl.addf "alignas($1) ", [rope(s.alignment)]
|
||||
if p.hcrOn: add(decl, "static ")
|
||||
elif sfImportc in s.flags: add(decl, "extern ")
|
||||
@@ -957,7 +958,10 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
var header = genProcHeader(m, prc)
|
||||
var returnStmt: Rope = nil
|
||||
assert(prc.ast != nil)
|
||||
let procBody = transformBody(m.g.graph, prc, cache = false)
|
||||
|
||||
var procBody = transformBody(m.g.graph, prc, cache = false)
|
||||
if sfInjectDestructors in prc.flags:
|
||||
procBody = injectDestructorCalls(m.g.graph, prc, procBody)
|
||||
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
@@ -1857,7 +1861,10 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
m.initProc.options = initProcOptions(m)
|
||||
#softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
# XXX replicate this logic!
|
||||
let transformedN = transformStmt(m.g.graph, m.module, n)
|
||||
var transformedN = transformStmt(m.g.graph, m.module, n)
|
||||
if sfInjectDestructors in m.module.flags:
|
||||
transformedN = injectDestructorCalls(m.g.graph, m.module, transformedN)
|
||||
|
||||
if m.hcrOn:
|
||||
addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard)
|
||||
else:
|
||||
|
||||
@@ -33,7 +33,7 @@ import
|
||||
nversion, msgs, idents, types, tables,
|
||||
ropes, math, passes, ccgutils, wordrecg, renderer,
|
||||
intsets, cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
|
||||
transf
|
||||
transf, injectdestructors
|
||||
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
@@ -2259,7 +2259,10 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
|
||||
let transformedBody = transformBody(oldProc.module.graph, prc, cache = false)
|
||||
var transformedBody = transformBody(oldProc.module.graph, prc, cache = false)
|
||||
if sfInjectDestructors in prc.flags:
|
||||
transformedBody = injectDestructorCalls(oldProc.module.graph, prc, transformedBody)
|
||||
|
||||
p.nested: genStmt(p, transformedBody)
|
||||
|
||||
var def: Rope
|
||||
@@ -2540,7 +2543,9 @@ proc genModule(p: PProc, n: PNode) =
|
||||
add(p.body, frameCreate(p,
|
||||
makeJSString("module " & p.module.module.name.s),
|
||||
makeJSString(toFilename(p.config, p.module.module.info))))
|
||||
let transformedN = transformStmt(p.module.graph, p.module.module, n)
|
||||
var transformedN = transformStmt(p.module.graph, p.module.module, n)
|
||||
if sfInjectDestructors in p.module.module.flags:
|
||||
transformedN = injectDestructorCalls(p.module.graph, p.module.module, transformedN)
|
||||
if p.config.hcrOn and n.kind == nkStmtList:
|
||||
let moduleSym = p.module.module
|
||||
var moduleLoadedVar = rope(moduleSym.name.s) & "_loaded" &
|
||||
|
||||
@@ -296,7 +296,7 @@ type
|
||||
DetectionPass = object
|
||||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo, noDestructors: bool
|
||||
somethingToDo: bool
|
||||
graph: ModuleGraph
|
||||
|
||||
proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
|
||||
@@ -423,8 +423,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if innerProc:
|
||||
if s.isIterator: c.somethingToDo = true
|
||||
if not c.processed.containsOrIncl(s.id):
|
||||
let body = transformBody(c.graph, s, cache = true,
|
||||
noDestructors = c.noDestructors)
|
||||
let body = transformBody(c.graph, s, cache = true)
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
if ow == owner:
|
||||
@@ -714,7 +713,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = transformBody(d.graph, s)
|
||||
var body = transformBody(d.graph, s, cache = false)
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envVars.getOrDefault(s.id).isNil:
|
||||
s.transformedBody = body
|
||||
@@ -833,8 +832,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo
|
||||
fn.kind = oldKind
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
noDestructors: bool): PNode =
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
@@ -850,7 +848,6 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
tooEarly = true
|
||||
else:
|
||||
var d = initDetectionPass(g, fn)
|
||||
d.noDestructors = noDestructors
|
||||
detectCapturedVars(body, fn, d)
|
||||
if not d.somethingToDo and fn.isIterator:
|
||||
addClosureParam(d, fn, body.info)
|
||||
|
||||
@@ -671,6 +671,12 @@ proc cstringCheck(tracked: PEffects; n: PNode) =
|
||||
a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
|
||||
message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
|
||||
|
||||
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
|
||||
createTypeBoundOps(tracked.graph, tracked.c, typ, info)
|
||||
if (typ != nil and tfHasAsgn in typ.flags) or
|
||||
optSeqDestructors in tracked.config.globalOptions:
|
||||
tracked.owner.flags.incl sfInjectDestructors
|
||||
|
||||
proc track(tracked: PEffects, n: PNode) =
|
||||
template gcsafeAndSideeffectCheck() =
|
||||
if notGcSafe(op) and not importedFromC(a):
|
||||
@@ -693,7 +699,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
addEffect(tracked, n.sons[0], useLineInfo=false)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[0].typ, n.info)
|
||||
createTypeBoundOps(tracked, n[0].typ, n.info)
|
||||
else:
|
||||
# A `raise` with no arguments means we're going to re-raise the exception
|
||||
# being handled or, if outside of an `except` block, a `ReraiseError`.
|
||||
@@ -707,7 +713,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
return
|
||||
if n.typ != nil:
|
||||
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n.typ, n.info)
|
||||
createTypeBoundOps(tracked, n.typ, n.info)
|
||||
if a.kind == nkCast and a[1].typ.kind == tyProc:
|
||||
a = a[1]
|
||||
# XXX: in rare situations, templates and macros will reach here after
|
||||
@@ -750,7 +756,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
# check required for 'nim check':
|
||||
if n[1].typ.len > 0:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[1].typ.lastSon, n.info)
|
||||
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
@@ -771,18 +777,18 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
notNilCheck(tracked, n.sons[1], n.sons[0].typ)
|
||||
when false: cstringCheck(tracked, n)
|
||||
if tracked.owner.kind != skMacro:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, n[0].typ, n.info)
|
||||
createTypeBoundOps(tracked, n[0].typ, n.info)
|
||||
of nkVarSection, nkLetSection:
|
||||
for child in n:
|
||||
let last = lastSon(child)
|
||||
if last.kind != nkEmpty: track(tracked, last)
|
||||
if tracked.owner.kind != skMacro:
|
||||
if child.kind == nkVarTuple:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, child[^1].typ, child.info)
|
||||
createTypeBoundOps(tracked, child[^1].typ, child.info)
|
||||
for i in 0..child.len-3:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, child[i].typ, child.info)
|
||||
createTypeBoundOps(tracked, child[i].typ, child.info)
|
||||
else:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, child[0].typ, child.info)
|
||||
createTypeBoundOps(tracked, child[0].typ, child.info)
|
||||
if child.kind == nkIdentDefs and last.kind != nkEmpty:
|
||||
for i in 0 .. child.len-3:
|
||||
initVar(tracked, child.sons[i], volatileCheck=false)
|
||||
@@ -828,15 +834,15 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if tracked.owner.kind != skMacro:
|
||||
if it.kind == nkVarTuple:
|
||||
for x in it:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, x.typ, x.info)
|
||||
createTypeBoundOps(tracked, x.typ, x.info)
|
||||
else:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, it.typ, it.info)
|
||||
createTypeBoundOps(tracked, it.typ, it.info)
|
||||
let iterCall = n[n.len-2]
|
||||
let loopBody = n[n.len-1]
|
||||
if tracked.owner.kind != skMacro and iterCall.safeLen > 1:
|
||||
# XXX this is a bit hacky:
|
||||
if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
|
||||
createTypeBoundOps(tracked.graph, tracked.c, iterCall[1].typ, iterCall[1].info)
|
||||
createTypeBoundOps(tracked, iterCall[1].typ, iterCall[1].info)
|
||||
track(tracked, iterCall)
|
||||
track(tracked, loopBody)
|
||||
setLen(tracked.init, oldState)
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
import
|
||||
options, ast, astalgo, trees, msgs,
|
||||
idents, renderer, types, semfold, magicsys, cgmeth,
|
||||
lowerings, injectdestructors, liftlocals,
|
||||
lowerings, liftlocals,
|
||||
modulegraphs, lineinfos
|
||||
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
|
||||
noDestructors = false): PNode
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode
|
||||
|
||||
import closureiters, lambdalifting
|
||||
|
||||
@@ -49,7 +48,7 @@ type
|
||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||
nestedProcs: int # > 0 if we are in a nested proc
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
deferDetected, tooEarly, needsDestroyPass, noDestructors: bool
|
||||
deferDetected, tooEarly: bool
|
||||
graph: ModuleGraph
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
@@ -131,7 +130,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
if s.kind in routineKinds:
|
||||
discard transformBody(c.graph, s, true, c.noDestructors)
|
||||
discard transformBody(c.graph, s, true)
|
||||
if s.kind == skIterator:
|
||||
if c.tooEarly: return n
|
||||
else: return liftIterSym(c.graph, n, getCurrOwner(c))
|
||||
@@ -678,7 +677,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
|
||||
let body = transformBody(c.graph, iter, true, c.noDestructors)
|
||||
let body = transformBody(c.graph, iter, true)
|
||||
pushInfoContext(c.graph.config, n.info)
|
||||
inc(c.inlining)
|
||||
add(stmtList, transform(c, body))
|
||||
@@ -913,9 +912,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
nkBlockStmt, nkBlockExpr}:
|
||||
oldDeferAnchor = c.deferAnchor
|
||||
c.deferAnchor = n
|
||||
if (n.typ != nil and tfHasAsgn in n.typ.flags) or
|
||||
optSeqDestructors in c.graph.config.globalOptions:
|
||||
c.needsDestroyPass = true
|
||||
case n.kind
|
||||
of nkSym:
|
||||
result = transformSym(c, n)
|
||||
@@ -1113,8 +1109,7 @@ template liftDefer(c, root) =
|
||||
if c.deferDetected:
|
||||
liftDeferAux(root)
|
||||
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
|
||||
noDestructors = false): PNode =
|
||||
proc transformBody*(g: ModuleGraph, prc: PSym, cache: bool): PNode =
|
||||
assert prc.kind in routineKinds
|
||||
|
||||
if prc.transformedBody != nil:
|
||||
@@ -1124,13 +1119,10 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
|
||||
else:
|
||||
prc.transformedBody = newNode(nkEmpty) # protects from recursion
|
||||
var c = openTransf(g, prc.getModule, "")
|
||||
c.noDestructors = noDestructors
|
||||
result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly, noDestructors)
|
||||
result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
|
||||
result = processTransf(c, result, prc)
|
||||
liftDefer(c, result)
|
||||
result = liftLocalsIfRequested(prc, result, g.cache, g.config)
|
||||
if c.needsDestroyPass and not noDestructors:
|
||||
result = injectDestructorCalls(g, prc, result)
|
||||
|
||||
if prc.isIterator:
|
||||
result = g.transformClosureIterator(prc, result)
|
||||
@@ -1152,12 +1144,9 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdasForTopLevel(module, result)
|
||||
if c.needsDestroyPass:
|
||||
result = injectDestructorCalls(g, module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
|
||||
noDestructors = false): PNode =
|
||||
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
@@ -1166,6 +1155,4 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
|
||||
liftDefer(c, result)
|
||||
# expressions are not to be injected with destructor calls as that
|
||||
# the list of top level statements needs to be collected before.
|
||||
if c.needsDestroyPass and not noDestructors:
|
||||
result = injectDestructorCalls(g, module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -1005,13 +1005,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
if a.kind == nkSym:
|
||||
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
|
||||
else:
|
||||
let ast = a.sym.ast.shallowCopy
|
||||
for i in 0..<a.sym.ast.len:
|
||||
ast[i] = a.sym.ast[i]
|
||||
ast[bodyPos] = transformBody(c.graph, a.sym)
|
||||
ast.copyTree()
|
||||
regs[ra].node =
|
||||
if a.sym.ast.isNil:
|
||||
newNode(nkNilLit)
|
||||
else:
|
||||
let ast = a.sym.ast.shallowCopy
|
||||
for i in 0..<a.sym.ast.len:
|
||||
ast[i] = a.sym.ast[i]
|
||||
ast[bodyPos] = transformBody(c.graph, a.sym, cache=true)
|
||||
ast.copyTree()
|
||||
of opcSymOwner:
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
@@ -1983,7 +1985,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
"NimScript: attempt to call non-routine: " & sym.name.s)
|
||||
|
||||
proc evalStmt*(c: PCtx, n: PNode) =
|
||||
let n = transformExpr(c.graph, c.module, n, noDestructors = true)
|
||||
let n = transformExpr(c.graph, c.module, n)
|
||||
let start = genStmt(c, n)
|
||||
# execute new instructions; this redundant opcEof check saves us lots
|
||||
# of allocations in 'execute':
|
||||
@@ -1991,7 +1993,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
|
||||
discard execute(c, start)
|
||||
|
||||
proc evalExpr*(c: PCtx, n: PNode): PNode =
|
||||
let n = transformExpr(c.graph, c.module, n, noDestructors = true)
|
||||
let n = transformExpr(c.graph, c.module, n)
|
||||
let start = genExpr(c, n)
|
||||
assert c.code[start].opcode != opcEof
|
||||
result = execute(c, start)
|
||||
@@ -2037,7 +2039,7 @@ proc evalConstExprAux(module: PSym;
|
||||
g: ModuleGraph; prc: PSym, n: PNode,
|
||||
mode: TEvalMode): PNode =
|
||||
if g.config.errorCounter > 0: return n
|
||||
let n = transformExpr(g, module, n, noDestructors = true)
|
||||
let n = transformExpr(g, module, n)
|
||||
setupGlobalCtx(module, g)
|
||||
var c = PCtx g.vm
|
||||
let oldMode = c.mode
|
||||
|
||||
@@ -2243,8 +2243,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
s.ast.sons[miscPos] = x
|
||||
# thanks to the jmp we can add top level statements easily and also nest
|
||||
# procs easily:
|
||||
let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s),
|
||||
noDestructors = true)
|
||||
let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
|
||||
let procStart = c.xjmp(body, opcJmp, 0)
|
||||
var p = PProc(blocks: @[], sym: s)
|
||||
let oldPrc = c.prc
|
||||
|
||||
@@ -58,9 +58,9 @@ iterator items(p: Pony): int =
|
||||
|
||||
for x in getPony():
|
||||
echo x
|
||||
# XXX this needs to be enabled once top level statements
|
||||
# produce destructor calls again.
|
||||
#echo "Pony is dying!"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user