further improvements for thread analysis

This commit is contained in:
Araq 2011-06-13 20:57:49 +02:00
commit ca637c019c
7 changed files with 36 additions and 17 deletions

View file

@ -13,7 +13,7 @@
import import
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread nimsets, syntaxes, times, rodread, semthreads
type type
TPassContext* = object of TObject # the pass's context TPassContext* = object of TObject # the pass's context
@ -60,7 +60,7 @@ proc astNeeded*(s: PSym): bool =
({sfCompilerProc, sfCompileTime} * s.flags == {}) and ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
(s.typ.callConv != ccInline) and (s.typ.callConv != ccInline) and
(s.ast.sons[genericParamsPos].kind == nkEmpty): (s.ast.sons[genericParamsPos].kind == nkEmpty):
result = false result = semthreads.needsGlobalAnalysis()
else: else:
result = true result = true

View file

@ -199,6 +199,10 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
RecoverContext(c) RecoverContext(c)
result = ast.emptyNode result = ast.emptyNode
proc checkThreads(c: PContext) =
for i in 0 .. c.threadEntries.len-1:
semthreads.AnalyseThread(c.threadEntries[i])
proc myClose(context: PPassContext, n: PNode): PNode = proc myClose(context: PPassContext, n: PNode): PNode =
var c = PContext(context) var c = PContext(context)
closeScope(c.tab) # close module's scope closeScope(c.tab) # close module's scope
@ -208,6 +212,7 @@ proc myClose(context: PPassContext, n: PNode): PNode =
else: else:
InternalError(n.info, "n is not nil") #result := n; InternalError(n.info, "n is not nil") #result := n;
addCodeForGenerics(c, result) addCodeForGenerics(c, result)
checkThreads(c)
popOwner() popOwner()
popProcCon(c) popProcCon(c)

View file

@ -40,6 +40,7 @@ type
generics*: PNode # a list of the things to compile; list of generics*: PNode # a list of the things to compile; list of
# nkExprEqExpr nodes which contain the # nkExprEqExpr nodes which contain the
# generic symbol and the instantiated symbol # generic symbol and the instantiated symbol
threadEntries*: PNode # list of thread entries to check
lastGenericIdx*: int # used for the generics stack lastGenericIdx*: int # used for the generics stack
tab*: TSymTab # each module has its own symbol table tab*: TSymTab # each module has its own symbol table
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
@ -123,6 +124,7 @@ proc newContext(module: PSym, nimfile: string): PContext =
append(result.optionStack, newOptionEntry()) append(result.optionStack, newOptionEntry())
result.module = module result.module = module
result.generics = newNode(nkStmtList) result.generics = newNode(nkStmtList)
result.threadEntries = newNode(nkStmtList)
result.converters = @[] result.converters = @[]
result.filename = nimfile result.filename = nimfile
IntSetInit(result.includedFiles) IntSetInit(result.includedFiles)

View file

@ -568,11 +568,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mEcho: result = semEcho(c, setMs(n, s)) of mEcho: result = semEcho(c, setMs(n, s))
of mCreateThread: of mCreateThread:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
if gGlobalOptions * {optThreads, optThreadAnalysis} == if semthreads.needsGlobalAnalysis():
{optThreads, optThreadAnalysis}: c.threadEntries.add(result)
# XXX This analysis should be done as late as possible
# (forward references!)
semthreads.AnalyseThread(result)
else: result = semDirectOp(c, n, flags) else: result = semDirectOp(c, n, flags)
proc isTypeExpr(n: PNode): bool = proc isTypeExpr(n: PNode): bool =

View file

