first steps in adding template/macro calls to stack traces

This commit is contained in:
Araq 2017-12-21 10:03:33 +01:00
commit ee67a67ac4
17 changed files with 96 additions and 38 deletions

View file

@ -62,8 +62,8 @@ type
nkTripleStrLit, # a triple string literal """ nkTripleStrLit, # a triple string literal """
nkNilLit, # the nil literal nkNilLit, # the nil literal
# end of atoms # end of atoms
nkMetaNode_Obsolete, # difficult to explain; represents itself nkComesFrom, # "comes from" template/macro information for
# (used for macros) # better stack trace generation
nkDotCall, # used to temporarily flag a nkCall node; nkDotCall, # used to temporarily flag a nkCall node;
# this is used # this is used
# for transforming ``s.len`` to ``len(s)`` # for transforming ``s.len`` to ``len(s)``

View file

@ -1982,10 +1982,35 @@ proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
assert((sym.loc.r != nil) and (sym.loc.t != nil)) assert((sym.loc.r != nil) and (sym.loc.t != nil))
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
template genStmtListExprImpl(exprOrStmt) {.dirty.} =
#let hasNimFrame = magicsys.getCompilerProc("nimFrame") != nil
let hasNimFrame = p.prc != nil and
sfSystemModule notin p.module.module.flags and
optStackTrace in p.prc.options
var frameName: Rope = nil
for i in 0 .. n.len - 2:
let it = n[i]
if it.kind == nkComesFrom:
if hasNimFrame and frameName == nil:
inc p.labels
frameName = "FR" & rope(p.labels) & "_"
let theMacro = it[0].sym
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
makeCString theMacro.name.s,
theMacro.info.quotedFilename, it.info.line)
else:
genStmts(p, it)
if n.len > 0: exprOrStmt
if frameName != nil:
add p.s(cpsStmts), deinitFrameNoDebug(p, frameName)
proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) = proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) =
var length = sonsLen(n) genStmtListExprImpl:
for i in countup(0, length - 2): genStmts(p, n.sons[i]) expr(p, n[n.len - 1], d)
if length > 0: expr(p, n.sons[length - 1], d)
proc genStmtList(p: BProc, n: PNode) =
genStmtListExprImpl:
genStmts(p, n[n.len - 1])
proc upConv(p: BProc, n: PNode, d: var TLoc) = proc upConv(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
@ -2184,8 +2209,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d) of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
of nkBlockExpr, nkBlockStmt: genBlock(p, n, d) of nkBlockExpr, nkBlockStmt: genBlock(p, n, d)
of nkStmtListExpr: genStmtListExpr(p, n, d) of nkStmtListExpr: genStmtListExpr(p, n, d)
of nkStmtList: of nkStmtList: genStmtList(p, n)
for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i])
of nkIfExpr, nkIfStmt: genIf(p, n, d) of nkIfExpr, nkIfStmt: genIf(p, n, d)
of nkWhen: of nkWhen:
# This should be a "when nimvm" node. # This should be a "when nimvm" node.

View file

@ -564,9 +564,6 @@ proc genBreakStmt(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label]) lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string =
result = "#raiseException((#Exception*)$1, $2);$n"
proc genRaiseStmt(p: BProc, t: PNode) = proc genRaiseStmt(p: BProc, t: PNode) =
if p.inExceptBlock > 0: if p.inExceptBlock > 0:
# if the current try stmt have a finally block, # if the current try stmt have a finally block,
@ -580,7 +577,8 @@ proc genRaiseStmt(p: BProc, t: PNode) =
var e = rdLoc(a) var e = rdLoc(a)
var typ = skipTypes(t.sons[0].typ, abstractPtrs) var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t) genLineDir(p, t)
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
[e, makeCString(typ.sym.name.s)])
else: else:
genLineDir(p, t) genLineDir(p, t)
# reraise the last exception: # reraise the last exception:

View file

