diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 7447dbb6c..faf37247e 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1450,7 +1450,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op) - of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit: + of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mCreateThread: genCall(p, e, d) of mReset: genReset(p, e) of mEcho: genEcho(p, e) diff --git a/compiler/commands.nim b/compiler/commands.nim index 1295a5490..c5a689dfc 100755 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -104,7 +104,7 @@ Advanced options: --genMapping generate a mapping file containing (Nimrod, mangled) identifier pairs --lineDir:on|off generation of #line directive on|off - --checkpoints:on|off turn checkpoints on|off; for debugging Nimrod + --threadanalysis:on|off turn thread analysis on|off --skipCfg do not read the general configuration file --skipProjCfg do not read the project's configuration file --gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC @@ -252,7 +252,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = of wForceBuild, wF: result = contains(gGlobalOptions, optForceFullMake) of wWarnings, wW: result = contains(gOptions, optWarns) of wHints: result = contains(gOptions, optHints) - of wCheckpoints: result = contains(gOptions, optCheckpoints) + of wThreadAnalysis: result = contains(gGlobalOptions, optThreadAnalysis) of wStackTrace: result = contains(gOptions, optStackTrace) of wLineTrace: result = contains(gOptions, optLineTrace) of wDebugger: result = contains(gOptions, optEndb) @@ -367,7 +367,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = of wWarning: ProcessSpecificNote(arg, wWarning, pass, info) of wHint: ProcessSpecificNote(arg, wHint, pass, info) of wHints: ProcessOnOffSwitch({optHints}, arg, pass, info) - of wCheckpoints: ProcessOnOffSwitch({optCheckpoints}, arg, pass, info) + of wThreadAnalysis: ProcessOnOffSwitchG({optThreadAnalysis}, arg, pass, info) of wStackTrace: ProcessOnOffSwitch({optStackTrace}, arg, pass, info) of wLineTrace: ProcessOnOffSwitch({optLineTrace}, arg, pass, info) of wDebugger: diff --git a/compiler/options.nim b/compiler/options.nim index d7025e6f7..662848053 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -25,7 +25,6 @@ type # please make sure we have under 32 options optEndb, # embedded debugger optByRef, # use pass by ref for objects # (for interfacing with C) - optCheckpoints, # check for checkpoints (used for debugging) optProfiler # profiler turned on TOptions* = set[TOption] TGlobalOption* = enum @@ -46,7 +45,9 @@ type # please make sure we have under 32 options optStdout, # output to stdout optSuggest, # ideTools: 'suggest' optContext, # ideTools: 'context' - optDef # ideTools: 'def' + optDef, # ideTools: 'def' + optThreadAnalysis # thread analysis pass + TGlobalOptions* = set[TGlobalOption] TCommands* = enum # Nimrod's commands cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, @@ -71,7 +72,7 @@ var gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, optOverflowCheck, optAssert, optWarns, optHints, optStackTrace, optLineTrace} - gGlobalOptions*: TGlobalOptions = {optRefcGC} + gGlobalOptions*: TGlobalOptions = {optRefcGC, optThreadAnalysis} gExitcode*: int8 searchPaths*: TLinkedList outFile*: string = "" diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 7c78570e2..a450db3a4 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -106,23 +106,23 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = else: result = defaultStr proc processMagic(c: PContext, n: PNode, s: PSym) = - var v: string - #if not (sfSystemModule in c.module.flags) then - # liMessage(n.info, errMagicOnlyInSystem); + #if sfSystemModule notin c.module.flags: + # liMessage(n.info, errMagicOnlyInSystem) if n.kind != nkExprColonExpr: LocalError(n.info, errStringLiteralExpected) return + var v: string if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s else: v = expectStrLit(c, n) - incl(s.flags, sfImportc) - # magics don't need an implementation, so we - # treat them as imported, instead of modifing a lot of working code - # BUGFIX: magic does not imply ``lfNoDecl`` anymore! for m in countup(low(TMagic), high(TMagic)): if substr($m, 1) == v: s.magic = m - return - Message(n.info, warnUnknownMagic, v) + break + if s.magic == mNone: Message(n.info, warnUnknownMagic, v) + elif s.magic != mCreateThread: + # magics don't need an implementation, so we + # treat them as imported, instead of modifing a lot of working code: + incl(s.flags, sfImportc) proc wordToCallConv(sw: TSpecialWord): TCallingConvention = # this assumes that the order of special words and calling conventions is diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 39f3e1f15..5ea8e765b 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -568,7 +568,8 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mEcho: result = semEcho(c, setMs(n, s)) of mCreateThread: result = semDirectOp(c, n, flags) - if optThreads in gGlobalOptions: + if gGlobalOptions * {optThreads, optThreadAnalysis} == + {optThreads, optThreadAnalysis}: # XXX This analysis should be done as late as possible # (forward references!) semthreads.AnalyseThread(result) diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim index 9d78123d6..9f4e62756 100644 --- a/compiler/semthreads.nim +++ b/compiler/semthreads.nim @@ -170,12 +170,23 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner = var formal = skipTypes(prc.typ, abstractInst).n.sons[i].sym newCtx.mapping[formal.id] = call.args[i-1] pushInfoContext(n.info) - computed[call] = analyse(newCtx, prc.ast.sons[codePos]) + result = analyse(newCtx, prc.ast.sons[codePos]) + if prc.typ.sons[0] != nil: + if prc.ast.len > resultPos: + result = newCtx.mapping[prc.ast.sons[resultPos].sym.id] + else: + result = toNil + else: + result = toVoid + computed[call] = result popInfoContext() else: - # ugh, cycle! We are already computing it but don't know the outcome yet... - if prc.typ.sons[0] == nil: result = toVoid - else: result = toNil + result = computed[call] + if result == toUndefined: + # ugh, cycle! We are already computing it but don't know the + # outcome yet... + if prc.typ.sons[0] == nil: result = toVoid + else: result = toNil proc analyseVarTuple(c: PProcCtx, n: PNode) = if n.kind != nkVarTuple: InternalError(n.info, "analyseVarTuple") @@ -210,28 +221,39 @@ template aggregateOwner(result, ana: expr) = if result == toNil: result = a else: localError(n.info, errDifferentHeaps) +proc analyseOp(c: PProcCtx, n: PNode): TThreadOwner = + if n[0].kind != nkSym or n[0].sym.kind != skProc: + Message(n.info, warnAnalysisLoophole, renderTree(n)) + result = toNil + else: + var prc = n[0].sym + # XXX create thread!? + case prc.magic + of mNew, mNewFinalize, mNewSeq, mSetLengthStr, mSetLengthSeq, + mAppendSeqElem, mReset, mAppendStrCh, mAppendStrStr: + writeAccess(c, n[1], toMine) + result = toVoid + of mSwap: + var a = analyse(c, n[2]) + writeAccess(c, n[1], a) + writeAccess(c, n[2], a) + result = toVoid + of mIntToStr, mInt64ToStr, mFloatToStr, mBoolToStr, mCharToStr, + mCStrToStr, mStrToStr, mEnumToStr, + mConStrStr, mConArrArr, mConArrT, + mConTArr, mConTT, mSlice, + mRepr, mArrToSeq, mCopyStr, mCopyStrLast, + mNewString, mNewStringOfCap: + # XXX no check for effects in the arguments? + result = toMine + else: + result = analyseCall(c, n) + proc analyse(c: PProcCtx, n: PNode): TThreadOwner = case n.kind of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit, nkHiddenCallConv: - if n[0].kind != nkSym or n[0].sym.kind != skProc: - Message(n.info, warnAnalysisLoophole, renderTree(n)) - result = toNil - else: - var prc = n[0].sym - # XXX create thread!? - case prc.magic - of mNew, mNewFinalize, mNewSeq, mSetLengthStr, mSetLengthSeq, - mAppendSeqElem, mReset, mAppendStrCh, mAppendStrStr: - writeAccess(c, n[1], toMine) - result = toVoid - of mSwap: - var a = analyse(c, n[2]) - writeAccess(c, n[1], a) - writeAccess(c, n[2], a) - result = toVoid - else: - result = analyseCall(c, n) + result = analyseOp(c, n) of nkAsgn, nkFastAsgn: analyseAssign(c, n) result = toVoid @@ -290,7 +312,8 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner = of nkVarSection: result = analyseVarSection(c, n) of nkConstSection: result = analyseConstSection(c, n) of nkTypeSection, nkCommentStmt: result = toVoid - of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt: + of nkIfStmt, nkWhileStmt, nkTryStmt, nkCaseStmt, nkStmtList, nkBlockStmt, + nkElifBranch, nkElse, nkExceptBranch, nkOfBranch: for i in 0 .. t.data[maxIdx].val: maxIdx = j swap(t.data[maxIdx], t.data[i])