@ -171,6 +171,8 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner =
newCtx.mapping[formal.id] = call.args[i-1] newCtx.mapping[formal.id] = call.args[i-1]
pushInfoContext(n.info) pushInfoContext(n.info)
result = analyse(newCtx, prc.ast.sons[codePos]) result = analyse(newCtx, prc.ast.sons[codePos])
if prc.ast.sons[codePos].kind == nkEmpty:
Message(n.info, warnAnalysisLoophole, renderTree(n))
if prc.typ.sons[0] != nil: if prc.typ.sons[0] != nil:
if prc.ast.len > resultPos: if prc.ast.len > resultPos:
result = newCtx.mapping[prc.ast.sons[resultPos].sym.id] result = newCtx.mapping[prc.ast.sons[resultPos].sym.id]
@ -221,14 +223,17 @@ template aggregateOwner(result, ana: expr) =
if result == toNil: result = a if result == toNil: result = a
else: localError(n.info, errDifferentHeaps) else: localError(n.info, errDifferentHeaps)
proc analyseArgs(c: PProcCtx, n: PNode, start = 1) =
for i in start..n.len-1: discard analyse(c, n[i])
proc analyseOp(c: PProcCtx, n: PNode): TThreadOwner = proc analyseOp(c: PProcCtx, n: PNode): TThreadOwner =
if n[0].kind != nkSym or n[0].sym.kind != skProc: if n[0].kind != nkSym or n[0].sym.kind != skProc:
Message(n.info, warnAnalysisLoophole, renderTree(n)) Message(n.info, warnAnalysisLoophole, renderTree(n))
result = toNil result = toNil
else: else:
var prc = n[0].sym var prc = n[0].sym
# XXX create thread!?
case prc.magic case prc.magic
of mNone: result = analyseCall(c, n)
of mNew, mNewFinalize, mNewSeq, mSetLengthStr, mSetLengthSeq, of mNew, mNewFinalize, mNewSeq, mSetLengthStr, mSetLengthSeq,
mAppendSeqElem, mReset, mAppendStrCh, mAppendStrStr: mAppendSeqElem, mReset, mAppendStrCh, mAppendStrStr:
writeAccess(c, n[1], toMine) writeAccess(c, n[1], toMine)
@ -244,10 +249,14 @@ proc analyseOp(c: PProcCtx, n: PNode): TThreadOwner =
mConTArr, mConTT, mSlice, mConTArr, mConTT, mSlice,
mRepr, mArrToSeq, mCopyStr, mCopyStrLast, mRepr, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mNewStringOfCap: mNewString, mNewStringOfCap:
# XXX no check for effects in the arguments? analyseArgs(c, n)
result = toMine result = toMine
else: else:
result = analyseCall(c, n) # don't recurse, but check args; NOTE: This is essential that
# ``mCreateThread`` is handled here to avoid the recursion
analyseArgs(c, n)
if prc.typ.sons[0] == nil: result = toVoid
else: result = toNil
proc analyse(c: PProcCtx, n: PNode): TThreadOwner = proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
case n.kind case n.kind
@ -325,8 +334,7 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
result = toVoid result = toVoid
else: InternalError(n.info, "analysis not implemented for: " & $n.kind) else: InternalError(n.info, "analysis not implemented for: " & $n.kind)
proc AnalyseThread*(threadCreation: PNode) = proc analyseThreadCreationCall(n: PNode) =
var n = threadCreation
# thread proc is second param of ``createThread``: # thread proc is second param of ``createThread``:
if n[2].kind != nkSym or n[2].sym.kind != skProc: if n[2].kind != nkSym or n[2].sym.kind != skProc:
Message(n.info, warnAnalysisLoophole, renderTree(n)) Message(n.info, warnAnalysisLoophole, renderTree(n))
@ -337,3 +345,11 @@ proc AnalyseThread*(threadCreation: PNode) =
c.mapping[formal.id] = toTheirs # thread receives foreign data! c.mapping[formal.id] = toTheirs # thread receives foreign data!
discard analyse(c, prc.ast.sons[codePos]) discard analyse(c, prc.ast.sons[codePos])
proc needsGlobalAnalysis*: bool =
result = gGlobalOptions * {optThreads, optThreadAnalysis} ==
{optThreads, optThreadAnalysis}
proc AnalyseThread*(threadCreation: PNode) =
if needsGlobalAnalysis():
analyseThreadCreationCall(threadCreation)

View file

@ -1,7 +1,8 @@
discard """ discard """
file: "tthreadanalysis2.nim" file: "tthreadanalysis2.nim"
line: 44 line: 45
errormsg: "possible inconsistency of thread local heaps" errormsg: "possible inconsistency of thread local heaps"
cmd: "nimrod cc --hints:on --threads:on $# $#"
""" """
import os import os

View file

@ -1,6 +1,4 @@
* codegen for threadvars * codegen for threadvars
* clean up thread analysis: fix remaining XXX; thread analysis as a separate
pass
* implement message passing built-ins * implement message passing built-ins
* add --deadlock_prevention:on|off switch? timeout for locks? * add --deadlock_prevention:on|off switch? timeout for locks?