ARC: solves phase ordering problems (#12654)

This commit is contained in:
Andreas Rumpf
2019-11-14 23:19:18 +01:00
committed by GitHub
parent f22d3c75aa
commit a14abc5708
9 changed files with 65 additions and 62 deletions

View File

@@ -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]

View File

@@ -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:

View File

@@ -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" &

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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!"
#------------------------------------------------------------