transf and vmgen compile again

This commit is contained in:
Andreas Rumpf
2018-05-12 09:38:41 +02:00
parent 1310279691
commit fedc136985
9 changed files with 234 additions and 223 deletions

View File

@@ -116,7 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
strutils, options, dfa, lowerings, rodread, tables
strutils, options, dfa, lowerings, rodread, tables, modulegraphs,
configuration
const
InterestingSyms = {skVar, skResult, skLet}
@@ -130,6 +131,7 @@ type
tmp: PSym
destroys, topLevelVars: PNode
toDropBit: Table[int, PSym]
graph: ModuleGraph
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
# XXX why are temps fields in an object here?
@@ -222,21 +224,21 @@ proc patchHead(s: PSym) =
template genOp(opr, opname) =
let op = opr
if op == nil:
globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
elif op.ast[genericParamsPos].kind != nkEmpty:
globalError(dest.info, "internal error: '" & opname & "' operator is generic")
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
patchHead op
result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
proc genSink(t: PType; dest: PNode): PNode =
proc genSink(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(if t.sink != nil: t.sink else: t.assignment, "=sink")
proc genCopy(t: PType; dest: PNode): PNode =
proc genCopy(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(t.assignment, "=")
proc genDestroy(t: PType; dest: PNode): PNode =
proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(t.destructor, "=destroy")
@@ -249,14 +251,14 @@ proc dropBit(c: var Con; s: PSym): PSym =
proc registerDropBit(c: var Con; s: PSym) =
let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info)
result.typ = getSysType(tyBool)
result.typ = getSysType(c.graph, s.info, tyBool)
let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal)
c.toDropBit[s.id] = result
# generate:
# if not sinkParam_AliveBit: `=destroy`(sinkParam)
c.destroys.add newTree(nkIfStmt,
newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s)))
newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s)))
proc p(n: PNode; c: var Con): PNode
@@ -274,36 +276,36 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let bit = newSymNode dropBit(c, n.sym)
if optMoveCheck in c.owner.options:
result.add callCodegenProc("chckMove", bit)
result.add callCodegenProc(c.graph, "chckMove", bit)
result.add newTree(nkAsgn, bit,
newIntTypeNode(nkIntLit, 0, getSysType(tyBool)))
newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
result.add n
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
if ri.kind in constrExprs:
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
# watch out and no not transform 'ri' twice if it's a call:
let ri2 = copyNode(ri)
recurse(ri, ri2)
result.add ri2
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
result.add p(ri, c)
elif ri.kind == nkSym and isSinkParam(ri.sym):
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
result.add destructiveMoveSink(ri, c)
else:
result = genCopy(ri.typ, dest)
result = genCopy(c, ri.typ, dest)
result.add p(ri, c)
proc passCopyToSink(n: PNode; c: var Con): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = getTemp(c, n.typ, n.info)
if hasDestructor(n.typ):
var m = genCopy(n.typ, tmp)
var m = genCopy(c, n.typ, tmp)
m.add p(n, c)
result.add m
message(n.info, hintPerformance,
message(c.graph.config, n.info, hintPerformance,
"passing '$1' to a sink parameter introduces an implicit copy; " &
"use 'move($1)' to prevent it" % $n)
else:
@@ -312,7 +314,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
proc genReset(n: PNode; c: var Con): PNode =
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic("reset", mReset)))
result.add(newSymNode(createMagic(c.graph, "reset", mReset)))
# The mReset builtin does not take the address:
result.add n
@@ -345,7 +347,7 @@ proc p(n: PNode; c: var Con): PNode =
let L = it.len-1
let ri = it[L]
if it.kind == nkVarTuple and hasDestructor(ri.typ):
let x = lowerTupleUnpacking(it, c.owner)
let x = lowerTupleUnpacking(c.graph, it, c.owner)
result.add p(x, c)
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
for j in 0..L-2:
@@ -354,7 +356,7 @@ proc p(n: PNode; c: var Con): PNode =
# move the variable declaration to the top of the frame:
c.addTopVar v
# make sure it's destroyed at the end of the proc:
c.destroys.add genDestroy(v.typ, v)
c.destroys.add genDestroy(c, v.typ, v)
if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c)
result.add r
@@ -400,11 +402,11 @@ proc p(n: PNode; c: var Con): PNode =
discard "produce temp creation"
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = getTemp(c, n.typ, n.info)
var sinkExpr = genSink(n.typ, tmp)
var sinkExpr = genSink(c, n.typ, tmp)
sinkExpr.add n
result.add sinkExpr
result.add tmp
c.destroys.add genDestroy(n.typ, tmp)
c.destroys.add genDestroy(c, n.typ, tmp)
else:
result = n
of nkAsgn, nkFastAsgn:
@@ -420,17 +422,18 @@ proc p(n: PNode; c: var Con): PNode =
result = copyNode(n)
recurse(n, result)
proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
when defined(nimDebugDestroys):
echo "injecting into ", n
var c: Con
c.owner = owner
c.tmp = newSym(skTemp, getIdent":d", owner, n.info)
c.tmpObj = createObj(owner, n.info)
c.tmpObj = createObj(g, owner, n.info)
c.tmp.typ = c.tmpObj
c.destroys = newNodeI(nkStmtList, n.info)
c.topLevelVars = newNodeI(nkVarSection, n.info)
c.toDropBit = initTable[int, PSym]()
c.graph = g
let cfg = constructCfg(owner, n)
shallowCopy(c.g, cfg)
c.jumpTargets = initIntSet()

View File

