lambda lifting compiles again

This commit is contained in:
Andreas Rumpf 2018-05-12 08:30:55 +02:00
commit 1310279691
3 changed files with 154 additions and 149 deletions

View file

@ -102,14 +102,14 @@ proc genLabel(c: Con): TPosition =
proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) = proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
let dist = p.int - c.code.len let dist = p.int - c.code.len
internalAssert(-0x7fff < dist and dist < 0x7fff) doAssert(-0x7fff < dist and dist < 0x7fff)
c.code.add Instr(n: n, kind: goto, dest: dist) c.code.add Instr(n: n, kind: goto, dest: dist)
proc patch(c: var Con, p: TPosition) = proc patch(c: var Con, p: TPosition) =
# patch with current index # patch with current index
let p = p.int let p = p.int
let diff = c.code.len - p let diff = c.code.len - p
internalAssert(-0x7fff < diff and diff < 0x7fff) doAssert(-0x7fff < diff and diff < 0x7fff)
c.code[p].dest = diff c.code[p].dest = diff
proc popBlock(c: var Con; oldLen: int) = proc popBlock(c: var Con; oldLen: int) =

View file

@ -11,7 +11,8 @@
import import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, rodread, lowerings, tables idents, renderer, types, magicsys, rodread, lowerings, tables,
modulegraphs
discard """ discard """
The basic approach is that captured vars need to be put on the heap and The basic approach is that captured vars need to be put on the heap and
@ -125,25 +126,25 @@ proc newCall(a: PSym, b: PNode): PNode =
result.add newSymNode(a) result.add newSymNode(a)
result.add b result.add b
proc createStateType(iter: PSym): PType = proc createStateType(g: ModuleGraph; iter: PSym): PType =
var n = newNodeI(nkRange, iter.info) var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1)) addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0)) addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter) result = newType(tyRange, iter)
result.n = n result.n = n
var intType = nilOrSysInt() var intType = nilOrSysInt(g)
if intType.isNil: intType = newType(tyInt, iter) if intType.isNil: intType = newType(tyInt, iter)
rawAddSon(result, intType) rawAddSon(result, intType)
proc createStateField(iter: PSym): PSym = proc createStateField(g: ModuleGraph; iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info) result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = createStateType(iter) result.typ = createStateType(g, iter)
proc createEnvObj(owner: PSym; info: TLineInfo): PType = proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
# YYY meh, just add the state field for every closure for now, it's too # YYY meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator: # hard to figure out if it comes from a closure iterator:
result = createObj(owner, info, final=false) result = createObj(g, owner, info, final=false)
rawAddField(result, createStateField(owner)) rawAddField(result, createStateField(g, owner))
proc getIterResult(iter: PSym): PSym = proc getIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len: if resultPos < iter.ast.len:
@ -166,7 +167,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
assert sfFromGeneric in param.flags assert sfFromGeneric in param.flags
#echo "produced environment: ", param.id, " for ", routine.id #echo "produced environment: ", param.id, " for ", routine.id
proc getHiddenParam(routine: PSym): PSym = proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
let params = routine.ast.sons[paramsPos] let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params) let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName: if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
@ -174,7 +175,7 @@ proc getHiddenParam(routine: PSym): PSym =
assert sfFromGeneric in result.flags assert sfFromGeneric in result.flags
else: else:
# writeStackTrace() # writeStackTrace()
localError(routine.info, "internal error: could not find env param for " & routine.name.s) localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
result = routine result = routine
proc getEnvParam*(routine: PSym): PSym = proc getEnvParam*(routine: PSym): PSym =
@ -208,14 +209,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
result.sons[0] = le result.sons[0] = le
result.sons[1] = ri result.sons[1] = ri
proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode = proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
result = newNodeIT(nkClosure, info, prc.typ) result = newNodeIT(nkClosure, info, prc.typ)
result.add(newSymNode(prc)) result.add(newSymNode(prc))
if env == nil: if env == nil:
result.add(newNodeIT(nkNilLit, info, getSysType(tyNil))) result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil)))
else: else:
if env.skipConv.kind == nkClosure: if env.skipConv.kind == nkClosure:
localError(info, "internal error: taking closure of closure") localError(g.config, info, "internal error: taking closure of closure")
result.add(env) result.add(env)
proc interestingIterVar(s: PSym): bool {.inline.} = proc interestingIterVar(s: PSym): bool {.inline.} =
@ -232,7 +233,7 @@ proc liftingHarmful(owner: PSym): bool {.inline.} =
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
result = gCmd == cmdCompileToJS and not isCompileTime result = gCmd == cmdCompileToJS and not isCompileTime
proc liftIterSym*(n: PNode; owner: PSym): PNode = proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env)) # transforms (iter) to (let env = newClosure[iter](); (iter, env))
if liftingHarmful(owner): return n if liftingHarmful(owner): return n
let iter = n.sym let iter = n.sym
@ -240,10 +241,10 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ) result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let hp = getHiddenParam(iter) let hp = getHiddenParam(g, iter)
var env: PNode var env: PNode
if owner.isIterator: if owner.isIterator:
let it = getHiddenParam(owner) let it = getHiddenParam(g, owner)
addUniqueField(it.typ.sons[0], hp) addUniqueField(it.typ.sons[0], hp)
env = indirectAccess(newSymNode(it), hp, hp.info) env = indirectAccess(newSymNode(it), hp, hp.info)
else: else:
@ -255,11 +256,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
addVar(v, env) addVar(v, env)
result.add(v) result.add(v)
# add 'new' statement: # add 'new' statement:
result.add newCall(getSysSym"internalNew", env) result.add newCall(getSysSym(g, n.info, "internalNew"), env)
result.add makeClosure(iter, env, n.info) result.add makeClosure(g, iter, env, n.info)
proc freshVarForClosureIter*(s, owner: PSym): PNode = proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
let envParam = getHiddenParam(owner) let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.lastSon let obj = envParam.typ.lastSon
addField(obj, s) addField(obj, s)
@ -269,18 +270,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode =
if field != nil: if field != nil:
result = rawIndirectAccess(access, field, s.info) result = rawIndirectAccess(access, field, s.info)
else: else:
localError(s.info, "internal error: cannot generate fresh variable") localError(g.config, s.info, "internal error: cannot generate fresh variable")
result = access result = access
# ------------------ new stuff ------------------------------------------- # ------------------ new stuff -------------------------------------------
proc markAsClosure(owner: PSym; n: PNode) = proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym let s = n.sym
if illegalCapture(s): if illegalCapture(s):
localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" % localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
[s.name.s, typeToString(s.typ), $s.info]) [s.name.s, typeToString(s.typ), $s.info])
elif owner.typ.callConv notin {ccClosure, ccDefault}: elif owner.typ.callConv notin {ccClosure, ccDefault}:
localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]]) [s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
incl(owner.typ.flags, tfCapturesEnv) incl(owner.typ.flags, tfCapturesEnv)
owner.typ.callConv = ccClosure owner.typ.callConv = ccClosure
@ -290,12 +291,14 @@ type
processed, capturedVars: IntSet processed, capturedVars: IntSet
ownerToType: Table[int, PType] ownerToType: Table[int, PType]
somethingToDo: bool somethingToDo: bool
graph: ModuleGraph
proc initDetectionPass(fn: PSym): DetectionPass = proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
result.processed = initIntSet() result.processed = initIntSet()
result.capturedVars = initIntSet() result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]() result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id) result.processed.incl(fn.id)
result.graph = g
discard """ discard """
proc outer = proc outer =
@ -312,7 +315,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
result = c.ownerToType.getOrDefault(owner.id) result = c.ownerToType.getOrDefault(owner.id)
if result.isNil: if result.isNil:
result = newType(tyRef, owner) result = newType(tyRef, owner)
let obj = createEnvObj(owner, info) let obj = createEnvObj(c.graph, owner, info)
rawAddSon(result, obj) rawAddSon(result, obj)
c.ownerToType[owner.id] = result c.ownerToType[owner.id] = result
@ -321,13 +324,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
let obj = refObj.lastSon let obj = refObj.lastSon
let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
if refObj == fieldType: if refObj == fieldType:
localError(dep.info, "internal error: invalid up reference computed") localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
let upIdent = getIdent(upName) let upIdent = getIdent(upName)
let upField = lookupInRecord(obj.n, upIdent) let upField = lookupInRecord(obj.n, upIdent)
if upField != nil: if upField != nil:
if upField.typ != fieldType: if upField.typ != fieldType:
localError(dep.info, "internal error: up references do not agree") localError(c.graph.config, dep.info, "internal error: up references do not agree")
else: else:
let result = newSym(skField, upIdent, obj.owner, obj.owner.info) let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
result.typ = fieldType result.typ = fieldType
@ -369,7 +372,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
cp.typ = t cp.typ = t
addHiddenParam(fn, cp) addHiddenParam(fn, cp)
elif cp.typ != t and fn.kind != skIterator: elif cp.typ != t and fn.kind != skIterator:
localError(fn.info, "internal error: inconsistent environment type") localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
#echo "adding closure to ", fn.name.s #echo "adding closure to ", fn.name.s
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
@ -395,7 +398,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
addClosureParam(c, owner, n.info) addClosureParam(c, owner, n.info)
if interestingIterVar(s): if interestingIterVar(s):
if not c.capturedVars.containsOrIncl(s.id): if not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(owner).typ.lastSon let obj = getHiddenParam(c.graph, owner).typ.lastSon
#let obj = c.getEnvTypeForOwner(s.owner).lastSon #let obj = c.getEnvTypeForOwner(s.owner).lastSon
addField(obj, s) addField(obj, s)
# but always return because the rest of the proc is only relevant when # but always return because the rest of the proc is only relevant when
@ -415,7 +418,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
""" """
# mark 'owner' as taking a closure: # mark 'owner' as taking a closure:
c.somethingToDo = true c.somethingToDo = true
markAsClosure(owner, n) markAsClosure(c.graph, owner, n)
addClosureParam(c, owner, n.info) addClosureParam(c, owner, n.info)
#echo "capturing ", n.info #echo "capturing ", n.info
# variable 's' is actually captured: # variable 's' is actually captured:
@ -440,7 +443,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
""" """
let up = w.skipGenericOwner let up = w.skipGenericOwner
#echo "up for ", w.name.s, " up ", up.name.s #echo "up for ", w.name.s, " up ", up.name.s
markAsClosure(w, n) markAsClosure(c.graph, w, n)
addClosureParam(c, w, n.info) # , ow addClosureParam(c, w, n.info) # , ow
createUpField(c, w, up, n.info) createUpField(c, w, up, n.info)
w = up w = up
@ -467,10 +470,10 @@ proc initLiftingPass(fn: PSym): LiftingPass =
result.processed.incl(fn.id) result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]() result.envVars = initTable[int, PNode]()
proc accessViaEnvParam(n: PNode; owner: PSym): PNode = proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym let s = n.sym
# Type based expression construction for simplicity: # Type based expression construction for simplicity:
let envParam = getHiddenParam(owner) let envParam = getHiddenParam(g, owner)
if not envParam.isNil: if not envParam.isNil:
var access = newSymNode(envParam) var access = newSymNode(envParam)
while true: while true:
@ -482,7 +485,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
let upField = lookupInRecord(obj.n, getIdent(upName)) let upField = lookupInRecord(obj.n, getIdent(upName))
if upField == nil: break if upField == nil: break
access = rawIndirectAccess(access, upField, n.info) access = rawIndirectAccess(access, upField, n.info)
localError(n.info, "internal error: environment misses: " & s.name.s) localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
result = n result = n
proc newEnvVar(owner: PSym; typ: PType): PNode = proc newEnvVar(owner: PSym; typ: PType): PNode =
@ -501,22 +504,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
proc setupEnvVar(owner: PSym; d: DetectionPass; proc setupEnvVar(owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass): PNode =
if owner.isIterator: if owner.isIterator:
return getHiddenParam(owner).newSymNode return getHiddenParam(d.graph, owner).newSymNode
result = c.envvars.getOrDefault(owner.id) result = c.envvars.getOrDefault(owner.id)
if result.isNil: if result.isNil:
let envVarType = d.ownerToType.getOrDefault(owner.id) let envVarType = d.ownerToType.getOrDefault(owner.id)
if envVarType.isNil: if envVarType.isNil:
localError owner.info, "internal error: could not determine closure type" localError d.graph.config, owner.info, "internal error: could not determine closure type"
result = newEnvVar(owner, envVarType) result = newEnvVar(owner, envVarType)
c.envVars[owner.id] = result c.envVars[owner.id] = result
proc getUpViaParam(owner: PSym): PNode = proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
let p = getHiddenParam(owner) let p = getHiddenParam(g, owner)
result = p.newSymNode result = p.newSymNode
if owner.isIterator: if owner.isIterator:
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName))
if upField == nil: if upField == nil:
localError(owner.info, "could not find up reference for closure iter") localError(g.config, owner.info, "could not find up reference for closure iter")
else: else:
result = rawIndirectAccess(result, upField, p.info) result = rawIndirectAccess(result, upField, p.info)
@ -526,7 +529,7 @@ proc rawClosureCreation(owner: PSym;
var env: PNode var env: PNode
if owner.isIterator: if owner.isIterator:
env = getHiddenParam(owner).newSymNode env = getHiddenParam(d.graph, owner).newSymNode
else: else:
env = setupEnvVar(owner, d, c) env = setupEnvVar(owner, d, c)
if env.kind == nkSym: if env.kind == nkSym:
@ -534,7 +537,7 @@ proc rawClosureCreation(owner: PSym;
addVar(v, env) addVar(v, env)
result.add(v) result.add(v)
# add 'new' statement: # add 'new' statement:
result.add(newCall(getSysSym"internalNew", env)) result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
# add assignment statements for captured parameters: # add assignment statements for captured parameters:
for i in 1..<owner.typ.n.len: for i in 1..<owner.typ.n.len:
let local = owner.typ.n[i].sym let local = owner.typ.n[i].sym
@ -545,7 +548,7 @@ proc rawClosureCreation(owner: PSym;
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
if upField != nil: if upField != nil:
let up = getUpViaParam(owner) let up = getUpViaParam(d.graph, owner)
if up != nil and upField.typ == up.typ: if up != nil and upField.typ == up.typ:
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info), result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
up, env.info)) up, env.info))
@ -553,7 +556,7 @@ proc rawClosureCreation(owner: PSym;
# result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info), # result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
# oldenv, env.info)) # oldenv, env.info))
else: else:
localError(env.info, "internal error: cannot create up reference") localError(d.graph.config, env.info, "internal error: cannot create up reference")
proc closureCreationForIter(iter: PNode; proc closureCreationForIter(iter: PNode;
d: DetectionPass; c: var LiftingPass): PNode = d: DetectionPass; c: var LiftingPass): PNode =
@ -561,10 +564,10 @@ proc closureCreationForIter(iter: PNode;
let owner = iter.sym.skipGenericOwner let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(envName), owner, iter.info) var v = newSym(skVar, getIdent(envName), owner, iter.info)
incl(v.flags, sfShadowed) incl(v.flags, sfShadowed)
v.typ = getHiddenParam(iter.sym).typ v.typ = getHiddenParam(d.graph, iter.sym).typ
var vnode: PNode var vnode: PNode
if owner.isIterator: if owner.isIterator:
let it = getHiddenParam(owner) let it = getHiddenParam(d.graph, owner)
addUniqueField(it.typ.sons[0], v) addUniqueField(it.typ.sons[0], v)
vnode = indirectAccess(newSymNode(it), v, v.info) vnode = indirectAccess(newSymNode(it), v, v.info)
else: else:
@ -572,7 +575,7 @@ proc closureCreationForIter(iter: PNode;
var vs = newNodeI(nkVarSection, iter.info) var vs = newNodeI(nkVarSection, iter.info)
addVar(vs, vnode) addVar(vs, vnode)
result.add(vs) result.add(vs)
result.add(newCall(getSysSym"internalNew", vnode)) result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName)) let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName))
if upField != nil: if upField != nil:
@ -581,8 +584,8 @@ proc closureCreationForIter(iter: PNode;
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info), result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
u, iter.info)) u, iter.info))
else: else:
localError(iter.info, "internal error: cannot create up reference for iter") localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter")
result.add makeClosure(iter.sym, vnode, iter.info) result.add makeClosure(d.graph, iter.sym, vnode, iter.info)
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass; proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass): PNode =
@ -592,11 +595,11 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
if field != nil: if field != nil:
result = rawIndirectAccess(access, field, n.info) result = rawIndirectAccess(access, field, n.info)
else: else:
localError(n.info, "internal error: not part of closure object type") localError(d.graph.config, n.info, "internal error: not part of closure object type")
result = n result = n
proc getStateField(owner: PSym): PSym = proc getStateField(g: ModuleGraph; owner: PSym): PSym =
getHiddenParam(owner).typ.sons[0].n.sons[0].sym getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode c: var LiftingPass): PNode
@ -604,8 +607,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
proc transformYield(n: PNode; owner: PSym; d: DetectionPass; proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass): PNode =
if c.inContainer > 0: if c.inContainer > 0:
localError(n.info, "invalid control flow: 'yield' within a constructor") localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
let state = getStateField(owner) let state = getStateField(d.graph, owner)
assert state != nil assert state != nil
assert state.typ != nil assert state.typ != nil
assert state.typ.n != nil assert state.typ.n != nil
@ -615,7 +618,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
var stateAsgnStmt = newNodeI(nkAsgn, n.info) var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)), stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info)) state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info) var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
@ -628,7 +632,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
retStmt.add(emptyNode) retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info) var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt) result.add(stateAsgnStmt)
@ -637,16 +642,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
proc transformReturn(n: PNode; owner: PSym; d: DetectionPass; proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass): PNode =
let state = getStateField(owner) let state = getStateField(d.graph, owner)
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info) var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)), stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info)) state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt))) stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
result.add(stateAsgnStmt) result.add(stateAsgnStmt)
result.add(n) result.add(n)
proc wrapIterBody(n: PNode; owner: PSym): PNode = proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
if not owner.isIterator: return n if not owner.isIterator: return n
when false: when false:
# unfortunately control flow is still convoluted and we can end up # unfortunately control flow is still convoluted and we can end up
@ -660,7 +665,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
let info = n.info let info = n.info
result = newNodeI(nkStmtList, info) result = newNodeI(nkStmtList, info)
var gs = newNodeI(nkGotoState, info) var gs = newNodeI(nkGotoState, info)
gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info)) gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
result.add(gs) result.add(gs)
var state0 = newNodeI(nkState, info) var state0 = newNodeI(nkState, info)
state0.add(newIntNode(nkIntLit, 0)) state0.add(newIntNode(nkIntLit, 0))
@ -669,9 +674,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
result.add(n) result.add(n)
var stateAsgnStmt = newNodeI(nkAsgn, info) var stateAsgnStmt = newNodeI(nkAsgn, info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
getStateField(owner), info)) getStateField(g, owner), info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt))) stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
result.add(stateAsgnStmt) result.add(stateAsgnStmt)
proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
@ -679,25 +684,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
let s = n.sym let s = n.sym
if s == owner: if s == owner:
# recursive calls go through (lambda, hiddenParam): # recursive calls go through (lambda, hiddenParam):
let available = getHiddenParam(owner) let available = getHiddenParam(d.graph, owner)
result = makeClosure(s, available.newSymNode, n.info) result = makeClosure(d.graph, s, available.newSymNode, n.info)
elif s.isIterator: elif s.isIterator:
result = closureCreationForIter(n, d, c) result = closureCreationForIter(n, d, c)
elif s.skipGenericOwner == owner: elif s.skipGenericOwner == owner:
# direct dependency, so use the outer's env variable: # direct dependency, so use the outer's env variable:
result = makeClosure(s, setupEnvVar(owner, d, c), n.info) result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
else: else:
let available = getHiddenParam(owner) let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(s).typ let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc; # ugh: call through some other inner proc;
var access = newSymNode(available) var access = newSymNode(available)
while true: while true:
if access.typ == wanted: if access.typ == wanted:
return makeClosure(s, access, n.info) return makeClosure(d.graph, s, access, n.info)
let obj = access.typ.sons[0] let obj = access.typ.sons[0]
let upField = lookupInRecord(obj.n, getIdent(upName)) let upField = lookupInRecord(obj.n, getIdent(upName))
if upField == nil: if upField == nil:
localError(n.info, "internal error: no environment found") localError(d.graph.config, n.info, "internal error: no environment found")
return n return n
access = rawIndirectAccess(access, upField, n.info) access = rawIndirectAccess(access, upField, n.info)
@ -713,7 +718,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# echo renderTree(s.getBody, {renderIds}) # echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer let oldInContainer = c.inContainer
c.inContainer = 0 c.inContainer = 0
let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s) let body = wrapIterBody(d.graph, liftCapturedVars(s.getBody, s, d, c), s)
if c.envvars.getOrDefault(s.id).isNil: if c.envvars.getOrDefault(s.id).isNil:
s.ast.sons[bodyPos] = body s.ast.sons[bodyPos] = body
else: else:
@ -723,9 +728,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
result = symToClosure(n, owner, d, c) result = symToClosure(n, owner, d, c)
elif s.id in d.capturedVars: elif s.id in d.capturedVars:
if s.owner != owner: if s.owner != owner:
result = accessViaEnvParam(n, owner) result = accessViaEnvParam(d.graph, n, owner)
elif owner.isIterator and interestingIterVar(s): elif owner.isIterator and interestingIterVar(s):
result = accessViaEnvParam(n, owner) result = accessViaEnvParam(d.graph, n, owner)
else: else:
result = accessViaEnvVar(n, owner, d, c) result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom, of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
@ -791,8 +796,8 @@ proc semCaptureSym*(s, owner: PSym) =
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv' # since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
# here # here
proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode = proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode =
var d = initDetectionPass(fn) var d = initDetectionPass(g, fn)
var c = initLiftingPass(fn) var c = initLiftingPass(fn)
# pretend 'fn' is a closure iterator for the analysis: # pretend 'fn' is a closure iterator for the analysis:
let oldKind = fn.kind let oldKind = fn.kind
@ -801,11 +806,11 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
fn.typ.callConv = ccClosure fn.typ.callConv = ccClosure
d.ownerToType[fn.id] = ptrType d.ownerToType[fn.id] = ptrType
detectCapturedVars(body, fn, d) detectCapturedVars(body, fn, d)
result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn) result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
fn.kind = oldKind fn.kind = oldKind
fn.typ.callConv = oldCC fn.typ.callConv = oldCC
proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode = proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ... # the transformation even when compiling to JS ...
@ -819,7 +824,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
result = body result = body
tooEarly = true tooEarly = true
else: else:
var d = initDetectionPass(fn) var d = initDetectionPass(g, fn)
detectCapturedVars(body, fn, d) detectCapturedVars(body, fn, d)
if not d.somethingToDo and fn.isIterator: if not d.somethingToDo and fn.isIterator:
addClosureParam(d, fn, body.info) addClosureParam(d, fn, body.info)
@ -829,7 +834,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
var newBody = liftCapturedVars(body, fn, d, c) var newBody = liftCapturedVars(body, fn, d, c)
if c.envvars.getOrDefault(fn.id) != nil: if c.envvars.getOrDefault(fn.id) != nil:
newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody) newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody)
result = wrapIterBody(newBody, fn) result = wrapIterBody(g, newBody, fn)
else: else:
result = body result = body
#if fn.name.s == "get2": #if fn.name.s == "get2":
@ -845,7 +850,7 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
# ------------------- iterator transformation -------------------------------- # ------------------- iterator transformation --------------------------------
proc liftForLoop*(body: PNode; owner: PSym): PNode = proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
# problem ahead: the iterator could be invoked indirectly, but then # problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here: # we don't know what environment to create here:
# #
@ -876,7 +881,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
if liftingHarmful(owner): return body if liftingHarmful(owner): return body
var L = body.len var L = body.len
if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds): if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
localError(body.info, "ignored invalid for loop") localError(g.config, body.info, "ignored invalid for loop")
return body return body
var call = body[L-2] var call = body[L-2]
@ -889,7 +894,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
# createClosure() # createClosure()
let iter = op.sym let iter = op.sym
let hp = getHiddenParam(iter) let hp = getHiddenParam(g, iter)
env = newSym(skLet, iter.name, owner, body.info) env = newSym(skLet, iter.name, owner, body.info)
env.typ = hp.typ env.typ = hp.typ
env.flags = hp.flags env.flags = hp.flags
@ -898,7 +903,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
addVar(v, newSymNode(env)) addVar(v, newSymNode(env))
result.add(v) result.add(v)
# add 'new' statement: # add 'new' statement:
result.add(newCall(getSysSym"internalNew", env.newSymNode)) result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
elif op.kind == nkStmtListExpr: elif op.kind == nkStmtListExpr:
let closure = op.lastSon let closure = op.lastSon
if closure.kind == nkClosure: if closure.kind == nkClosure:
@ -908,7 +913,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
var loopBody = newNodeI(nkStmtList, body.info, 3) var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2) var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool)) whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
whileLoop.sons[1] = loopBody whileLoop.sons[1] = loopBody
result.add whileLoop result.add whileLoop
@ -923,7 +928,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
addSon(vpart, ast.emptyNode) # no explicit type addSon(vpart, ast.emptyNode) # no explicit type
if not env.isNil: if not env.isNil:
call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info) call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
addSon(vpart, call) addSon(vpart, call)
addSon(v2, vpart) addSon(v2, vpart)