@ -493,7 +493,32 @@ proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
proc lenField(p: BProc): Rope = proc lenField(p: BProc): Rope =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len") result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim" include ccgcalls, "ccgstmts.nim"
proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "VarSlot")
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.rope)
else:
result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
discard cgsym(p.module, "nimFrame")
addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " &
" $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
frame, procname, filename, rope(line))
proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope =
result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n")
include ccgexprs
# ----------------------------- dynamic library handling ----------------- # ----------------------------- dynamic library handling -----------------
# We don't finalize dynamic libs as the OS does this for us. # We don't finalize dynamic libs as the OS does this for us.
@ -600,7 +625,7 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.typ.sym = nil # generate a new name sym.typ.sym = nil # generate a new name
proc cgsym(m: BModule, name: string): Rope = proc cgsym(m: BModule, name: string): Rope =
var sym = magicsys.getCompilerProc(name) let sym = magicsys.getCompilerProc(name)
if sym != nil: if sym != nil:
case sym.kind case sym.kind
of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym) of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
@ -637,19 +662,6 @@ proc generateHeaders(m: BModule) =
add(m.s[cfsHeaders], "#undef powerpc" & tnl) add(m.s[cfsHeaders], "#undef powerpc" & tnl)
add(m.s[cfsHeaders], "#undef unix" & tnl) add(m.s[cfsHeaders], "#undef unix" & tnl)
proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "VarSlot")
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.rope)
else:
result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n")
proc closureSetup(p: BProc, prc: PSym) = proc closureSetup(p: BProc, prc: PSym) =
if tfCapturesEnv notin prc.typ.flags: return if tfCapturesEnv notin prc.typ.flags: return
# prc.ast[paramsPos].last contains the type we're after: # prc.ast[paramsPos].last contains the type we're after:

View file

@ -109,7 +109,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
var evalTemplateCounter* = 0 var evalTemplateCounter* = 0
# to prevent endless recursion in templates instantiation # to prevent endless recursion in templates instantiation
proc wrapInComesFrom*(info: TLineInfo; res: PNode): PNode = proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
when true: when true:
result = res result = res
result.info = info result.info = info
@ -124,8 +124,12 @@ proc wrapInComesFrom*(info: TLineInfo; res: PNode): PNode =
if x[i].kind in nkCallKinds: if x[i].kind in nkCallKinds:
x.sons[i].info = info x.sons[i].info = info
else: else:
result = newNodeI(nkPar, info) result = newNodeI(nkStmtListExpr, info)
var d = newNodeI(nkComesFrom, info)
d.add newSymNode(sym, info)
result.add d
result.add res result.add res
result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode = proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
inc(evalTemplateCounter) inc(evalTemplateCounter)
@ -156,6 +160,6 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
for i in countup(0, safeLen(body) - 1): for i in countup(0, safeLen(body) - 1):
evalTemplateAux(body.sons[i], args, ctx, result) evalTemplateAux(body.sons[i], args, ctx, result)
result.flags.incl nfFromTemplate result.flags.incl nfFromTemplate
result = wrapInComesFrom(n.info, result) result = wrapInComesFrom(n.info, tmpl, result)
dec(evalTemplateCounter) dec(evalTemplateCounter)

View file

@ -2369,6 +2369,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkGotoState, nkState: of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented") internalError(n.info, "first class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r) of nkPragmaBlock: gen(p, n.lastSon, r)
of nkComesFrom:
discard "XXX to implement for better stack traces"
else: internalError(n.info, "gen: unknown node type: " & $n.kind) else: internalError(n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals var globals: PGlobals

View file

@ -723,7 +723,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
result = accessViaEnvParam(n, owner) result = accessViaEnvParam(n, owner)
else: else:
result = accessViaEnvVar(n, owner, d, c) result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
nkTemplateDef, nkTypeSection: nkTemplateDef, nkTypeSection:
discard discard
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef: of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef:

View file

@ -1397,8 +1397,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkBracketRi, "]") put(g, tkBracketRi, "]")
of nkTupleClassTy: of nkTupleClassTy:
put(g, tkTuple, "tuple") put(g, tkTuple, "tuple")
of nkMetaNode_Obsolete: of nkComesFrom:
put(g, tkParLe, "(META|") put(g, tkParLe, "(ComesFrom|")
gsub(g, n, 0) gsub(g, n, 0)
put(g, tkParRi, ")") put(g, tkParRi, ")")
of nkGotoState, nkState: of nkGotoState, nkState:

View file

@ -423,7 +423,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
result = evalMacroCall(c.module, c.cache, n, nOrig, sym) result = evalMacroCall(c.module, c.cache, n, nOrig, sym)
if efNoSemCheck notin flags: if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags) result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, result) result = wrapInComesFrom(nOrig.info, sym, result)
popInfoContext() popInfoContext()
proc forceBool(c: PContext, n: PNode): PNode = proc forceBool(c: PContext, n: PNode): PNode =

View file