@@ -23,7 +23,7 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, astalgo, types, intsets, tables, msgs
import ast, astalgo, types, intsets, tables, msgs, options
type
InstrKind* = enum
@@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) =
if c.blocks[i].label == n.sons[0].sym:
c.blocks[i].fixups.add L1
return
globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
#globalError(n.info, "VM problem: cannot find 'break' target")
else:
c.blocks[c.blocks.high].fixups.add L1
@@ -334,7 +334,7 @@ proc gen(c: var Con; n: PNode) =
of nkVarSection, nkLetSection: genVarSection(c, n)
else: discard
proc dfa(code: seq[Instr]) =
proc dfa(code: seq[Instr]; conf: ConfigRef) =
var u = newSeq[IntSet](code.len) # usages
var d = newSeq[IntSet](code.len) # defs
var c = newSeq[IntSet](code.len) # consumed
@@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) =
of use, useWithinCall:
let s = code[i].sym
if s.id notin d[i]:
localError(code[i].n.info, "usage of uninitialized variable: " & s.name.s)
localError(conf, code[i].n.info, "usage of uninitialized variable: " & s.name.s)
if s.id in c[i]:
localError(code[i].n.info, "usage of an already consumed variable: " & s.name.s)
localError(conf, code[i].n.info, "usage of an already consumed variable: " & s.name.s)
else: discard
proc dataflowAnalysis*(s: PSym; body: PNode) =
proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
var c = Con(code: @[], blocks: @[])
gen(c, body)
when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
dfa(c.code)
dfa(c.code, conf)
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
## constructs a control flow graph for ``body``.

View File

@@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) =
result[0].setLen(result[0].len - "\n".len)
result[1] = p.waitForExit
proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) =
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) =
let workingDir = parentDir(info.toFullPath)
if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile("gorge_" & $h, "txt")
let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")
var f: File
if open(f, filename):
result = (f.readAll, 0)

View File

@@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym =
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
return params[i].sym
proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode =
proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode =
let liftDest = getPragmaVal(prc.ast, wLiftLocals)
if liftDest == nil: return n
let partialParam = lookupParam(prc.typ.n, liftDest)
if partialParam.isNil:
localError(liftDest.info, "'$1' is not a parameter of '$2'" %
localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" %
[$liftDest, prc.name.s])
return n
let objType = partialParam.typ.skipTypes(abstractPtrs)
if objType.kind != tyObject or tfPartial notin objType.flags:
localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
return n
var c = Ctx(partialParam: partialParam, objType: objType)
let w = newTree(nkStmtList, n)

View File