View file

@ -12,18 +12,18 @@
const const
genPrefix* = ":tmp" # prefix for generated names genPrefix* = ":tmp" # prefix for generated names
import ast, astalgo, types, idents, magicsys, msgs, options import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs
from trees import getMagic from trees import getMagic
proc newDeref*(n: PNode): PNode {.inline.} = proc newDeref*(n: PNode): PNode {.inline.} =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0]) result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
addSon(result, n) addSon(result, n)
proc newTupleAccess*(tup: PNode, i: int): PNode = proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes( result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i]) abstractInst).sons[i])
addSon(result, copyTree(tup)) addSon(result, copyTree(tup))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt)) var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
lit.intVal = i lit.intVal = i
addSon(result, lit) addSon(result, lit)
@ -44,7 +44,7 @@ proc newFastAsgnStmt(le, ri: PNode): PNode =
result.sons[0] = le result.sons[0] = le
result.sons[1] = ri result.sons[1] = ri
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode = proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple assert n.kind == nkVarTuple
let value = n.lastSon let value = n.lastSon
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
@ -61,7 +61,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
result.add newAsgnStmt(tempAsNode, value) result.add newAsgnStmt(tempAsNode, value)
for i in 0 .. n.len-3: for i in 0 .. n.len-3:
if n.sons[i].kind == nkSym: v.addVar(n.sons[i]) if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i)) result.add newAsgnStmt(n.sons[i], newTupleAccess(g, tempAsNode, i))
proc newTupleAccessRaw*(tup: PNode, i: int): PNode = proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
result = newNodeI(nkBracketExpr, tup.info) result = newNodeI(nkBracketExpr, tup.info)
@ -112,13 +112,13 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
result.add newFastAsgnStmt(n[1], n[2]) result.add newFastAsgnStmt(n[1], n[2])
result.add newFastAsgnStmt(n[2], tempAsNode) result.add newFastAsgnStmt(n[2], tempAsNode)
proc createObj*(owner: PSym, info: TLineInfo; final=true): PType = proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType =
result = newType(tyObject, owner) result = newType(tyObject, owner)
if final: if final:
rawAddSon(result, nil) rawAddSon(result, nil)
incl result.flags, tfFinal incl result.flags, tfFinal
else: else:
rawAddSon(result, getCompilerProc("RootObj").typ) rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info) result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent("Env_" & info.toFilename), let s = newSym(skType, getIdent("Env_" & info.toFilename),
owner, info) owner, info)
@ -218,7 +218,7 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
#if field == nil: #if field == nil:
# echo "FIELD ", b # echo "FIELD ", b
# debug deref.typ # debug deref.typ
internalAssert field != nil assert field != nil
addSon(deref, a) addSon(deref, a)
result = newNodeI(nkDotExpr, info) result = newNodeI(nkDotExpr, info)
addSon(result, deref) addSon(result, deref)
@ -242,7 +242,7 @@ proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode =
#if field == nil: #if field == nil:
# echo "FIELD ", b # echo "FIELD ", b
# debug deref.typ # debug deref.typ
internalAssert field != nil assert field != nil
addSon(deref, a) addSon(deref, a)
result = newNodeI(nkDotExpr, info) result = newNodeI(nkDotExpr, info)
addSon(result, deref) addSon(result, deref)
@ -278,12 +278,12 @@ proc genDeref*(n: PNode): PNode =
n.typ.skipTypes(abstractInst).sons[0]) n.typ.skipTypes(abstractInst).sons[0])
result.add n result.add n
proc callCodegenProc*(name: string, arg1: PNode; proc callCodegenProc*(g: ModuleGraph; name: string, arg1: PNode;
arg2, arg3, optionalArgs: PNode = nil): PNode = arg2, arg3, optionalArgs: PNode = nil): PNode =
result = newNodeI(nkCall, arg1.info) result = newNodeI(nkCall, arg1.info)
let sym = magicsys.getCompilerProc(name) let sym = magicsys.getCompilerProc(g, name)
if sym == nil: if sym == nil:
localError(arg1.info, errSystemNeeds, name) localError(g.config, arg1.info, "system module needs: " & name)
else: else:
result.add newSymNode(sym) result.add newSymNode(sym)
result.add arg1 result.add arg1
@ -333,7 +333,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon
result = not containsGarbageCollectedRef(t) result = not containsGarbageCollectedRef(t)
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType; proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
v: PNode; useShallowCopy=false): PSym = v: PNode; useShallowCopy=false): PSym =
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info) result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
result.typ = typ result.typ = typ
@ -349,7 +349,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
varInit.add newFastAsgnStmt(newSymNode(result), v) varInit.add newFastAsgnStmt(newSymNode(result), v)
else: else:
let deepCopyCall = newNodeI(nkCall, varInit.info, 3) let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
deepCopyCall.sons[0] = newSymNode(getSysMagic("deepCopy", mDeepCopy)) deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
deepCopyCall.sons[1] = newSymNode(result) deepCopyCall.sons[1] = newSymNode(result)
deepCopyCall.sons[2] = v deepCopyCall.sons[2] = v
varInit.add deepCopyCall varInit.add deepCopyCall
@ -384,23 +384,23 @@ stmtList:
""" """
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
varSection, varInit, call, barrier, fv: PNode; varSection, varInit, call, barrier, fv: PNode;
spawnKind: TSpawnResult): PSym = spawnKind: TSpawnResult): PSym =
var body = newNodeI(nkStmtList, f.info) var body = newNodeI(nkStmtList, f.info)
var threadLocalBarrier: PSym var threadLocalBarrier: PSym
if barrier != nil: if barrier != nil:
var varSection2 = newNodeI(nkVarSection, barrier.info) var varSection2 = newNodeI(nkVarSection, barrier.info)
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner,
barrier.typ, barrier) barrier.typ, barrier)
body.add varSection2 body.add varSection2
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.newSymNode)
var threadLocalProm: PSym var threadLocalProm: PSym
if spawnKind == srByVar: if spawnKind == srByVar:
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
elif fv != nil: elif fv != nil:
internalAssert fv.typ.kind == tyGenericInst internalAssert g.config, fv.typ.kind == tyGenericInst
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
body.add varSection body.add varSection
body.add varInit body.add varInit
if fv != nil and spawnKind != srByVar: if fv != nil and spawnKind != srByVar:
@ -409,30 +409,30 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
"owner", fv.info), threadParam.newSymNode) "owner", fv.info), threadParam.newSymNode)
body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode) body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.newSymNode)
if spawnKind == srByVar: if spawnKind == srByVar:
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
elif fv != nil: elif fv != nil:
let fk = fv.typ.sons[1].flowVarKind let fk = fv.typ.sons[1].flowVarKind
if fk == fvInvalid: if fk == fvInvalid:
localError(f.info, "cannot create a flowVar of type: " & localError(g.config, f.info, "cannot create a flowVar of type: " &
typeToString(fv.typ.sons[1])) typeToString(fv.typ.sons[1]))
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
if fk == fvGC: "data" else: "blob", fv.info), call) if fk == fvGC: "data" else: "blob", fv.info), call)
if fk == fvGC: if fk == fvGC:
let incRefCall = newNodeI(nkCall, fv.info, 2) let incRefCall = newNodeI(nkCall, fv.info, 2)
incRefCall.sons[0] = newSymNode(getSysMagic("GCref", mGCref)) incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode, incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
"data", fv.info) "data", fv.info)
body.add incRefCall body.add incRefCall
if barrier == nil: if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need # by now 'fv' is shared and thus might have beeen overwritten! we need
# to use the thread-local view instead: # to use the thread-local view instead:
body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode) body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.newSymNode)
else: else:
body.add call body.add call
if barrier != nil: if barrier != nil:
body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode) body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode)
var params = newNodeI(nkFormalParams, f.info) var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode params.add emptyNode
@ -460,7 +460,7 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result.typ = newType(tyPtr, objType.owner) result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType) result.typ.rawAddSon(objType)
proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym,
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
@ -470,7 +470,7 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
# 'tyOpenArray': # 'tyOpenArray':
var argType = n[i].typ.skipTypes(abstractInst) var argType = n[i].typ.skipTypes(abstractInst)
if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}: if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}:
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter") localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter")
#elif containsTyRef(argType): #elif containsTyRef(argType):
# localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
@ -480,7 +480,7 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
objType.addField(field) objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
let temp = addLocalVar(varSection, varInit, objType.owner, argType, let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
indirectAccess(castExpr, field, n.info)) indirectAccess(castExpr, field, n.info))
call.add(newSymNode(temp)) call.add(newSymNode(temp))
@ -501,20 +501,20 @@ proc getRoot*(n: PNode): PSym =
if getMagic(n) == mSlice: result = getRoot(n.sons[1]) if getMagic(n) == mSlice: result = getRoot(n.sons[1])
else: discard else: discard
proc newIntLit*(value: BiggestInt): PNode = proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value) result = nkIntLit.newIntNode(value)
result.typ = getSysType(tyInt) result.typ = getSysType(g, info, tyInt)
proc genHigh*(n: PNode): PNode = proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray: if skipTypes(n.typ, abstractVar).kind == tyArray:
result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar))) result = newIntLit(g, n.info, lastOrd(skipTypes(n.typ, abstractVar)))
else: else:
result = newNodeI(nkCall, n.info, 2) result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(tyInt) result.typ = getSysType(g, n.info, tyInt)
result.sons[0] = newSymNode(getSysMagic("high", mHigh)) result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
result.sons[1] = n result.sons[1] = n
proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym; proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym;
castExpr, call, castExpr, call,
varSection, varInit, result: PNode) = varSection, varInit, result: PNode) =
let formals = n[0].typ.n let formals = n[0].typ.n
@ -535,10 +535,10 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
# important special case: we always create a zero-copy slice: # important special case: we always create a zero-copy slice:
let slice = newNodeI(nkCall, n.info, 4) let slice = newNodeI(nkCall, n.info, 4)
slice.typ = n.typ slice.typ = n.typ
slice.sons[0] = newSymNode(createMagic("slice", mSlice)) slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice))
slice.sons[0].typ = getSysType(tyInt) # fake type slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info) var fieldB = newSym(skField, tmpName, objType.owner, n.info)
fieldB.typ = getSysType(tyInt) fieldB.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldB) objType.addField(fieldB)
if getMagic(n) == mSlice: if getMagic(n) == mSlice:
@ -548,12 +548,12 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
var fieldA = newSym(skField, tmpName, objType.owner, n.info) var fieldA = newSym(skField, tmpName, objType.owner, n.info)
fieldA.typ = getSysType(tyInt) fieldA.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldA) objType.addField(fieldA)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ, let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ,
indirectAccess(castExpr, fieldA, n.info), indirectAccess(castExpr, fieldA, n.info),
useShallowCopy=true) useShallowCopy=true)
slice.sons[2] = threadLocal.newSymNode slice.sons[2] = threadLocal.newSymNode
@ -562,13 +562,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = a.typ field.typ = a.typ
objType.addField(field) objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(n)) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
slice.sons[2] = newIntLit(0) slice.sons[2] = newIntLit(g, n.info, 0)
# the array itself does not need to go through a thread local variable: # the array itself does not need to go through a thread local variable:
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info)) slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ, let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ,
indirectAccess(castExpr, fieldB, n.info), indirectAccess(castExpr, fieldB, n.info),
useShallowCopy=true) useShallowCopy=true)
slice.sons[3] = threadLocal.newSymNode slice.sons[3] = threadLocal.newSymNode
@ -580,7 +580,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = a.typ field.typ = a.typ
objType.addField(field) objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ, let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info), indirectAccess(castExpr, field, n.info),
useShallowCopy=true) useShallowCopy=true)
call.add(genDeref(threadLocal.newSymNode)) call.add(genDeref(threadLocal.newSymNode))
@ -589,13 +589,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = argType field.typ = argType
objType.addField(field) objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
let threadLocal = addLocalVar(varSection, varInit, let threadLocal = addLocalVar(g, varSection, varInit,
objType.owner, field.typ, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info), indirectAccess(castExpr, field, n.info),
useShallowCopy=true) useShallowCopy=true)
call.add(threadLocal.newSymNode) call.add(threadLocal.newSymNode)
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType;
barrier, dest: PNode = nil): PNode = barrier, dest: PNode = nil): PNode =
# if 'barrier' != nil, then it is in a 'parallel' section and we # if 'barrier' != nil, then it is in a 'parallel' section and we
# generate quite different code # generate quite different code
@ -603,31 +603,31 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
let spawnKind = spawnResult(retType, barrier!=nil) let spawnKind = spawnResult(retType, barrier!=nil)
case spawnKind case spawnKind
of srVoid: of srVoid:
internalAssert dest == nil internalAssert g.config, dest == nil
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
of srFlowVar: of srFlowVar:
internalAssert dest == nil internalAssert g.config, dest == nil
result = newNodeIT(nkStmtListExpr, n.info, retType) result = newNodeIT(nkStmtListExpr, n.info, retType)
of srByVar: of srByVar:
if dest == nil: localError(n.info, "'spawn' must not be discarded") if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded")
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
if n.kind notin nkCallKinds: if n.kind notin nkCallKinds:
localError(n.info, "'spawn' takes a call expression") localError(g.config, n.info, "'spawn' takes a call expression")
return return
if optThreadAnalysis in gGlobalOptions: if optThreadAnalysis in gGlobalOptions:
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}: if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(n.info, "'spawn' takes a GC safe call expression") localError(g.config, n.info, "'spawn' takes a GC safe call expression")
var var
threadParam = newSym(skParam, getIdent"thread", owner, n.info) threadParam = newSym(skParam, getIdent"thread", owner, n.info)
argsParam = newSym(skParam, getIdent"args", owner, n.info) argsParam = newSym(skParam, getIdent"args", owner, n.info)
block: block:
let ptrType = getSysType(tyPointer) let ptrType = getSysType(g, n.info, tyPointer)
threadParam.typ = ptrType threadParam.typ = ptrType
argsParam.typ = ptrType argsParam.typ = ptrType
argsParam.position = 1 argsParam.position = 1
var objType = createObj(owner, n.info) var objType = createObj(g, owner, n.info)
incl(objType.flags, tfFinal) incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType) let castExpr = createCastExpr(argsParam, objType)
@ -644,7 +644,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
# templates and macros are in fact valid here due to the nature of # templates and macros are in fact valid here due to the nature of
# the transformation: # the transformation:
if fn.kind == nkClosure: if fn.kind == nkClosure:
localError(n.info, "closure in spawn environment is not allowed") localError(g.config, n.info, "closure in spawn environment is not allowed")
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro, if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skFunc, skMethod, skConverter}): skFunc, skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj # for indirect calls we pass the function pointer in the scratchObj
@ -655,24 +655,24 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info) fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind == skIterator: elif fn.kind == nkSym and fn.sym.kind == skIterator:
localError(n.info, "iterator in spawn environment is not allowed") localError(g.config, n.info, "iterator in spawn environment is not allowed")
elif fn.typ.callConv == ccClosure: elif fn.typ.callConv == ccClosure:
localError(n.info, "closure in spawn environment is not allowed") localError(g.config, n.info, "closure in spawn environment is not allowed")
call.add(fn) call.add(fn)
var varSection = newNodeI(nkVarSection, n.info) var varSection = newNodeI(nkVarSection, n.info)
var varInit = newNodeI(nkStmtList, n.info) var varInit = newNodeI(nkStmtList, n.info)
if barrier.isNil: if barrier.isNil:
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call,
varSection, varInit, result) varSection, varInit, result)
else: else:
setupArgsForParallelism(n, objType, scratchObj, castExpr, call, setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call,
varSection, varInit, result) varSection, varInit, result)
var barrierAsExpr: PNode = nil var barrierAsExpr: PNode = nil
if barrier != nil: if barrier != nil:
let typ = newType(tyPtr, owner) let typ = newType(tyPtr, owner)
typ.rawAddSon(magicsys.getCompilerProc("Barrier").typ) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
var field = newSym(skField, getIdent"barrier", owner, n.info) var field = newSym(skField, getIdent"barrier", owner, n.info)
field.typ = typ field.typ = typ
objType.addField(field) objType.addField(field)
@ -689,7 +689,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
# create flowVar: # create flowVar:
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1])) result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
if barrier == nil: if barrier == nil:
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField) result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField)
elif spawnKind == srByVar: elif spawnKind == srByVar:
var field = newSym(skField, getIdent"fv", owner, n.info) var field = newSym(skField, getIdent"fv", owner, n.info)
@ -699,10 +699,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
fvAsExpr = indirectAccess(castExpr, field, n.info) fvAsExpr = indirectAccess(castExpr, field, n.info)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest)) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
let wrapper = createWrapperProc(fn, threadParam, argsParam, let wrapper = createWrapperProc(g, fn, threadParam, argsParam,
varSection, varInit, call, varSection, varInit, call,
barrierAsExpr, fvAsExpr, spawnKind) barrierAsExpr, fvAsExpr, spawnKind)
result.add callCodegenProc("nimSpawn" & $spawnExpr.len, wrapper.newSymNode, result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
genAddrOf(scratchObj.newSymNode), nil, spawnExpr) genAddrOf(scratchObj.newSymNode), nil, spawnExpr)
if spawnKind == srFlowVar: result.add fvField if spawnKind == srFlowVar: result.add fvField