implemented 'injectStmt'; more debug support

This commit is contained in:
Araq 2013-12-16 22:26:17 +01:00
commit 132b6b3efe
12 changed files with 60 additions and 12 deletions

View file

@ -290,6 +290,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
genNamedParamCall(p, e, d) genNamedParamCall(p, e, d)
else: else:
genPrefixCall(p, nil, e, d) genPrefixCall(p, nil, e, d)
postStmtActions(p)
when false: when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d) if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
@ -303,6 +304,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
genNamedParamCall(p, ri, d) genNamedParamCall(p, ri, d)
else: else:
genPrefixCall(p, le, ri, d) genPrefixCall(p, le, ri, d)
postStmtActions(p)
when false: when false:
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d) if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)

View file

@ -906,7 +906,12 @@ proc genPragma(p: BProc, n: PNode) =
of wEmit: genEmit(p, it) of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it) of wBreakpoint: genBreakPoint(p, it)
of wWatchpoint: genWatchpoint(p, it) of wWatchpoint: genWatchpoint(p, it)
else: nil of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}
genStmts(p, it.sons[1])
p.module.injectStmt = p.s(cpsStmts)
else: discard
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options: if optFieldCheck in p.options:

View file

@ -289,6 +289,9 @@ proc genLineDir(p: BProc, t: PNode) =
linefmt(p, cpsStmts, "nimln($1, $2);$n", linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename) line.toRope, t.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} =
app(p.s(cpsStmts), p.module.injectStmt)
proc accessThreadLocalVar(p: BProc, s: PSym) proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.} proc emulatedThreadVars(): bool {.inline.}

View file

@ -111,6 +111,7 @@ type
labels*: natural # for generating unique module-scope names labels*: natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', PRope] # special procs for the extensionLoaders*: array['0'..'9', PRope] # special procs for the
# OpenGL wrapper # OpenGL wrapper
injectStmt*: PRope
var var
mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module

View file

@ -43,7 +43,8 @@ const
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto} wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
wInjectStmt}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame, wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
@ -722,6 +723,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wOperator: of wOperator:
if sym == nil: invalidPragma(it) if sym == nil: invalidPragma(it)
else: sym.position = expectIntLit(c, it) else: sym.position = expectIntLit(c, it)
of wInjectStmt:
if it.kind != nkExprColonExpr:
localError(it.info, errExprExpected)
else:
it.sons[1] = c.semExpr(c, it.sons[1])
else: invalidPragma(it) else: invalidPragma(it)
else: invalidPragma(it) else: invalidPragma(it)
else: processNote(c, it) else: processNote(c, it)

View file

@ -380,7 +380,8 @@ proc analyseThreadProc*(prc: PSym) =
var formals = skipTypes(prc.typ, abstractInst).n var formals = skipTypes(prc.typ, abstractInst).n
for i in 1 .. formals.len-1: for i in 1 .. formals.len-1:
var formal = formals.sons[i].sym var formal = formals.sons[i].sym
c.mapping[formal.id] = toTheirs # thread receives foreign data! # the input is copied and belongs to the thread:
c.mapping[formal.id] = toMine
discard analyse(c, prc.getBody) discard analyse(c, prc.getBody)
proc needsGlobalAnalysis*: bool = proc needsGlobalAnalysis*: bool =

View file

@ -60,7 +60,7 @@ type
wPassc, wPassl, wBorrow, wDiscardable, wPassc, wPassl, wBorrow, wDiscardable,
wFieldChecks, wFieldChecks,
wWatchPoint, wSubsChar, wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wNoStackFrame, wNoStackFrame,
wImplicitStatic, wGlobal, wCodegenDecl, wImplicitStatic, wGlobal, wCodegenDecl,
@ -142,7 +142,8 @@ const
"compiletime", "noinit", "compiletime", "noinit",
"passc", "passl", "borrow", "discardable", "fieldchecks", "passc", "passl", "borrow", "discardable", "fieldchecks",
"watchpoint", "watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend", "computedgoto", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
"computedgoto", "injectstmt",
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
"nostackframe", "implicitstatic", "global", "codegendecl", "nostackframe", "implicitstatic", "global", "codegendecl",

View file

@ -5053,6 +5053,18 @@ Note that this pragma is somewhat of a misnomer: Other backends will provide
the same feature under the same name. the same feature under the same name.
Extern pragma
-------------
Like ``exportc`` or ``importc`` the `extern`:idx: pragma affects name
mangling. The string literal passed to ``extern`` can be a format string:
.. code-block:: Nimrod
proc p(s: string) {.extern: "prefix$1".} =
echo s
In the example the external name of ``p`` is set to ``prefixp``.
Bycopy pragma Bycopy pragma
------------- -------------

View file

@ -470,6 +470,19 @@ proc is declared in the generated code:
echo "realistic interrupt handler" echo "realistic interrupt handler"
InjectStmt pragma
-----------------
The `injectStmt`:idx: pragma can be used to inject a statement before every
other statement in the current module. It is only supposed to be used for
debugging:
.. code-block:: nimrod
{.injectStmt: gcInvariants().}
# ... complex code here that produces crashes ...
LineDir option LineDir option
-------------- --------------
The `lineDir`:idx: option can be turned on or off. If turned on the The `lineDir`:idx: option can be turned on or off. If turned on the

View file

@ -760,7 +760,7 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
# ---------------------- thread memory region ------------------------------- # ---------------------- thread memory region -------------------------------
template InstantiateForRegion(allocator: expr) = template InstantiateForRegion(allocator: expr) =
when false: when defined(fulldebug):
proc interiorAllocatedPtr*(p: pointer): pointer = proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p) result = interiorAllocatedPtr(allocator, p)

View file

@ -345,8 +345,9 @@ proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildren(cell: PCell, op: TWalkOp) = proc forAllChildren(cell: PCell, op: TWalkOp) =
gcAssert(cell != nil, "forAllChildren: 1") gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(cell.typ != nil, "forAllChildren: 2") gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3" gcAssert(cell.typ != nil, "forAllChildren: 3")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
let marker = cell.typ.marker let marker = cell.typ.marker
if marker != nil: if marker != nil:
marker(cellToUsr(cell), op.int) marker(cellToUsr(cell), op.int)
@ -361,7 +362,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
for i in 0..s.len-1: for i in 0..s.len-1:
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +% forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
GenericSeqSize), cell.typ.base, op) GenericSeqSize), cell.typ.base, op)
else: nil else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} = proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused. # we check the last 8 entries (cache line) for a slot that could be reused.
@ -408,8 +409,10 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
add(gch.zct, res) add(gch.zct, res)
{.push stackTrace: off, profiler:off.} {.push stackTrace: off, profiler:off.}
proc gcInvariant*(msg: string) = proc gcInvariant*() =
sysAssert(allocInv(gch.region), msg) sysAssert(allocInv(gch.region), "injected")
when defined(markForDebug):
markForDebug(gch)
{.pop.} {.pop.}
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer = proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =

View file

@ -18,7 +18,8 @@ const
logGC = false logGC = false
traceGC = false # extensive debugging traceGC = false # extensive debugging
alwaysCycleGC = false alwaysCycleGC = false
alwaysGC = false # collect after every memory allocation (for debugging) alwaysGC = defined(fulldebug) # collect after every memory
# allocation (for debugging)
leakDetector = false leakDetector = false
overwriteFree = false overwriteFree = false
trackAllocationSource = leakDetector trackAllocationSource = leakDetector