@@ -21,7 +21,8 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals,
modulegraphs
type
PTransNode* = distinct PNode
@@ -44,6 +45,7 @@ type
nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly, needsDestroyPass: bool
graph: ModuleGraph
PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
@@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) =
c.transCon = t
proc popTransCon(c: PTransf) =
if (c.transCon == nil): internalError("popTransCon")
if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
c.transCon = c.transCon.next
proc getCurrOwner(c: PTransf): PSym =
@@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
incl(r.flags, sfFromGeneric)
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly:
result = freshVarForClosureIter(r, owner)
result = freshVarForClosureIter(c.graph, r, owner)
else:
result = newSymNode(r)
@@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
if s.typ != nil and s.typ.callConv == ccClosure:
if s.kind == skIterator:
if c.tooEarly: return n
else: return liftIterSym(n, getCurrOwner(c))
else: return liftIterSym(c.graph, n, getCurrOwner(c))
elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
# top level .closure procs are still somewhat supported for 'Nake':
return makeClosure(s, nil, n.info)
return makeClosure(c.graph, s, nil, n.info)
#elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
# echo n.info, " come heer for ", c.tooEarly
# if not c.tooEarly:
@@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
if sfBorrow in s.flags and s.kind in routineKinds:
# simply exchange the symbol:
b = s.getBody
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
b = newSymNode(b.sym, n.info)
else:
b = n
@@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode =
proc freshVar(c: PTransf; v: PSym): PNode =
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly:
result = freshVarForClosureIter(v, owner)
result = freshVarForClosureIter(c.graph, v, owner)
else:
var newVar = copySym(v)
incl(newVar.flags, sfFromGeneric)
@@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
result[i] = PTransNode(it)
elif it.kind == nkIdentDefs:
if it.sons[0].kind == nkSym:
internalAssert(it.len == 3)
internalAssert(c.graph.config, it.len == 3)
let x = freshVar(c, it.sons[0].sym)
idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
var defs = newTransNode(nkIdentDefs, it.info, 3)
if importantComments():
if importantComments(c.graph.config):
# keep documentation information:
PNode(defs).comment = it.comment
defs[0] = x.PTransNode
@@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
result[i] = transform(c, it)
else:
if it.kind != nkVarTuple:
internalError(it.info, "transformVarSection: not nkVarTuple")
internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
var L = sonsLen(it)
var defs = newTransNode(it.kind, it.info, L)
for j in countup(0, L-3):
@@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
if it.kind == nkCommentStmt:
result[i] = PTransNode(it)
else:
if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
if it.sons[0].kind != nkSym:
internalError(it.info, "transformConstSection")
internalError(c.graph.config, it.info, "transformConstSection")
result[i] = PTransNode(it)
@@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
# XXX: BUG: what if `n` is an expression with side-effects?
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
transform(c, newTupleAccess(n, i))))
transform(c, newTupleAccess(c.graph, n, i))))
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
case n.kind
@@ -382,7 +384,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
PNode(result).typ = n.typ
proc generateThunk(prc: PNode, dest: PType): PNode =
proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
## a closure.
@@ -394,9 +396,9 @@ proc generateThunk(prc: PNode, dest: PType): PNode =
conv.add(emptyNode)
conv.add(prc)
if prc.kind == nkClosure:
internalError(prc.info, "closure to closure created")
internalError(c.graph.config, prc.info, "closure to closure created")
result.add(conv)
result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
proc transformConv(c: PTransf, n: PNode): PTransNode =
# numeric types need range checks:
@@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
of tyProc:
result = transformSons(c, n)
if dest.callConv == ccClosure and source.callConv == ccDefault:
result = generateThunk(result[1].PNode, dest).PTransNode
result = generateThunk(c, result[1].PNode, dest).PTransNode
else:
result = transformSons(c, n)
@@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
if n.kind == nkVarSection:
let x = n.sons[0].sons[0]
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
internalError(x.info, "bah " & x.sym.name.s & " " &
internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
else:
for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
@@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
proc transformFor(c: PTransf, n: PNode): PTransNode =
# generate access statements for the parameters (unless they are constant)
# put mapping from formal parameters to actual parameters
if n.kind != nkForStmt: internalError(n.info, "transformFor")
if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
var length = sonsLen(n)
var call = n.sons[length - 2]
@@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
if not c.tooEarly:
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
else:
result[1] = newNode(nkEmpty).PTransNode
discard c.breakSyms.pop
@@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
while (j < sonsLen(n)):
let b = transform(c, n.sons[j]).PNode
if not isConstExpr(b): break
a = evalOp(op.magic, n, a, b, nil)
a = evalOp(op.magic, n, a, b, nil, c.graph)
inc(j)
add(result, a.PTransNode)
if len(result) == 2: result = result[1]
@@ -708,7 +710,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
let t = lastSon(s.sons[0].sym.ast)
if t.kind != nkSym or sfDispatcher notin t.sym.flags:
methodDef(s.sons[0].sym, false)
result = methodCall(s).PTransNode
result = methodCall(s, c.graph.config).PTransNode
else:
result = s.PTransNode
@@ -719,7 +721,7 @@ proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
let actions = newTransNode(nkStmtListExpr, n[1], 2)
# Generating `let exc = (excType)(getCurrentException())`
# -> getCurrentException()
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode))
# -> (excType)
let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
convNode[0] = PTransNode(ast.emptyNode)
@@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
cnst.len != 0
proc commonOptimizations*(c: PSym, n: PNode): PNode =
proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
result = n
for i in 0 ..< n.safeLen:
result.sons[i] = commonOptimizations(c, n.sons[i])
result.sons[i] = commonOptimizations(g, c, n.sons[i])
var op = getMergeOp(n)
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
result = newNodeIT(nkCall, n.info, n.typ)
@@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
while j < sonsLen(args):
let b = args.sons[j]
if not isConstExpr(b): break
a = evalOp(op.magic, result, a, b, nil)
a = evalOp(op.magic, result, a, b, nil, g)
inc(j)
add(result, a)
if len(result) == 2: result = result[1]
else:
var cnst = getConstExpr(c, n)
var cnst = getConstExpr(c, n, g)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
result = cnst
@@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
let L = n.len-1
result[L] = transform(c, n.sons[L])
# XXX comment handling really sucks:
if importantComments():
if importantComments(c.graph.config):
PNode(result).comment = n.comment
of nkClosure:
# it can happen that for-loop-inlining produced a fresh
@@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
when false:
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
var cnst = getConstExpr(c.module, PNode(result))
var cnst = getConstExpr(c.module, PNode(result), c.graph)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
result = PTransNode(cnst) # do not miss an optimization
@@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
popTransCon(c)
incl(result.flags, nfTransf)
proc openTransf(module: PSym, filename: string): PTransf =
proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
new(result)
result.contSyms = @[]
result.breakSyms = @[]
result.module = module
result.graph = g
proc flattenStmts(n: PNode) =
var goOn = true
@@ -967,46 +970,46 @@ template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
if nfTransf in n.flags or prc.kind in {skTemplate}:
result = n
else:
var c = openTransf(module, "")
result = liftLambdas(prc, n, c.tooEarly)
var c = openTransf(g, module, "")
result = liftLambdas(g, prc, n, c.tooEarly)
#result = n
result = processTransf(c, result, prc)
liftDefer(c, result)
#result = liftLambdas(prc, result)
when useEffectSystem: trackProc(prc, result)
result = liftLocalsIfRequested(prc, result)
when useEffectSystem: trackProc(g, prc, result)
result = liftLocalsIfRequested(prc, result, g.config)
if c.needsDestroyPass: #and newDestructors:
result = injectDestructorCalls(prc, result)
result = injectDestructorCalls(g, prc, result)
incl(result.flags, nfTransf)
#if prc.name.s == "testbody":
# echo renderTree(result)
proc transformStmt*(module: PSym, n: PNode): PNode =
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(module, "")
var c = openTransf(g, module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
#result = liftLambdasForTopLevel(module, result)
when useEffectSystem: trackTopLevelStmt(module, result)
when useEffectSystem: trackTopLevelStmt(g, module, result)
#if n.info ?? "temp.nim":
# echo renderTree(result, {renderIds})
if c.needsDestroyPass:
result = injectDestructorCalls(module, result)
result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf)
proc transformExpr*(module: PSym, n: PNode): PNode =
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(module, "")
var c = openTransf(g, module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
if c.needsDestroyPass:
result = injectDestructorCalls(module, result)
result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf)

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import ast, passes, msgs, idents, intsets, options
import ast, passes, msgs, idents, intsets, options, modulegraphs
const
byteExcess* = 128 # we use excess-K for immediates
@@ -207,18 +207,18 @@ type
errorFlag*: string
cache*: IdentCache
config*: ConfigRef
graph*: ModuleGraph
TPosition* = distinct int
PEvalContext* = PCtx
proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx =
let conf = if config != nil: config else: newConfigRef()
proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
cache: cache, config: conf)
cache: cache, config: g.config, graph: g)
proc refresh*(c: PCtx, module: PSym) =
c.module = module

View File