@ -2380,6 +2380,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if n.len != 1 and n.len != 2: illFormedAst(n) if n.len != 1 and n.len != 2: illFormedAst(n)
for i in 0 ..< n.len: for i in 0 ..< n.len:
n.sons[i] = semExpr(c, n.sons[i]) n.sons[i] = semExpr(c, n.sons[i])
of nkComesFrom: discard "ignore the comes from information for now"
else: else:
localError(n.info, errInvalidExpressionX, localError(n.info, errInvalidExpressionX,
renderTree(n, {renderNoComments})) renderTree(n, {renderNoComments}))

View file

@ -655,5 +655,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result.typ = n.typ result.typ = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n) of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n) of nkDotExpr: result = foldFieldAccess(m, n)
of nkStmtListExpr:
if n.len == 2 and n[0].kind == nkComesFrom:
result = getConstExpr(m, n[1])
else: else:
discard discard

View file

@ -186,7 +186,7 @@ proc semGenericStmt(c: PContext, n: PNode,
let a = n.sym let a = n.sym
let b = getGenSym(c, a) let b = getGenSym(c, a)
if b != a: n.sym = b if b != a: n.sym = b
of nkEmpty, succ(nkSym)..nkNilLit: of nkEmpty, succ(nkSym)..nkNilLit, nkComesFrom:
# see tests/compile/tgensymgeneric.nim: # see tests/compile/tgensymgeneric.nim:
# We need to open the gensym'ed symbol again so that the instantiation # We need to open the gensym'ed symbol again so that the instantiation
# creates a fresh copy; but this is wrong the very first reason for gensym # creates a fresh copy; but this is wrong the very first reason for gensym

View file

@ -331,7 +331,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkMixinStmt: of nkMixinStmt:
if c.scopeN > 0: result = semTemplBodySons(c, n) if c.scopeN > 0: result = semTemplBodySons(c, n)
else: result = semMixinStmt(c.c, n, c.toMixin) else: result = semMixinStmt(c.c, n, c.toMixin)
of nkEmpty, nkSym..nkNilLit: of nkEmpty, nkSym..nkNilLit, nkComesFrom:
discard discard
of nkIfStmt: of nkIfStmt:
for i in countup(0, sonsLen(n)-1): for i in countup(0, sonsLen(n)-1):
@ -528,7 +528,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
result = semTemplBodyDirty(c, n.sons[0]) result = semTemplBodyDirty(c, n.sons[0])
of nkBindStmt: of nkBindStmt:
result = semBindStmt(c.c, n, c.toBind) result = semBindStmt(c.c, n, c.toBind)
of nkEmpty, nkSym..nkNilLit: of nkEmpty, nkSym..nkNilLit, nkComesFrom:
discard discard
else: else:
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',

View file

@ -791,7 +791,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
case n.kind case n.kind
of nkSym: of nkSym:
result = transformSym(c, n) result = transformSym(c, n)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom:
# nothing to be done for leaves: # nothing to be done for leaves:
result = PTransNode(n) result = PTransNode(n)
of nkBracketExpr: result = transformArrayAccess(c, n) of nkBracketExpr: result = transformArrayAccess(c, n)

View file

@ -1847,6 +1847,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
globalError(n.info, errGenerated, "VM is not allowed to 'cast'") globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
of nkTypeOfExpr: of nkTypeOfExpr:
genTypeLit(c, n.typ, dest) genTypeLit(c, n.typ, dest)
of nkComesFrom:
discard "XXX to implement for better stack traces"
else: else:
globalError(n.info, errGenerated, "cannot generate VM code for " & $n) globalError(n.info, errGenerated, "cannot generate VM code for " & $n)

View file

@ -21,7 +21,7 @@ type
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit, nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit, nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall, nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
nnkCommand, nnkCall, nnkCallStrLit, nnkInfix, nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
nnkPrefix, nnkPostfix, nnkHiddenCallConv, nnkPrefix, nnkPostfix, nnkHiddenCallConv,
nnkExprEqExpr, nnkExprEqExpr,

View file

@ -70,6 +70,18 @@ proc getFrame*(): PFrame {.compilerRtl, inl.} = framePtr
proc popFrame {.compilerRtl, inl.} = proc popFrame {.compilerRtl, inl.} =
framePtr = framePtr.prev framePtr = framePtr.prev
when false:
proc popFrameOfAddr(s: PFrame) {.compilerRtl.} =
var it = framePtr
if it == s:
framePtr = framePtr.prev
else:
while it != nil:
if it == s:
framePtr = it.prev
break
it = it.prev
proc setFrame*(s: PFrame) {.compilerRtl, inl.} = proc setFrame*(s: PFrame) {.compilerRtl, inl.} =
framePtr = s framePtr = s