@@ -9,18 +9,18 @@
import ast, types, msgs, os, streams, options, idents
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string =
try:
var filename = parentDir(info.toFullPath) / file
if not fileExists(filename):
filename = file.findFile
filename = findFile(conf, file)
result = readFile(filename)
# we produce a fake include statement for every slurped filename, so that
# the module dependencies are accurate:
appendToModule(module, newNode(nkIncludeStmt, info, @[
newStrNode(nkStrLit, filename)]))
except IOError:
localError(info, errCannotOpenFile, file)
localError(conf, info, "cannot open file: " & file)
result = ""
proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
@@ -271,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
of tyOr: result = mapTypeToBracket("or", mOr, t, info)
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
of tyAnything: result = atomicType("anything", mNone)
of tyInferred: internalAssert false
of tyInferred: assert false
of tyStatic, tyFromExpr:
if inst:
if t.n != nil: result = t.n.copyTree
@@ -281,7 +281,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result.add atomicType("static", mNone)
if t.n != nil:
result.add t.n.copyTree
of tyUnused, tyOptAsRef: internalError("mapTypeToAstX")
of tyUnused, tyOptAsRef: assert(false, "mapTypeToAstX")
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAstX(t, info, false, true)

View File

@@ -120,7 +120,7 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
c.code.add(ins)
c.debug.add(n.info)
else:
localError(n.info, errGenerated,
localError(c.config, n.info,
"VM: immediate value does not fit into an int8")
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
@@ -137,7 +137,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
c.code.add(ins)
c.debug.add(n.info)
else:
localError(n.info, errGenerated,
localError(c.config, n.info,
"VM: immediate value does not fit into an int16")
proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
@@ -151,7 +151,7 @@ proc genLabel(c: PCtx): TPosition =
proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
let dist = p.int - c.code.len
internalAssert(-0x7fff < dist and dist < 0x7fff)
internalAssert(c.config, -0x7fff < dist and dist < 0x7fff)
gABx(c, n, opcJmpBack, 0, dist)
proc patch(c: PCtx, p: TPosition) =
@@ -159,7 +159,7 @@ proc patch(c: PCtx, p: TPosition) =
let p = p.int
let diff = c.code.len - p
#c.jumpTargets.incl(c.code.len)
internalAssert(-0x7fff < diff and diff < 0x7fff)
internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
let oldInstr = c.code[p]
# opcode and regA stay the same:
c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
@@ -201,7 +201,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
c.slots[i] = (inUse: true, kind: k)
return TRegister(i)
if c.maxSlots >= high(TRegister):
globalError(cc.bestEffort, "VM problem: too many registers required")
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
result = TRegister(c.maxSlots)
c.slots[c.maxSlots] = (inUse: true, kind: k)
inc c.maxSlots
@@ -223,7 +223,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
return
if c.maxSlots+n >= high(TRegister):
globalError(cc.bestEffort, "VM problem: too many registers required")
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
result = TRegister(c.maxSlots)
inc c.maxSlots, n
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
@@ -251,7 +251,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
var d: TDest = dest
gen(c, n, d, flags)
#internalAssert d == dest # issue #7407
#internalAssert c.config, d == dest # issue #7407
proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
var tmp: TDest = -1
@@ -261,7 +261,7 @@ proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
var tmp: TDest = -1
gen(c, n, tmp, flags)
#internalAssert tmp >= 0 # 'nim check' does not like this internalAssert.
#internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert.
if tmp >= 0:
result = TRegister(tmp)
@@ -320,7 +320,7 @@ proc genBreak(c: PCtx; n: PNode) =
if c.prc.blocks[i].label == n.sons[0].sym:
c.prc.blocks[i].fixups.add L1
return
globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
globalError(c.config, n.info, "VM problem: cannot find 'break' target")
else:
c.prc.blocks[c.prc.blocks.high].fixups.add L1
@@ -378,7 +378,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int =
#assert(n.kind != nkCall)
n.flags.incl nfAllConst
c.constants.add n.canonValue
internalAssert result < 0x7fff
internalAssert c.config, result < 0x7fff
proc sameConstant*(a, b: PNode): bool =
result = false
@@ -405,10 +405,10 @@ proc genLiteral(c: PCtx; n: PNode): int =
if sameConstant(c.constants[i], n): return i
result = rawGenLiteral(c, n)
proc unused(n: PNode; x: TDest) {.inline.} =
proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} =
if x >= 0:
#debug(n)
globalError(n.info, "not unused")
globalError(c.config, n.info, "not unused")
proc genCase(c: PCtx; n: PNode; dest: var TDest) =
# if (!expr1) goto L1;
@@ -424,7 +424,7 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
if not isEmptyType(n.typ):
if dest < 0: dest = getTemp(c, n.typ)
else:
unused(n, dest)
unused(c, n, dest)
var endings: seq[TPosition] = @[]
withTemp(tmp, n.sons[0].typ):
c.gen(n.sons[0], tmp)
@@ -451,7 +451,7 @@ proc genType(c: PCtx; typ: PType): int =
if sameType(t, typ): return i
result = c.types.len
c.types.add(typ)
internalAssert(result <= 0x7fff)
internalAssert(c.config, result <= 0x7fff)
proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
@@ -525,7 +525,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
var r: TRegister = x+i
c.gen(n.sons[i], r)
if i >= fntyp.len:
internalAssert tfVarargs in fntyp.flags
internalAssert c.config, tfVarargs in fntyp.flags
c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
if dest < 0:
c.gABC(n, opcIndCall, 0, x, n.len)
@@ -540,12 +540,12 @@ proc needsAsgnPatch(n: PNode): bool =
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
proc genField(n: PNode): TRegister =
proc genField(c: PCtx; n: PNode): TRegister =
if n.kind != nkSym or n.sym.kind != skField:
globalError(n.info, "no field symbol")
globalError(c.config, n.info, "no field symbol")
let s = n.sym
if s.position > high(result):
globalError(n.info,
globalError(c.config, n.info,
"too large offset! cannot generate code for: " & s.name.s)
result = s.position
@@ -572,7 +572,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
# XXX field checks here
let left = if le.kind == nkDotExpr: le else: le.sons[0]
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
let idx = genField(left.sons[1])
let idx = genField(c, left.sons[1])
c.gABC(left, opcWrObj, dest, idx, value)
c.freeTemp(dest)
of nkDerefExpr, nkHiddenDeref:
@@ -779,7 +779,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
let tmp3 = c.getTemp(n.sons[1].typ)
if dest < 0: dest = c.getTemp(n[0].typ)
proc mkIntLit(ival: int): int =
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt)))
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt)))
if src.kind in unsignedIntegers and dst.kind in signedIntegers:
# cast unsigned to signed integer of same size
# signedVal = (unsignedVal xor offset) -% offset
@@ -802,7 +802,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
c.freeTemp(tmp2)
c.freeTemp(tmp3)
else:
globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size")
globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size")
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
case m
@@ -818,7 +818,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mSucc, mAddI:
c.genAddSubInt(n, dest, opcAddInt)
of mInc, mDec:
unused(n, dest)
unused(c, n, dest)
let opc = if m == mInc: opcAddInt else: opcSubInt
let d = c.genx(n.sons[1])
if n.sons[2].isInt8Lit:
@@ -832,10 +832,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.freeTemp(d)
of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
of mNew, mNewFinalize:
unused(n, dest)
unused(c, n, dest)
c.genNew(n)
of mNewSeq:
unused(n, dest)
unused(c, n, dest)
c.genNewSeq(n)
of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
of mNewString:
@@ -855,7 +855,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mLengthStr, mXLenStr:
genUnaryABI(c, n, dest, opcLenStr)
of mIncl, mExcl:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
var tmp = c.genx(n.sons[2])
c.genSetType(n.sons[1], d)
@@ -952,19 +952,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mInSet: genBinarySet(c, n, dest, opcContainsSet)
of mRepr: genUnaryABC(c, n, dest, opcRepr)
of mExit:
unused(n, dest)
unused(c, n, dest)
var tmp = c.genx(n.sons[1])
c.gABC(n, opcQuit, tmp)
c.freeTemp(tmp)
of mSetLengthStr, mSetLengthSeq:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
var tmp = c.genx(n.sons[2])
c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
c.genAsgnPatch(n.sons[1], d)
c.freeTemp(tmp)
of mSwap:
unused(n, dest)
unused(c, n, dest)
c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym))
of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
of mCopyStr:
@@ -996,7 +996,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
# skip 'nkHiddenAddr':
let d2AsNode = n.sons[2].sons[0]
if needsAsgnPatch(d2AsNode):
d2 = c.getTemp(getSysType(tyFloat))
d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat))
else:
d2 = c.genx(d2AsNode)
var
@@ -1009,13 +1009,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genAsgnPatch(d2AsNode, d2)
c.freeTemp(d2)
of mReset:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
c.gABC(n, opcReset, d)
of mOf, mIs:
if dest < 0: dest = c.getTemp(n.typ)
var tmp = c.genx(n.sons[1])
var idx = c.getTemp(getSysType(tyInt))
var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
var typ = n.sons[2].typ
if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
c.gABx(n, opcLdImmInt, idx, c.genType(typ))
@@ -1023,7 +1023,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.freeTemp(tmp)
c.freeTemp(idx)
of mSizeOf:
globalError(n.info, errCannotInterpretNodeX, renderTree(n))
globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n))
of mHigh:
if dest < 0: dest = c.getTemp(n.typ)
let tmp = c.genx(n.sons[1])
@@ -1034,23 +1034,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABI(n, opcLenSeq, dest, tmp, 1)
c.freeTemp(tmp)
of mEcho:
unused(n, dest)
unused(c, n, dest)
let n = n[1].skipConv
let x = c.getTempRange(n.len, slotTempUnknown)
internalAssert n.kind == nkBracket
internalAssert c.config, n.kind == nkBracket
for i in 0..<n.len:
var r: TRegister = x+i
c.gen(n.sons[i], r)
c.gABC(n, opcEcho, x, n.len)
c.freeTempRange(x, n.len)
of mAppendStrCh:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddStrCh)
of mAppendStrStr:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddStrStr)
of mAppendSeqElem:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddSeqElem)
of mParseExprToAst:
genUnaryABC(c, n, dest, opcParseExprToAst)
@@ -1068,7 +1068,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
of mNChild: genBinaryABC(c, n, dest, opcNChild)
of mNSetChild, mNDel:
unused(n, dest)
unused(c, n, dest)
var
tmp1 = c.genx(n.sons[1])
tmp2 = c.genx(n.sons[2])
@@ -1098,22 +1098,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
#genUnaryABC(c, n, dest, opcNGetType)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
of mNSetIntVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetIntVal)
of mNSetFloatVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetFloatVal)
of mNSetSymbol:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetSymbol)
of mNSetIdent:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetIdent)
of mNSetType:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetType)
of mNSetStrVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetStrVal)
of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
@@ -1124,7 +1124,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcNBindSym, dest, idx)
else:
localError(n.info, "invalid bindSym usage")
localError(c.config, n.info, "invalid bindSym usage")
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
@@ -1138,12 +1138,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of "getColumn":
genUnaryABC(c, n, dest, opcNGetColumn)
else:
internalAssert false
internalAssert c.config, false
of mNHint:
unused(n, dest)
unused(c, n, dest)
genUnaryStmt(c, n, opcNHint)
of mNWarning:
unused(n, dest)
unused(c, n, dest)
genUnaryStmt(c, n, opcNWarning)
of mNError:
if n.len <= 1:
@@ -1151,7 +1151,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABC(n, opcQueryErrorFlag, dest)
else:
# setter
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNError)
of mNCallSite:
if dest < 0: dest = c.getTemp(n.typ)
@@ -1162,7 +1162,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genCall(n, dest)
of mExpandToAst:
if n.len != 2:
globalError(n.info, errGenerated, "expandToAst requires 1 argument")
globalError(c.config, n.info, "expandToAst requires 1 argument")
let arg = n.sons[1]
if arg.kind in nkCallKinds:
#if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
@@ -1172,12 +1172,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
# do not call clearDest(n, dest) here as getAst has a meta-type as such
# produces a value
else:
globalError(n.info, "expandToAst requires a call expression")
globalError(c.config, n.info, "expandToAst requires a call expression")
of mRunnableExamples:
discard "just ignore any call to runnableExamples"
else:
# mGCref, mGCunref,
globalError(n.info, "cannot generate code for: " & $m)
globalError(c.config, n.info, "cannot generate code for: " & $m)
proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
## Signature: proc to*[T](data: string): T
@@ -1306,14 +1306,14 @@ proc setSlot(c: PCtx; v: PSym) =
if v.position == 0:
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
if c.prc.maxSlots >= high(TRegister):
globalError(v.info, "cannot generate code; too many registers required")
globalError(c.config, v.info, "cannot generate code; too many registers required")
v.position = c.prc.maxSlots
c.prc.slots[v.position] = (inUse: true,
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
inc c.prc.maxSlots
proc cannotEval(n: PNode) {.noinline.} =
globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
globalError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
proc isOwnedBy(a, b: PSym): bool =
@@ -1333,10 +1333,10 @@ proc checkCanEval(c: PCtx; n: PNode) =
if {sfCompileTime, sfGlobal} <= s.flags: return
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
cannotEval(n)
cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
cannotEval(n)
cannotEval(c, n)
proc isTemp(c: PCtx; dest: TDest): bool =
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
@@ -1378,7 +1378,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
# XXX field checks here
let left = if le.kind == nkDotExpr: le else: le.sons[0]
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
let idx = genField(left.sons[1])
let idx = genField(c, left.sons[1])
let tmp = c.genx(ri)
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
c.freeTemp(tmp)
@@ -1398,7 +1398,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(val)
else:
if s.kind == skForVar: c.setSlot s
internalAssert s.position > 0 or (s.position == 0 and
internalAssert c.config, s.position > 0 or (s.position == 0 and
s.kind in {skParam,skResult})
var dest: TRegister = s.position + ord(s.kind == skParam)
assert le.typ != nil
@@ -1424,15 +1424,15 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
c.globals.add(importcSymbol(s))
s.position = c.globals.len
else:
localError(info, errGenerated, "VM is not allowed to 'importc'")
localError(c.config, info, "VM is not allowed to 'importc'")
else:
localError(info, errGenerated,
localError(c.config, info,
"cannot 'importc' variable at compile time")
proc getNullValue*(typ: PType, info: TLineInfo): PNode
proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.globals.add(getNullValue(s.typ, n.info))
c.globals.add(getNullValue(s.typ, n.info, c.config))
s.position = c.globals.len
# This is rather hard to support, due to the laziness of the VM code
# generator. See tests/compile/tmacro2 for why this is necessary:
@@ -1451,7 +1451,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
if sfCompileTime in s.flags or c.mode == emRepl:
discard
elif s.position == 0:
cannotEval(n)
cannotEval(c, n)
if s.position == 0:
if sfImportc in s.flags: c.importcSym(n.info, s)
else: genGlobalInit(c, n, s)
@@ -1472,13 +1472,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
s.kind in {skParam,skResult}):
if dest < 0:
dest = s.position + ord(s.kind == skParam)
internalAssert(c.prc.slots[dest].kind < slotSomeTemp)
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
else:
# we need to generate an assignment:
genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp)
else:
# see tests/t99bott for an example that triggers it:
cannotEval(n)
cannotEval(c, n)
template needsRegLoad(): untyped =
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
@@ -1502,7 +1502,7 @@ proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
let a = c.genx(n.sons[0], flags)
let b = genField(n.sons[1])
let b = genField(c, n.sons[1])
if dest < 0: dest = c.getTemp(n.typ)
if needsRegLoad():
var cc = c.getTemp(n.typ)
@@ -1526,22 +1526,22 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
else:
genArrAccess2(c, n, dest, opcLdArr, flags)
proc getNullValueAux(obj: PNode, result: PNode) =
proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) =
case obj.kind
of nkRecList:
for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result, conf)
of nkRecCase:
getNullValueAux(obj.sons[0], result)
getNullValueAux(obj.sons[0], result, conf)
for i in countup(1, sonsLen(obj) - 1):
getNullValueAux(lastSon(obj.sons[i]), result)
getNullValueAux(lastSon(obj.sons[i]), result, conf)
of nkSym:
let field = newNodeI(nkExprColonExpr, result.info)
field.add(obj)
field.add(getNullValue(obj.sym.typ, result.info))
field.add(getNullValue(obj.sym.typ, result.info, conf))
addSon(result, field)
else: globalError(result.info, "cannot create null element for: " & $obj)
else: globalError(conf, result.info, "cannot create null element for: " & $obj)
proc getNullValue(typ: PType, info: TLineInfo): PNode =
proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
var t = skipTypes(typ, abstractRange-{tyTypeDesc})
result = emptyNode
case t.kind
@@ -1570,17 +1570,17 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
# initialize inherited fields:
var base = t.sons[0]
while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result)
getNullValueAux(skipTypes(base, skipPtrs).n, result, conf)
base = base.sons[0]
getNullValueAux(t.n, result)
getNullValueAux(t.n, result, conf)
of tyArray:
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info))
addSon(result, getNullValue(elemType(t), info, conf))
of tyTuple:
result = newNodeIT(nkTupleConstr, info, t)
for i in countup(0, sonsLen(t) - 1):
addSon(result, getNullValue(t.sons[i], info))
addSon(result, getNullValue(t.sons[i], info, conf))
of tySet:
result = newNodeIT(nkCurly, info, t)
of tyOpt:
@@ -1588,7 +1588,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tySequence:
result = newNodeIT(nkBracket, info, t)
else:
globalError(info, "cannot create null element for: " & $t.kind)
globalError(conf, info, "cannot create null element for: " & $t.kind)
proc ldNullOpcode(t: PType): TOpcode =
assert t != nil
@@ -1602,7 +1602,7 @@ proc genVarSection(c: PCtx; n: PNode) =
for i in 0 .. a.len-3:
if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
checkCanEval(c, a[i])
c.gen(lowerTupleUnpacking(a, c.getOwner))
c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner))
elif a.sons[0].kind == nkSym:
let s = a.sons[0].sym
checkCanEval(c, a.sons[0])
@@ -1610,7 +1610,7 @@ proc genVarSection(c: PCtx; n: PNode) =
if s.position == 0:
if sfImportc in s.flags: c.importcSym(a.info, s)
else:
let sa = getNullValue(s.typ, a.info)
let sa = getNullValue(s.typ, a.info, c.config)
#if s.ast.isNil: getNullValue(s.typ, a.info)
#else: canonValue(s.ast)
assert sa.kind != nkCall
@@ -1652,7 +1652,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(tyInt)
let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
@@ -1696,13 +1696,13 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
for i in 1..<n.len:
let it = n.sons[i]
if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
let idx = genField(it.sons[0])
let idx = genField(c, it.sons[0])
let tmp = c.genx(it.sons[1])
c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
dest, idx, tmp)
c.freeTemp(tmp)
else:
globalError(n.info, "invalid object constructor")
globalError(c.config, n.info, "invalid object constructor")
proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
@@ -1711,7 +1711,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
for i in 0..<n.len:
let it = n.sons[i]
if it.kind == nkExprColonExpr:
let idx = genField(it.sons[0])
let idx = genField(c, it.sons[0])
let tmp = c.genx(it.sons[1])
c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
dest, idx, tmp)
@@ -1786,9 +1786,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if c.prc.sym != nil and c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
of nkCallKinds:
if n.sons[0].kind == nkSym:
let s = n.sons[0].sym
@@ -1812,10 +1812,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genLit(c, n, dest)
of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
of nkNilLit:
if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
else: unused(n, dest)
if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest)
else: unused(c, n, dest)
of nkAsgn, nkFastAsgn:
unused(n, dest)
unused(c, n, dest)
genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
of nkDotExpr: genObjAccess(c, n, dest, flags)
of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
@@ -1828,20 +1828,20 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
gen(c, n.sons[0].sons[1], dest)
of nkCaseStmt: genCase(c, n, dest)
of nkWhileStmt:
unused(n, dest)
unused(c, n, dest)
genWhile(c, n)
of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
of nkReturnStmt:
unused(n, dest)
unused(c, n, dest)
genReturn(c, n)
of nkRaiseStmt:
genRaise(c, n)
of nkBreakStmt:
unused(n, dest)
unused(c, n, dest)
genBreak(c, n)
of nkTryStmt: genTry(c, n, dest)
of nkStmtList:
#unused(n, dest)
#unused(c, n, dest)
# XXX Fix this bug properly, lexim triggers it
for x in n: gen(c, x)
of nkStmtListExpr:
@@ -1851,17 +1851,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPragmaBlock:
gen(c, n.lastSon, dest, flags)
of nkDiscardStmt:
unused(n, dest)
unused(c, n, dest)
gen(c, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n.sons[1], dest)
of nkObjDownConv:
genConv(c, n, n.sons[0], dest)
of nkVarSection, nkLetSection:
unused(n, dest)
unused(c, n, dest)
genVarSection(c, n)
of declarativeDefs, nkMacroDef:
unused(n, dest)
unused(c, n, dest)
of nkLambdaKinds:
#let s = n.sons[namePos].sym
#discard genProc(c, s)
@@ -1881,7 +1881,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
unused(n, dest)
unused(c, n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n.sons[0], dest)
of nkBracket: genArrayConstr(c, n, dest)
@@ -1898,7 +1898,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkComesFrom:
discard "XXX to implement for better stack traces"
else:
globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
globalError(c.config, n.info, "cannot generate VM code for " & $n)
proc removeLastEof(c: PCtx) =
let last = c.code.len-1
@@ -1915,7 +1915,7 @@ proc genStmt*(c: PCtx; n: PNode): int =
c.gen(n, d)
c.gABC(n, opcEof)
if d >= 0:
globalError(n.info, errGenerated, "VM problem: dest register is set")
globalError(c.config, n.info, "VM problem: dest register is set")
proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
c.removeLastEof
@@ -1924,7 +1924,7 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
c.gen(n, d)
if d < 0:
if requiresValue:
globalError(n.info, errGenerated, "VM problem: dest register is not set")
globalError(c.config, n.info, "VM problem: dest register is not set")
d = 0
c.gABC(n, opcEof, d)
@@ -1939,7 +1939,7 @@ proc genParams(c: PCtx; params: PNode) =
c.prc.maxSlots = max(params.len, 1)
proc finalJumpTarget(c: PCtx; pc, diff: int) =
internalAssert(-0x7fff < diff and diff < 0x7fff)
internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
let oldInstr = c.code[pc]
# opcode and regA stay the same:
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or

View File

@@ -9,7 +9,8 @@
## Implements marshaling for the VM.
import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
import streams, json, intsets, tables, ast, astalgo, idents, types, msgs,
options
proc ptrToInt(x: PNode): int {.inline.} =
result = cast[int](x) # don't skip alignment
@@ -28,37 +29,38 @@ proc getField(n: PNode; position: int): PSym =
of nkOfBranch, nkElse:
result = getField(lastSon(n.sons[i]), position)
if result != nil: return
else: internalError(n.info, "getField(record case branch)")
else: discard
of nkSym:
if n.sym.position == position: result = n.sym
else: discard
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: ConfigRef)
proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
internalAssert x.kind == nkObjConstr
proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) =
assert x.kind == nkObjConstr
let start = 1
for i in countup(start, sonsLen(x) - 1):
if i > start: s.add(", ")
var it = x.sons[i]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym
let field = it.sons[0].sym
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it.sons[1], stored)
if it.sons[0].kind == nkSym:
let field = it.sons[0].sym
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it.sons[1], stored, conf)
elif typ.n != nil:
let field = getField(typ.n, i)
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it, stored)
storeAny(s, field.typ, it, stored, conf)
proc skipColon*(n: PNode): PNode =
result = n
if n.kind == nkExprColonExpr:
result = n.sons[1]
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
conf: ConfigRef) =
case t.kind
of tyNone: assert false
of tyBool: s.add($(a.intVal != 0))
@@ -74,7 +76,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
s.add("[")
for i in 0 .. a.len-1:
if i > 0: s.add(", ")
storeAny(s, t.elemType, a[i], stored)
storeAny(s, t.elemType, a[i], stored, conf)
s.add("]")
of tyTuple:
s.add("{")
@@ -82,11 +84,11 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
if i > 0: s.add(", ")
s.add("\"Field" & $i)
s.add("\": ")
storeAny(s, t.sons[i], a[i].skipColon, stored)
storeAny(s, t.sons[i], a[i].skipColon, stored, conf)
s.add("}")
of tyObject:
s.add("{")
storeObj(s, t, a, stored)
storeObj(s, t, a, stored, conf)
s.add("}")
of tySet:
s.add("[")
@@ -94,15 +96,16 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
if i > 0: s.add(", ")
if a[i].kind == nkRange:
var x = copyNode(a[i][0])
storeAny(s, t.lastSon, x, stored)
storeAny(s, t.lastSon, x, stored, conf)
while x.intVal+1 <= a[i][1].intVal:
s.add(", ")
storeAny(s, t.lastSon, x, stored)
storeAny(s, t.lastSon, x, stored, conf)
inc x.intVal
else:
storeAny(s, t.lastSon, a[i], stored)
storeAny(s, t.lastSon, a[i], stored, conf)
s.add("]")
of tyRange, tyGenericInst, tyAlias, tySink: storeAny(s, t.lastSon, a, stored)
of tyRange, tyGenericInst, tyAlias, tySink:
storeAny(s, t.lastSon, a, stored, conf)
of tyEnum:
# we need a slow linear search because of enums with holes:
for e in items(t.n):
@@ -121,7 +124,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
s.add("[")
s.add($x.ptrToInt)
s.add(", ")
storeAny(s, t.lastSon, a, stored)
storeAny(s, t.lastSon, a, stored, conf)
s.add("]")
of tyString, tyCString:
if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
@@ -129,14 +132,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
of tyFloat..tyFloat128: s.add($a.floatVal)
else:
internalError a.info, "cannot marshal at compile-time " & t.typeToString
internalError conf, a.info, "cannot marshal at compile-time " & t.typeToString
proc storeAny*(s: var string; t: PType; a: PNode) =
proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) =
var stored = initIntSet()
storeAny(s, t, a, stored)
storeAny(s, t, a, stored, conf)
proc loadAny(p: var JsonParser, t: PType,
tab: var Table[BiggestInt, PNode]): PNode =
tab: var Table[BiggestInt, PNode];
conf: ConfigRef): PNode =
case t.kind
of tyNone: assert false
of tyBool:
@@ -170,7 +174,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkBracket)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.elemType, tab)
result.add loadAny(p, t.elemType, tab, conf)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
of tySequence:
@@ -182,7 +186,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkBracket)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.elemType, tab)
result.add loadAny(p, t.elemType, tab, conf)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "")
else:
@@ -198,7 +202,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
if i >= t.len:
raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
result.add loadAny(p, t.sons[i], tab)
result.add loadAny(p, t.sons[i], tab, conf)
inc i
if p.kind == jsonObjectEnd: next(p)
else: raiseParseErr(p, "'}' end of object expected")
@@ -220,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType,
setLen(result.sons, pos + 1)
let fieldNode = newNode(nkExprColonExpr)
fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo())))
fieldNode.addSon(loadAny(p, field.typ, tab))
fieldNode.addSon(loadAny(p, field.typ, tab, conf))
result.sons[pos] = fieldNode
if p.kind == jsonObjectEnd: next(p)
else: raiseParseErr(p, "'}' end of object expected")
@@ -229,7 +233,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkCurly)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.lastSon, tab)
result.add loadAny(p, t.lastSon, tab, conf)
next(p)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
@@ -248,7 +252,7 @@ proc loadAny(p: var JsonParser, t: PType,
if p.kind == jsonInt:
let idx = p.getInt
next(p)
result = loadAny(p, t.lastSon, tab)
result = loadAny(p, t.lastSon, tab, conf)
tab[idx] = result
else: raiseParseErr(p, "index for ref type expected")
if p.kind == jsonArrayEnd: next(p)
@@ -275,14 +279,15 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
return
raiseParseErr(p, "float expected")
of tyRange, tyGenericInst, tyAlias, tySink: result = loadAny(p, t.lastSon, tab)
of tyRange, tyGenericInst, tyAlias, tySink:
result = loadAny(p, t.lastSon, tab, conf)
else:
internalError "cannot marshal at compile-time " & t.typeToString
internalError conf, "cannot marshal at compile-time " & t.typeToString
proc loadAny*(s: string; t: PType): PNode =
proc loadAny*(s: string; t: PType; conf: ConfigRef): PNode =
var tab = initTable[BiggestInt, PNode]()
var p: JsonParser
open(p, newStringStream(s), "unknown file")
next(p)
result = loadAny(p, t, tab)
result = loadAny(p, t, tab, conf)
close(p)