diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 69c06fbb58..dc17a39c75 100755 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -154,29 +154,25 @@ proc getStorageLoc(n: PNode): TStorageLoc = else: result = OnUnknown proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = - if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions): + if dest.s == OnStack or optRefcGC notin gGlobalOptions: appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) elif dest.s == OnHeap: # location is on heap # now the writer barrier is inlined for performance: # - # if afSrcIsNotNil in flags then begin - # UseMagic(p.module, 'nimGCref'); - # appf(p.s[cpsStmts], 'nimGCref($1);$n', [rdLoc(src)]); - # end - # else if not (afSrcIsNil in flags) then begin - # UseMagic(p.module, 'nimGCref'); - # appf(p.s[cpsStmts], 'if ($1) nimGCref($1);$n', [rdLoc(src)]); - # end; - # if afDestIsNotNil in flags then begin - # UseMagic(p.module, 'nimGCunref'); - # appf(p.s[cpsStmts], 'nimGCunref($1);$n', [rdLoc(dest)]); - # end - # else if not (afDestIsNil in flags) then begin - # UseMagic(p.module, 'nimGCunref'); - # appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]); - # end; - # appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]); + # if afSrcIsNotNil in flags: + # UseMagic(p.module, 'nimGCref') + # appf(p.s[cpsStmts], 'nimGCref($1);$n', [rdLoc(src)]) + # elif afSrcIsNil notin flags: + # UseMagic(p.module, 'nimGCref') + # appf(p.s[cpsStmts], 'if ($1) nimGCref($1);$n', [rdLoc(src)]) + # if afDestIsNotNil in flags: + # UseMagic(p.module, 'nimGCunref') + # appf(p.s[cpsStmts], 'nimGCunref($1);$n', [rdLoc(dest)]) + # elif afDestIsNil notin flags: + # UseMagic(p.module, 'nimGCunref') + # appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) + # appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) if canFormAcycle(dest.t): appcg(p.module, p.s[cpsStmts], "#asgnRef((void**) $1, $2);$n", [addrLoc(dest), rdLoc(src)]) @@ -196,7 +192,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # (for objects, etc.): if needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: - if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions): + if dest.s == OnStack or optRefcGC notin gGlobalOptions: appcg(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", [addrLoc(dest), addrLoc(src), rdLoc(dest)]) @@ -224,7 +220,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if needToCopy notin flags: genRefAssign(p, dest, src, flags) else: - if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions): + if dest.s == OnStack or optRefcGC notin gGlobalOptions: appcg(p, cpsStmts, "$1 = #copyString($2);$n", [rdLoc(dest), rdLoc(src)]) elif dest.s == OnHeap: appcg(p, cpsStmts, "#asgnRefNoCycle((void**) $1, #copyString($2));$n", @@ -826,19 +822,7 @@ proc genCall(p: BProc, t: PNode, d: var TLoc) = app(pl, ")") app(p.s[cpsStmts], pl) app(p.s[cpsStmts], ';' & tnl) - - when false: - app(pl, ")") - if (typ.sons[0] != nil) and not invalidRetType: - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - initLoc(list, locCall, nil, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying - else: - app(p.s[cpsStmts], pl) - app(p.s[cpsStmts], ';' & tnl) - + proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # # s = 'Hello ' & name & ', how do you feel?' & 'z' diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 1816c0f314..c9b5832fb1 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -7,13 +7,11 @@ # distribution, for details about the copyright. # -const +const RangeExpandLimit = 256 # do not generate ranges # over 'RangeExpandLimit' elements stringCaseThreshold = 8 # above X strings a hash-switch for strings is generated - # this version sets it too high to avoid hashing, because this has not - # been tested for a long time proc genLineDir(p: BProc, t: PNode) = var line = toLinenumber(t.info) # BUGFIX @@ -23,11 +21,11 @@ proc genLineDir(p: BProc, t: PNode) = appff(p.s[cpsStmts], "#line $2 \"$1\"$n", "; line $2 \"$1\"$n", [toRope(toFilename(t.info)), toRope(line)]) if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and - ((p.prc == nil) or not (sfPure in p.prc.flags)): + (p.prc == nil or sfPure notin p.prc.flags): appcg(p, cpsStmts, "#endb($1);$n", [toRope(line)]) elif ({optLineTrace, optStackTrace} * p.Options == {optLineTrace, optStackTrace}) and - ((p.prc == nil) or not (sfPure in p.prc.flags)): + (p.prc == nil or sfPure notin p.prc.flags): appf(p.s[cpsStmts], "F.line = $1;F.filename = $2;$n", [toRope(line), makeCString(toFilename(t.info).extractFilename)]) @@ -458,7 +456,7 @@ proc genTryStmtCpp(p: BProc, t: PNode) = rethrowFlag = getTempName() appf(p.s[cpsLocals], "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag]) if optStackTrace in p.Options: - appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl) + appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") app(p.s[cpsStmts], "try {" & tnl) add(p.nestedTryStmts, t) genStmts(p, t.sons[0]) @@ -493,6 +491,72 @@ proc genTryStmtCpp(p: BProc, t: PNode) = if rethrowFlag != nil: appf(p.s[cpsStmts], "if ($1) { throw; }$n", [rethrowFlag]) +proc genTryStmtCpp2(p: BProc, t: PNode) = + # code to generate: + # + # TSafePoint sp; + # pushSafePoint(&sp); + # sp.status = setjmp(sp.context); + # if (sp.status == 0) { + # myDiv(4, 9); + # popSafePoint(); + # } else { + # popSafePoint(); + # /* except DivisionByZero: */ + # if (sp.status == DivisionByZero) { + # printf('Division by Zero\n'); + # clearException(); + # } else { + # clearException(); + # } + # } + # /* finally: */ + # printf('fin!\n'); + # if (exception not cleared) + # propagateCurrentException(); + genLineDir(p, t) + var safePoint = getTempName() + discard cgsym(p.module, "E_Base") + appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) + appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" & + "$1.status = setjmp($1.context);$n", [safePoint]) + if optStackTrace in p.Options: + appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") + appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint]) + var length = sonsLen(t) + add(p.nestedTryStmts, t) + genStmts(p, t.sons[0]) + appcg(p, cpsStmts, "#popSafePoint();$n} else {$n#popSafePoint();$n") + var i = 1 + while (i < length) and (t.sons[i].kind == nkExceptBranch): + var blen = sonsLen(t.sons[i]) + if blen == 1: + # general except section: + if i > 1: app(p.s[cpsStmts], "else {" & tnl) + genStmts(p, t.sons[i].sons[0]) + appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();$n", [safePoint]) + if i > 1: app(p.s[cpsStmts], '}' & tnl) + else: + var orExpr: PRope = nil + for j in countup(0, blen - 2): + assert(t.sons[i].sons[j].kind == nkType) + if orExpr != nil: app(orExpr, "||") + appcg(p.module, orExpr, + "#isObj(#getCurrentException()->Sup.m_type, $1)", + [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) + if i > 1: app(p.s[cpsStmts], "else ") + appf(p.s[cpsStmts], "if ($1) {$n", [orExpr]) + genStmts(p, t.sons[i].sons[blen-1]) + # code to clear the exception: + appcg(p, cpsStmts, "$1.status = 0;#popCurrentException();}$n", + [safePoint]) + inc(i) + app(p.s[cpsStmts], '}' & tnl) # end of if statement + discard pop(p.nestedTryStmts) + if i < length and t.sons[i].kind == nkFinally: + genStmts(p, t.sons[i].sons[0]) + appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) + proc genTryStmt(p: BProc, t: PNode) = # code to generate: # @@ -523,7 +587,7 @@ proc genTryStmt(p: BProc, t: PNode) = appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" & "$1.status = setjmp($1.context);$n", [safePoint]) if optStackTrace in p.Options: - appcg(p, cpsStmts, "#framePtr = (TFrame*)&F;" & tnl) + appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n") appf(p.s[cpsStmts], "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) add(p.nestedTryStmts, t) @@ -543,8 +607,9 @@ proc genTryStmt(p: BProc, t: PNode) = for j in countup(0, blen - 2): assert(t.sons[i].sons[j].kind == nkType) if orExpr != nil: app(orExpr, "||") - appcg(p.module, orExpr, "#getCurrentException()->Sup.m_type == $1", - [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) + appcg(p.module, orExpr, + "#isObj(#getCurrentException()->Sup.m_type, $1)", + [genTypeInfo(p.module, t.sons[i].sons[j].typ)]) if i > 1: app(p.s[cpsStmts], "else ") appf(p.s[cpsStmts], "if ($1) {$n", [orExpr]) genStmts(p, t.sons[i].sons[blen-1]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 61cd36c42d..7f162b6e6c 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -84,6 +84,7 @@ type module*: PSym filename*: string s*: TCFileSections # sections of the C file + PreventStackTrace: bool # true if stack traces need to be prevented cfilename*: string # filename of the module (including path, # without extension) typeCache*: TIdTable # cache the generated types @@ -99,7 +100,6 @@ type typeNodes*, nimTypes*: int # used for type info generation typeNodesName*, nimTypesName*: PRope # used for type info generation labels*: natural # for generating unique module-scope names - var mainModProcs, mainModInit: PRope # parts of the main module @@ -603,19 +603,12 @@ proc retIsNotVoid(s: PSym): bool = proc initFrame(p: BProc, procname, filename: PRope): PRope = result = ropecg(p.module, "F.procname = $1;$n" & - "F.prev = #framePtr;$n" & "F.filename = $2;$n" & "F.line = 0;$n" & - "framePtr = (TFrame*)&F;$n", [procname, filename]) + "#pushFrame((TFrame*)&F);$n", [procname, filename]) -proc deinitFrame(p: BProc): PRope = - inc(p.labels, 3) - result = ropeff("framePtr = framePtr->prev;$n", - "%LOC$1 = load %TFrame* @framePtr$n" & - "%LOC$2 = getelementptr %TFrame* %LOC$1, %NI 0$n" & - "%LOC$3 = load %TFrame** %LOC$2$n" & - "store %TFrame* $LOC$3, %TFrame** @framePtr", [toRope(p.labels), - toRope(p.labels - 1), toRope(p.labels - 2)]) +proc deinitFrame(p: BProc): PRope = + result = ropecg(p.module, "#popFrame();$n") proc genProcAux(m: BModule, prc: PSym) = var @@ -628,7 +621,7 @@ proc genProcAux(m: BModule, prc: PSym) = header = con("N_LIB_EXPORT ", header) returnStmt = nil assert(prc.ast != nil) - if not (sfPure in prc.flags) and (prc.typ.sons[0] != nil): + if sfPure notin prc.flags and prc.typ.sons[0] != nil: res = prc.ast.sons[resultPos].sym # get result symbol if not isInvalidReturnType(prc.typ.sons[0]): # declare the result symbol: @@ -868,14 +861,17 @@ proc genInitCode(m: BModule) = if m.nimTypes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", [m.nimTypesName, toRope(m.nimTypes)]) - if optStackTrace in m.initProc.options: + if optStackTrace in m.initProc.options: + # BUT: the generated init code might depend on a current frame, so + # declare it nevertheless: getFrameDecl(m.initProc) + if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, m.initProc.s[cpsLocals]) app(prc, m.s[cfsTypeInit1]) procname = CStringLit(m.initProc, prc, m.module.name.s) filename = CStringLit(m.initProc, prc, toFilename(m.module.info)) app(prc, initFrame(m.initProc, procname, filename)) - else: + else: app(prc, m.initProc.s[cpsLocals]) app(prc, m.s[cfsTypeInit1]) app(prc, m.s[cfsTypeInit2]) @@ -884,7 +880,8 @@ proc genInitCode(m: BModule) = app(prc, m.s[cfsDynLibInit]) app(prc, m.initProc.s[cpsInit]) app(prc, m.initProc.s[cpsStmts]) - if optStackTrace in m.initProc.options: app(prc, deinitFrame(m.initProc)) + if optStackTrace in m.initProc.options and not m.PreventStackTrace: + app(prc, deinitFrame(m.initProc)) app(prc, '}' & tnl & tnl) app(m.s[cfsProcs], prc) @@ -911,6 +908,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = result.forwardedProcs = @[] result.typeNodesName = getTempName() result.nimTypesName = getTempName() + result.PreventStackTrace = sfSystemModule in module.flags proc newModule(module: PSym, filename: string): BModule = result = rawNewModule(module, filename) @@ -923,6 +921,7 @@ proc registerTypeInfoModule() = const moduleName = "nim__dat" var s = NewSym(skModule, getIdent(moduleName), nil) gNimDat = rawNewModule(s, joinPath(options.projectPath, moduleName) & ".nim") + gNimDat.PreventStackTrace = true addPendingModule(gNimDat) appff(mainModProcs, "N_NOINLINE(void, $1)(void);$n", "declare void $1() noinline$n", [getInitName(s)]) @@ -935,7 +934,6 @@ proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext = if gNimDat == nil: registerTypeInfoModule() - #MessageOut('cgen.myOpenCached has been called ' + filename) var cfile = changeFileExt(completeCFilePath(filename), cExt) var cfilenoext = changeFileExt(cfile, "") addFileToLink(cfilenoext) diff --git a/compiler/commands.nim b/compiler/commands.nim index a4763d6b26..1295a5490d 100755 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -513,7 +513,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) = else: InvalidCmdLineOption(pass, switch, info) proc ProcessCommand(switch: string, pass: TCmdLinePass) = - var + var cmd, arg: string info: TLineInfo info = newLineInfo("command line", 1, 1) diff --git a/install.sh b/install.sh index eed9f33e55..4cc4c944c9 100755 --- a/install.sh +++ b/install.sh @@ -63,15 +63,6 @@ if [ $# -eq 1 ] ; then mkdir -p $libdir/wrappers/sdl || exit 1 mkdir -p $libdir/wrappers/x11 || exit 1 mkdir -p $libdir/wrappers/zip || exit 1 - mkdir -p $libdir/oldwrappers || exit 1 - mkdir -p $libdir/oldwrappers/cairo || exit 1 - mkdir -p $libdir/oldwrappers/gtk || exit 1 - mkdir -p $libdir/oldwrappers/lua || exit 1 - mkdir -p $libdir/oldwrappers/opengl || exit 1 - mkdir -p $libdir/oldwrappers/pcre || exit 1 - mkdir -p $libdir/oldwrappers/sdl || exit 1 - mkdir -p $libdir/oldwrappers/x11 || exit 1 - mkdir -p $libdir/oldwrappers/zip || exit 1 mkdir -p $libdir/windows || exit 1 mkdir -p $libdir/posix || exit 1 mkdir -p $libdir/ecmas || exit 1 @@ -140,8 +131,6 @@ if [ $# -eq 1 ] ; then chmod 644 $docdir/tut1.txt cp doc/tut2.txt $docdir/tut2.txt || exit 1 chmod 644 $docdir/tut2.txt - cp doc/manual.html $docdir/manual.html || exit 1 - chmod 644 $docdir/manual.html cp doc/mytest.cfg $docdir/mytest.cfg || exit 1 chmod 644 $docdir/mytest.cfg cp doc/c2nim.pdf $docdir/c2nim.pdf || exit 1 @@ -470,136 +459,6 @@ if [ $# -eq 1 ] ; then chmod 644 $libdir/wrappers/zip/zzip.nim cp lib/wrappers/zip/libzip_all.c $libdir/wrappers/zip/libzip_all.c || exit 1 chmod 644 $libdir/wrappers/zip/libzip_all.c - cp lib/oldwrappers/iup.nim $libdir/oldwrappers/iup.nim || exit 1 - chmod 644 $libdir/oldwrappers/iup.nim - cp lib/oldwrappers/libcurl.nim $libdir/oldwrappers/libcurl.nim || exit 1 - chmod 644 $libdir/oldwrappers/libcurl.nim - cp lib/oldwrappers/mysql.nim $libdir/oldwrappers/mysql.nim || exit 1 - chmod 644 $libdir/oldwrappers/mysql.nim - cp lib/oldwrappers/odbcsql.nim $libdir/oldwrappers/odbcsql.nim || exit 1 - chmod 644 $libdir/oldwrappers/odbcsql.nim - cp lib/oldwrappers/postgres.nim $libdir/oldwrappers/postgres.nim || exit 1 - chmod 644 $libdir/oldwrappers/postgres.nim - cp lib/oldwrappers/python.nim $libdir/oldwrappers/python.nim || exit 1 - chmod 644 $libdir/oldwrappers/python.nim - cp lib/oldwrappers/sqlite3.nim $libdir/oldwrappers/sqlite3.nim || exit 1 - chmod 644 $libdir/oldwrappers/sqlite3.nim - cp lib/oldwrappers/tcl.nim $libdir/oldwrappers/tcl.nim || exit 1 - chmod 644 $libdir/oldwrappers/tcl.nim - cp lib/oldwrappers/cairo/cairo.nim $libdir/oldwrappers/cairo/cairo.nim || exit 1 - chmod 644 $libdir/oldwrappers/cairo/cairo.nim - cp lib/oldwrappers/cairo/cairoft.nim $libdir/oldwrappers/cairo/cairoft.nim || exit 1 - chmod 644 $libdir/oldwrappers/cairo/cairoft.nim - cp lib/oldwrappers/cairo/cairowin32.nim $libdir/oldwrappers/cairo/cairowin32.nim || exit 1 - chmod 644 $libdir/oldwrappers/cairo/cairowin32.nim - cp lib/oldwrappers/cairo/cairoxlib.nim $libdir/oldwrappers/cairo/cairoxlib.nim || exit 1 - chmod 644 $libdir/oldwrappers/cairo/cairoxlib.nim - cp lib/oldwrappers/gtk/atk.nim $libdir/oldwrappers/gtk/atk.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/atk.nim - cp lib/oldwrappers/gtk/gdk2.nim $libdir/oldwrappers/gtk/gdk2.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gdk2.nim - cp lib/oldwrappers/gtk/gdk2pixbuf.nim $libdir/oldwrappers/gtk/gdk2pixbuf.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gdk2pixbuf.nim - cp lib/oldwrappers/gtk/gdkglext.nim $libdir/oldwrappers/gtk/gdkglext.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gdkglext.nim - cp lib/oldwrappers/gtk/glib2.nim $libdir/oldwrappers/gtk/glib2.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/glib2.nim - cp lib/oldwrappers/gtk/gtk2.nim $libdir/oldwrappers/gtk/gtk2.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gtk2.nim - cp lib/oldwrappers/gtk/gtkglext.nim $libdir/oldwrappers/gtk/gtkglext.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gtkglext.nim - cp lib/oldwrappers/gtk/gtkhtml.nim $libdir/oldwrappers/gtk/gtkhtml.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/gtkhtml.nim - cp lib/oldwrappers/gtk/libglade2.nim $libdir/oldwrappers/gtk/libglade2.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/libglade2.nim - cp lib/oldwrappers/gtk/pango.nim $libdir/oldwrappers/gtk/pango.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/pango.nim - cp lib/oldwrappers/gtk/pangoutils.nim $libdir/oldwrappers/gtk/pangoutils.nim || exit 1 - chmod 644 $libdir/oldwrappers/gtk/pangoutils.nim - cp lib/oldwrappers/lua/lauxlib.nim $libdir/oldwrappers/lua/lauxlib.nim || exit 1 - chmod 644 $libdir/oldwrappers/lua/lauxlib.nim - cp lib/oldwrappers/lua/lua.nim $libdir/oldwrappers/lua/lua.nim || exit 1 - chmod 644 $libdir/oldwrappers/lua/lua.nim - cp lib/oldwrappers/lua/lualib.nim $libdir/oldwrappers/lua/lualib.nim || exit 1 - chmod 644 $libdir/oldwrappers/lua/lualib.nim - cp lib/oldwrappers/opengl/gl.nim $libdir/oldwrappers/opengl/gl.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/gl.nim - cp lib/oldwrappers/opengl/glext.nim $libdir/oldwrappers/opengl/glext.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/glext.nim - cp lib/oldwrappers/opengl/glu.nim $libdir/oldwrappers/opengl/glu.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/glu.nim - cp lib/oldwrappers/opengl/glut.nim $libdir/oldwrappers/opengl/glut.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/glut.nim - cp lib/oldwrappers/opengl/glx.nim $libdir/oldwrappers/opengl/glx.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/glx.nim - cp lib/oldwrappers/opengl/wingl.nim $libdir/oldwrappers/opengl/wingl.nim || exit 1 - chmod 644 $libdir/oldwrappers/opengl/wingl.nim - cp lib/oldwrappers/pcre/pcre.nim $libdir/oldwrappers/pcre/pcre.nim || exit 1 - chmod 644 $libdir/oldwrappers/pcre/pcre.nim - cp lib/oldwrappers/pcre/pcre_all.c $libdir/oldwrappers/pcre/pcre_all.c || exit 1 - chmod 644 $libdir/oldwrappers/pcre/pcre_all.c - cp lib/oldwrappers/sdl/sdl.nim $libdir/oldwrappers/sdl/sdl.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl.nim - cp lib/oldwrappers/sdl/sdl_gfx.nim $libdir/oldwrappers/sdl/sdl_gfx.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_gfx.nim - cp lib/oldwrappers/sdl/sdl_image.nim $libdir/oldwrappers/sdl/sdl_image.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_image.nim - cp lib/oldwrappers/sdl/sdl_mixer.nim $libdir/oldwrappers/sdl/sdl_mixer.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_mixer.nim - cp lib/oldwrappers/sdl/sdl_mixer_nosmpeg.nim $libdir/oldwrappers/sdl/sdl_mixer_nosmpeg.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_mixer_nosmpeg.nim - cp lib/oldwrappers/sdl/sdl_net.nim $libdir/oldwrappers/sdl/sdl_net.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_net.nim - cp lib/oldwrappers/sdl/sdl_ttf.nim $libdir/oldwrappers/sdl/sdl_ttf.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/sdl_ttf.nim - cp lib/oldwrappers/sdl/smpeg.nim $libdir/oldwrappers/sdl/smpeg.nim || exit 1 - chmod 644 $libdir/oldwrappers/sdl/smpeg.nim - cp lib/oldwrappers/x11/cursorfont.nim $libdir/oldwrappers/x11/cursorfont.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/cursorfont.nim - cp lib/oldwrappers/x11/keysym.nim $libdir/oldwrappers/x11/keysym.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/keysym.nim - cp lib/oldwrappers/x11/x.nim $libdir/oldwrappers/x11/x.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/x.nim - cp lib/oldwrappers/x11/xatom.nim $libdir/oldwrappers/x11/xatom.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xatom.nim - cp lib/oldwrappers/x11/xcms.nim $libdir/oldwrappers/x11/xcms.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xcms.nim - cp lib/oldwrappers/x11/xf86dga.nim $libdir/oldwrappers/x11/xf86dga.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xf86dga.nim - cp lib/oldwrappers/x11/xf86vmode.nim $libdir/oldwrappers/x11/xf86vmode.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xf86vmode.nim - cp lib/oldwrappers/x11/xi.nim $libdir/oldwrappers/x11/xi.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xi.nim - cp lib/oldwrappers/x11/xinerama.nim $libdir/oldwrappers/x11/xinerama.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xinerama.nim - cp lib/oldwrappers/x11/xkb.nim $libdir/oldwrappers/x11/xkb.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xkb.nim - cp lib/oldwrappers/x11/xkblib.nim $libdir/oldwrappers/x11/xkblib.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xkblib.nim - cp lib/oldwrappers/x11/xlib.nim $libdir/oldwrappers/x11/xlib.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xlib.nim - cp lib/oldwrappers/x11/xrandr.nim $libdir/oldwrappers/x11/xrandr.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xrandr.nim - cp lib/oldwrappers/x11/xrender.nim $libdir/oldwrappers/x11/xrender.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xrender.nim - cp lib/oldwrappers/x11/xresource.nim $libdir/oldwrappers/x11/xresource.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xresource.nim - cp lib/oldwrappers/x11/xshm.nim $libdir/oldwrappers/x11/xshm.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xshm.nim - cp lib/oldwrappers/x11/xutil.nim $libdir/oldwrappers/x11/xutil.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xutil.nim - cp lib/oldwrappers/x11/xv.nim $libdir/oldwrappers/x11/xv.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xv.nim - cp lib/oldwrappers/x11/xvlib.nim $libdir/oldwrappers/x11/xvlib.nim || exit 1 - chmod 644 $libdir/oldwrappers/x11/xvlib.nim - cp lib/oldwrappers/zip/libzip.nim $libdir/oldwrappers/zip/libzip.nim || exit 1 - chmod 644 $libdir/oldwrappers/zip/libzip.nim - cp lib/oldwrappers/zip/zlib.nim $libdir/oldwrappers/zip/zlib.nim || exit 1 - chmod 644 $libdir/oldwrappers/zip/zlib.nim - cp lib/oldwrappers/zip/zzip.nim $libdir/oldwrappers/zip/zzip.nim || exit 1 - chmod 644 $libdir/oldwrappers/zip/zzip.nim - cp lib/oldwrappers/zip/libzip_all.c $libdir/oldwrappers/zip/libzip_all.c || exit 1 - chmod 644 $libdir/oldwrappers/zip/libzip_all.c cp lib/windows/mmsystem.nim $libdir/windows/mmsystem.nim || exit 1 chmod 644 $libdir/windows/mmsystem.nim cp lib/windows/nb30.nim $libdir/windows/nb30.nim || exit 1 diff --git a/lib/core/threads.nim b/lib/core/threads.nim index a1c16fc85c..4e13d66de6 100755 --- a/lib/core/threads.nim +++ b/lib/core/threads.nim @@ -143,8 +143,6 @@ else: var c = cast[ptr TThreadProcClosure[TParam]](closure) c.fn(c.data) - {.passL: "-pthread".} - {.passC: "-pthread".} const noDeadlocks = true # compileOption("deadlockPrevention") @@ -285,6 +283,7 @@ proc createThread*[TParam](t: var TThread[TParam], ## proc `tp`. `param` is passed to `tp`. t.c.data = param t.c.fn = tp + CreateThreadLocalStorage() when hostOS == "windows": var dummyThreadId: int32 t.sys = CreateThread(nil, 0'i32, threadProcWrapper[TParam], diff --git a/lib/nimbase.h b/lib/nimbase.h index ab03b97fa7..fc527e0d03 100755 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -400,15 +400,6 @@ static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff}; # define INF (1.0 / 0.0) # endif #endif -/* -typedef struct TSafePoint TSafePoint; -struct TSafePoint { - NI exc; - NCSTRING excname; - NCSTRING msg; - TSafePoint* prev; - jmp_buf context; -}; */ typedef struct TFrame TFrame; struct TFrame { @@ -419,25 +410,8 @@ struct TFrame { NI len; }; -/* -extern TFrame* framePtr; -extern TSafePoint* excHandler; */ - -#if defined(__cplusplus) -struct NimException { - TSafePoint sp; - - NimException(NI aExc, NCSTRING aExcname, NCSTRING aMsg) { - sp.exc = aExc; sp.excname = aExcname; sp.msg = aMsg; - sp.prev = excHandler; - excHandler = &sp; - } -}; -#endif - #define NIM_POSIX_INIT __attribute__((constructor)) - #if defined(_MSCVER) && defined(__i386__) __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) { __asm { diff --git a/lib/system.nim b/lib/system.nim index 21da9d6ff4..1fd17210f6 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -44,10 +44,6 @@ type typeDesc* {.magic: TypeDesc.} ## meta type to denote ## a type description (for templates) -const - hasThreadSupport = false # deactivate for now: thread stack walking - # is missing! - proc defined*[T](x: T): bool {.magic: "Defined", noSideEffect.} ## Special compile-time procedure that checks whether `x` is ## defined. `x` has to be an identifier or a qualified identifier. @@ -779,7 +775,10 @@ proc compileOption*(option, arg: string): bool {. ## .. code-block:: nimrod ## when compileOption("opt", "size") and compileOption("gc", "boehm"): ## echo "compiled with optimization for size and uses Boehm's GC" - + +const + hasThreadSupport = compileOption("threads") + include "system/inclrtl" when not defined(ecmascript) and not defined(nimrodVm): @@ -1391,19 +1390,20 @@ type filename: CString len: int # length of slots (when not debugging always zero) -var - framePtr {.threadvar, compilerproc.}: PFrame +when defined(ecmaScript): + var + framePtr {.compilerproc.}: PFrame when not defined(ECMAScript): - {.push overflow_checks:off} - proc add* (x: var string, y: cstring) = + {.push stack_trace:off} + proc add*(x: var string, y: cstring) = var i = 0 while y[i] != '\0': add(x, y[i]) inc(i) {.pop.} else: - proc add* (x: var string, y: cstring) {.pure.} = + proc add*(x: var string, y: cstring) {.pure.} = asm """ var len = `x`[0].length-1; for (var i = 0; i < `y`.length; ++i) { @@ -1413,10 +1413,6 @@ else: `x`[0][len] = 0 """ -proc `/`*(x, y: int): float {.inline, noSideEffect.} = - ## integer division that results in a float. - result = toFloat(x) / toFloat(y) - proc echo*[Ty](x: openarray[Ty]) {.magic: "Echo".} ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is ## available for the ECMAScript target too! @@ -1450,6 +1446,7 @@ proc quit*(errorcode: int = QuitSuccess) {. ## unless a quit procedure calls ``GC_collect``. when not defined(EcmaScript) and not defined(NimrodVM): + {.push stack_trace: off.} proc atomicInc*(memLoc: var int, x: int): int {.inline.} ## atomic increment of `memLoc`. Returns the value after the operation. @@ -1475,8 +1472,6 @@ when not defined(EcmaScript) and not defined(NimrodVM): initStackBottom() initGC() # BUGFIX: need to be called here! - {.push stack_trace: off.} - include "system/ansi_c" proc cmp(x, y: string): int = @@ -1650,25 +1645,6 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## retrieves the current position of the file pointer that is used to ## read from the file `f`. The file's first byte has the index zero. - include "system/sysio" - - iterator lines*(filename: string): string = - ## Iterate over any line in the file named `filename`. - ## If the file does not exist `EIO` is raised. - var f = open(filename) - var res = "" - while not endOfFile(f): - rawReadLine(f, res) - yield res - Close(f) - - iterator lines*(f: TFile): string = - ## Iterate over any line in the file `f`. - var res = "" - while not endOfFile(f): - rawReadLine(f, res) - yield res - proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno", header: ""} ## returns the OS file handle of the file ``f``. This is only useful for @@ -1694,6 +1670,26 @@ when not defined(EcmaScript) and not defined(NimrodVM): # as it would recurse endlessly! include "system/arithm" {.pop.} # stack trace + + include "system/sysio" + + iterator lines*(filename: string): string = + ## Iterate over any line in the file named `filename`. + ## If the file does not exist `EIO` is raised. + var f = open(filename) + var res = "" + while not endOfFile(f): + rawReadLine(f, res) + yield res + Close(f) + + iterator lines*(f: TFile): string = + ## Iterate over any line in the file `f`. + var res = "" + while not endOfFile(f): + rawReadLine(f, res) + yield res + include "system/dyncalls" include "system/sets" @@ -1723,14 +1719,18 @@ when not defined(EcmaScript) and not defined(NimrodVM): result = n.sons[n.len] include "system/systhread" + {.push stack_trace: off.} include "system/mmdisp" + {.pop.} + include "system/sysstr" include "system/assign" include "system/repr" proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} = ## retrieves the current exception; if there is none, nil is returned. - result = currException + ThreadGlobals() + result = ||currException proc getCurrentExceptionMsg*(): string {.inline.} = ## retrieves the error message that was attached to the current @@ -1789,6 +1789,10 @@ proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = {.pop.} # checks {.pop.} # hints +proc `/`*(x, y: int): float {.inline, noSideEffect.} = + ## integer division that results in a float. + result = toFloat(x) / toFloat(y) + template `-|`(b, s: expr): expr = (if b >= 0: b else: s.len + b) diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim index 8509fe3a33..d80747671f 100755 --- a/lib/system/cgprocs.nim +++ b/lib/system/cgprocs.nim @@ -23,50 +23,3 @@ proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline.} -when false: - # Support for thread local storage: - when defined(windows): - type - TThreadVarSlot {.compilerproc.} = distinct int32 - - proc TlsAlloc(): TThreadVarSlot {. - importc: "TlsAlloc", stdcall, dynlib: "kernel32".} - proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {. - importc: "TlsSetValue", stdcall, dynlib: "kernel32".} - proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {. - importc: "TlsGetValue", stdcall, dynlib: "kernel32".} - - proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} = - result = TlsAlloc() - proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {. - compilerproc, inline.} = - TlsSetValue(s, value) - proc ThreadVarGetValue(s: TThreadVarSlot): pointer {. - compilerproc, inline.} = - result = TlsGetValue(s) - - else: - type - Tpthread_key {.importc: "pthread_key_t", - header: "".} = distinct int - TThreadVarSlot {.compilerproc.} = Tpthread_key - - proc pthread_getspecific(a1: Tpthread_key): pointer {. - importc: "pthread_getspecific", header: "".} - proc pthread_key_create(a1: ptr Tpthread_key, - destruct: proc (x: pointer) {.noconv.}): int32 {. - importc: "pthread_key_create", header: "".} - proc pthread_key_delete(a1: Tpthread_key): int32 {. - importc: "pthread_key_delete", header: "".} - - proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {. - importc: "pthread_setspecific", header: "".} - - proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} = - discard pthread_key_create(addr(result), nil) - proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {. - compilerproc, inline.} = - discard pthread_setspecific(s, value) - proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc, inline.} = - result = pthread_getspecific(s) - diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim index 01d8bd8a2b..2dccd85794 100755 --- a/lib/system/debugger.nim +++ b/lib/system/debugger.nim @@ -85,8 +85,7 @@ proc openAppend(filename: string): TFile = write(result, "----------------------------------------\n") proc dbgRepr(p: pointer, typ: PNimType): string = - var - cl: TReprClosure + var cl: TReprClosure initReprClosure(cl) cl.recDepth = maxDisplayRecDepth # locks for the GC turned out to be a bad idea... @@ -139,8 +138,10 @@ proc dbgShowCurrentProc(dbgFramePointer: PFrame) = write(stdout, "*** endb| (procedure name not available) ***\n") proc dbgShowExecutionPoint() = - write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line & - ") " & $framePtr.procname & " ***\n") + ThreadGlobals() + write(stdout, "*** endb| " & $(||framePtr).filename & + "(" & $(||framePtr).line & ") " & + $(||framePtr).procname & " ***\n") when defined(windows) or defined(dos) or defined(os2): {.define: FileSystemCaseInsensitive.} @@ -171,9 +172,10 @@ proc fileMatches(c, bp: cstring): bool = return true proc dbgBreakpointReached(line: int): int = + ThreadGlobals() for i in 0..dbgBPlen-1: if line >= dbgBP[i].low and line <= dbgBP[i].high and - fileMatches(framePtr.filename, dbgBP[i].filename): return i + fileMatches((||framePtr).filename, dbgBP[i].filename): return i return -1 proc scanAndAppendWord(src: string, a: var string, start: int): int = @@ -255,6 +257,7 @@ proc hasExt(s: string): bool = return false proc setBreakPoint(s: string, start: int) = + ThreadGlobals() var dbgTemp: string var i = scanWord(s, dbgTemp, start) if i <= start: @@ -269,7 +272,7 @@ proc setBreakPoint(s: string, start: int) = i = scanNumber(s, dbgBP[x].low, i) if dbgBP[x].low == 0: # set to current line: - dbgBP[x].low = framePtr.line + dbgBP[x].low = (||framePtr).line i = scanNumber(s, dbgBP[x].high, i) if dbgBP[x].high == 0: # set to low: dbgBP[x].high = dbgBP[x].low @@ -278,7 +281,7 @@ proc setBreakPoint(s: string, start: int) = if not hasExt(dbgTemp): add(dbgTemp, ".nim") dbgBP[x].filename = dbgTemp else: # use current filename - dbgBP[x].filename = $framePtr.filename + dbgBP[x].filename = $(||framePtr).filename # skip whitespace: while s[i] in {' ', '\t'}: inc(i) if s[i] != '\0': @@ -347,9 +350,10 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) = proc CommandPrompt() = # if we return from this routine, user code executes again + ThreadGlobals() var again = True - dbgFramePtr = framePtr # for going down and up the stack + dbgFramePtr = ||framePtr # for going down and up the stack dbgDown = 0 # how often we did go down while again: @@ -366,11 +370,11 @@ proc CommandPrompt() = again = false of "n", "next": dbgState = dbStepOver - dbgSkipToFrame = framePtr + dbgSkipToFrame = ||framePtr again = false of "f", "skipcurrent": dbgState = dbSkipCurrent - dbgSkipToFrame = framePtr.prev + dbgSkipToFrame = (||framePtr).prev again = false of "c", "continue": dbgState = dbBreakpoints @@ -401,7 +405,7 @@ proc CommandPrompt() = if dbgDown <= 0: debugOut("[Warning] cannot go up any further ") else: - dbgFramePtr = framePtr + dbgFramePtr = ||framePtr for j in 0 .. dbgDown-2: # BUGFIX dbgFramePtr = dbgFramePtr.prev dec(dbgDown) @@ -442,16 +446,17 @@ proc endbStep() = CommandPrompt() proc checkForBreakpoint() = - var i = dbgBreakpointReached(framePtr.line) + ThreadGlobals() + var i = dbgBreakpointReached((||framePtr).line) if i >= 0: write(stdout, "*** endb| reached ") write(stdout, dbgBP[i].name) write(stdout, " in ") - write(stdout, framePtr.filename) + write(stdout, (||framePtr).filename) write(stdout, "(") - write(stdout, framePtr.line) + write(stdout, (||framePtr).line) write(stdout, ") ") - write(stdout, framePtr.procname) + write(stdout, (||framePtr).procname) write(stdout, " ***\n") CommandPrompt() @@ -482,7 +487,8 @@ proc endb(line: int) {.compilerproc.} = # Thus, it must have as few parameters as possible to keep the # code size small! # Check if we are at an enabled breakpoint or "in the mood" - framePtr.line = line # this is done here for smaller code size! + ThreadGlobals() + (||framePtr).line = line # this is done here for smaller code size! if dbgLineHook != nil: dbgLineHook() case dbgState of dbStepInto: @@ -490,7 +496,7 @@ proc endb(line: int) {.compilerproc.} = dbgShowExecutionPoint() CommandPrompt() of dbSkipCurrent, dbStepOver: # skip current routine - if framePtr == dbgSkipToFrame: + if ||framePtr == dbgSkipToFrame: dbgShowExecutionPoint() CommandPrompt() else: # breakpoints are wanted though (I guess) diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index fb11309384..447ce3f950 100755 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -12,6 +12,8 @@ # However, the interface has been designed to take platform differences into # account and been ported to all major platforms. +{.push stack_trace: off.} + const NilLibHandle: TLibHandle = nil @@ -135,3 +137,6 @@ elif defined(mac): else: {.error: "no implementation for dyncalls".} + +{.pop.} + diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index ed2ec7ff01..9bdc695699 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -13,6 +13,7 @@ var stackTraceNewLine* = "\n" ## undocumented feature; it is replaced by ``
`` ## for CGI applications + isMultiThreaded: bool # true when prog created at least 1 thread when not defined(windows) or not defined(guiapp): proc writeToStdErr(msg: CString) = write(stdout, msg) @@ -36,30 +37,139 @@ type TSafePoint {.compilerproc, final.} = object prev: PSafePoint # points to next safe point ON THE STACK status: int - exc: ref E_Base # XXX only needed for bootstrapping; unused context: C_JmpBuf -#when hasThreadSupport: nil +when hasThreadSupport: + # Support for thread local storage: + when defined(windows): + type + TThreadVarSlot {.compilerproc.} = distinct int32 -var - excHandler {.threadvar, compilerproc.}: PSafePoint = nil - # list of exception handlers - # a global variable for the root of all try blocks - currException {.threadvar.}: ref E_Base + proc TlsAlloc(): TThreadVarSlot {. + importc: "TlsAlloc", stdcall, dynlib: "kernel32".} + proc TlsSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {. + importc: "TlsSetValue", stdcall, dynlib: "kernel32".} + proc TlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {. + importc: "TlsGetValue", stdcall, dynlib: "kernel32".} + + proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} = + result = TlsAlloc() + proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {. + compilerproc, inline.} = + TlsSetValue(s, value) + proc ThreadVarGetValue(s: TThreadVarSlot): pointer {. + compilerproc, inline.} = + result = TlsGetValue(s) + + else: + {.passL: "-pthread".} + {.passC: "-pthread".} + + type + Tpthread_key {.importc: "pthread_key_t", + header: "".} = distinct int + TThreadVarSlot {.compilerproc.} = Tpthread_key + + proc pthread_getspecific(a1: Tpthread_key): pointer {. + importc: "pthread_getspecific", header: "".} + proc pthread_key_create(a1: ptr Tpthread_key, + destruct: proc (x: pointer) {.noconv.}): int32 {. + importc: "pthread_key_create", header: "".} + proc pthread_key_delete(a1: Tpthread_key): int32 {. + importc: "pthread_key_delete", header: "".} + + proc pthread_setspecific(a1: Tpthread_key, a2: pointer): int32 {. + importc: "pthread_setspecific", header: "".} + + proc specificDestroy(mem: pointer) {.noconv.} = dealloc(mem) + + proc ThreadVarAlloc(): TThreadVarSlot {.compilerproc, inline.} = + discard pthread_key_create(addr(result), specificDestroy) + proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {. + compilerproc, inline.} = + discard pthread_setspecific(s, value) + proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.compilerproc, inline.} = + result = pthread_getspecific(s) + + type + TGlobals {.final, pure.} = object + excHandler: PSafePoint + currException: ref E_Base + framePtr: PFrame + buf: string # cannot be allocated on the stack! + assertBuf: string # we need a different buffer for + # assert, as it raises an exception and + # exception handler needs the buffer too + gAssertionFailed: ref EAssertionFailed + tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! + data: float # compiler should add thread local variables here! + PGlobals = ptr TGlobals + + var globalsSlot = ThreadVarAlloc() + proc CreateThreadLocalStorage*() {.inl.} = + isMultiThreaded = true + ThreadVarSetValue(globalsSlot, alloc0(sizeof(TGlobals))) + + proc GetGlobals(): PGlobals {.compilerRtl, inl.} = + result = cast[PGlobals](ThreadVarGetValue(globalsSlot)) + + # create for the main thread: + ThreadVarSetValue(globalsSlot, alloc0(sizeof(TGlobals))) + +when hasThreadSupport: + template ThreadGlobals = + var globals = GetGlobals() + template `||`(varname: expr): expr = globals.varname + + ThreadGlobals() +else: + template ThreadGlobals = nil # nothing + template `||`(varname: expr): expr = varname + + var + framePtr {.compilerproc.}: PFrame # XXX only temporarily a compilerproc + excHandler: PSafePoint = nil + # list of exception handlers + # a global variable for the root of all try blocks + currException: ref E_Base + + buf: string # cannot be allocated on the stack! + assertBuf: string # we need a different buffer for + # assert, as it raises an exception and + # exception handler needs the buffer too + tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! + gAssertionFailed: ref EAssertionFailed + +proc pushFrame(s: PFrame) {.compilerRtl, inl.} = + ThreadGlobals() + s.prev = ||framePtr + ||framePtr = s + +proc popFrame {.compilerRtl, inl.} = + ThreadGlobals() + ||framePtr = (||framePtr).prev + +proc setFrame(s: PFrame) {.compilerRtl, inl.} = + ThreadGlobals() + ||framePtr = s proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = - s.prev = excHandler - excHandler = s + ThreadGlobals() + s.prev = ||excHandler + ||excHandler = s proc popSafePoint {.compilerRtl, inl.} = - excHandler = excHandler.prev + ThreadGlobals() + ||excHandler = (||excHandler).prev proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = - e.parent = currException - currException = e + ThreadGlobals() + e.parent = ||currException + ||currException = e proc popCurrentException {.compilerRtl, inl.} = - currException = currException.parent + ThreadGlobals() + ||currException = (||currException).parent # some platforms have native support for stack traces: const @@ -80,11 +190,16 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: proc dladdr(addr1: pointer, info: ptr TDl_info): int {. importc: "dladdr", header: "".} - var - tempAddresses: array [0..127, pointer] # cannot be allocated on the stack! - tempDlInfo: TDl_info + when not hasThreadSupport: + var + tempAddresses: array [0..127, pointer] # should not be alloc'd on stack + tempDlInfo: TDl_info proc auxWriteStackTraceWithBacktrace(s: var string) = + when hasThreadSupport: + var + tempAddresses: array [0..127, pointer] # but better than a threadvar + tempDlInfo: TDl_info # This is allowed to be expensive since it only happens during crashes # (but this way you don't need manual stack tracing) var size = backtrace(cast[ptr pointer](addr(tempAddresses)), @@ -108,24 +223,18 @@ when defined(nativeStacktrace) and nativeStackTraceSupported: # Once we're past signalHandler, we're at what the user is # interested in enabled = true - -var - buf: string # cannot be allocated on the stack! - assertBuf: string # we need a different buffer for - # assert, as it raises an exception and - # exception handler needs the buffer too - tempFrames: array [0..127, PFrame] # cannot be allocated on the stack! proc auxWriteStackTrace(f: PFrame, s: var string) = const firstCalls = 32 + ThreadGlobals() var it = f i = 0 total = 0 - while it != nil and i <= high(tempFrames)-(firstCalls-1): + while it != nil and i <= high(||tempFrames)-(firstCalls-1): # the (-1) is for a nil entry that marks where the '...' should occur - tempFrames[i] = it + (||tempFrames)[i] = it inc(i) inc(total) it = it.prev @@ -136,37 +245,38 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = for j in 1..total-i-(firstCalls-1): if b != nil: b = b.prev if total != i: - tempFrames[i] = nil + (||tempFrames)[i] = nil inc(i) - while b != nil and i <= high(tempFrames): - tempFrames[i] = b + while b != nil and i <= high(||tempFrames): + (||tempFrames)[i] = b inc(i) b = b.prev for j in countdown(i-1, 0): - if tempFrames[j] == nil: + if (||tempFrames)[j] == nil: add(s, "(") add(s, $(total-i-1)) add(s, " calls omitted) ...") else: var oldLen = s.len - add(s, tempFrames[j].filename) - if tempFrames[j].line > 0: + add(s, (||tempFrames)[j].filename) + if (||tempFrames)[j].line > 0: add(s, '(') - add(s, $tempFrames[j].line) + add(s, $(||tempFrames)[j].line) add(s, ')') for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') - add(s, tempFrames[j].procname) + add(s, (||tempFrames)[j].procname) add(s, stackTraceNewLine) proc rawWriteStackTrace(s: var string) = when nimrodStackTrace: - if framePtr == nil: + ThreadGlobals() + if ||framePtr == nil: add(s, "No stack traceback available") add(s, stackTraceNewLine) else: add(s, "Traceback (most recent call last)") add(s, stackTraceNewLine) - auxWriteStackTrace(framePtr, s) + auxWriteStackTrace(||framePtr, s) elif defined(nativeStackTrace) and nativeStackTraceSupported: add(s, "Traceback from system (most recent call last)") add(s, stackTraceNewLine) @@ -184,53 +294,53 @@ proc quitOrDebug() {.inline.} = proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = GC_disable() # a bad thing is an error in the GC while raising an exception e.name = ename - if excHandler != nil: + ThreadGlobals() + if ||excHandler != nil: pushCurrentException(e) - c_longjmp(excHandler.context, 1) + c_longjmp((||excHandler).context, 1) else: - if not isNil(buf): - setLen(buf, 0) - rawWriteStackTrace(buf) + if not isNil(||buf): + setLen(||buf, 0) + rawWriteStackTrace(||buf) if e.msg != nil and e.msg[0] != '\0': - add(buf, "Error: unhandled exception: ") - add(buf, $e.msg) + add(||buf, "Error: unhandled exception: ") + add(||buf, $e.msg) else: - add(buf, "Error: unhandled exception") - add(buf, " [") - add(buf, $ename) - add(buf, "]\n") - writeToStdErr(buf) + add(||buf, "Error: unhandled exception") + add(||buf, " [") + add(||buf, $ename) + add(||buf, "]\n") + writeToStdErr(||buf) else: writeToStdErr(ename) quitOrDebug() GC_enable() proc reraiseException() {.compilerRtl.} = - if currException == nil: + ThreadGlobals() + if ||currException == nil: raise newException(ENoExceptionToReraise, "no exception to reraise") else: - raiseException(currException, currException.name) - -var - gAssertionFailed: ref EAssertionFailed + raiseException(||currException, (||currException).name) proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} = if not cond: + ThreadGlobals() #c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line) #quit(1) GC_disable() # BUGFIX: `$` allocates a new string object! - if not isNil(assertBuf): + if not isNil(||assertBuf): # BUGFIX: when debugging the GC, assertBuf may be nil - setLen(assertBuf, 0) - add(assertBuf, "[Assertion failure] file: ") - add(assertBuf, file) - add(assertBuf, " line: ") - add(assertBuf, $line) - add(assertBuf, "\n") - gAssertionFailed.msg = assertBuf + setLen(||assertBuf, 0) + add(||assertBuf, "[Assertion failure] file: ") + add(||assertBuf, file) + add(||assertBuf, " line: ") + add(||assertBuf, $line) + add(||assertBuf, "\n") + (||gAssertionFailed).msg = ||assertBuf GC_enable() - if gAssertionFailed != nil: - raise gAssertionFailed + if ||gAssertionFailed != nil: + raise ||gAssertionFailed else: c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line) quit(1) @@ -245,23 +355,24 @@ var proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} = # print stack trace and quit + ThreadGlobals() var s = sig GC_disable() - setLen(buf, 0) - rawWriteStackTrace(buf) + setLen(||buf, 0) + rawWriteStackTrace(||buf) - if s == SIGINT: add(buf, "SIGINT: Interrupted by Ctrl-C.\n") + if s == SIGINT: add(||buf, "SIGINT: Interrupted by Ctrl-C.\n") elif s == SIGSEGV: - add(buf, "SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n") + add(||buf, "SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n") elif s == SIGABRT: if dbgAborting: return # the debugger wants to abort - add(buf, "SIGABRT: Abnormal termination.\n") - elif s == SIGFPE: add(buf, "SIGFPE: Arithmetic error.\n") - elif s == SIGILL: add(buf, "SIGILL: Illegal operation.\n") + add(||buf, "SIGABRT: Abnormal termination.\n") + elif s == SIGFPE: add(||buf, "SIGFPE: Arithmetic error.\n") + elif s == SIGILL: add(||buf, "SIGILL: Illegal operation.\n") elif s == SIGBUS: - add(buf, "SIGBUS: Illegal storage access. (Attempt to read from nil?)\n") - else: add(buf, "unknown signal\n") - writeToStdErr(buf) + add(||buf, "SIGBUS: Illegal storage access. (Attempt to read from nil?)\n") + else: add(||buf, "unknown signal\n") + writeToStdErr(||buf) dbgAborting = True # play safe here... GC_enable() quit(1) # always quit when SIGABRT @@ -278,11 +389,9 @@ when not defined(noSignalHandler): registerSignalHandler() # call it in initialization section # for easier debugging of the GC, this memory is only allocated after the # signal handlers have been registered -new(gAssertionFailed) -buf = newString(2048) -assertBuf = newString(2048) -setLen(buf, 0) -setLen(assertBuf, 0) +new(||gAssertionFailed) +||buf = newStringOfCap(2000) +||assertBuf = newStringOfCap(2000) proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = raise newException(EOutOfRange, "value " & $val & " out of range") diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 7c70ccf855..52de66d489 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -391,7 +391,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = assert((cast[TAddress](res) and (MemAlign-1)) == 0) # now it is buffered in the ZCT res.typ = typ - when debugGC: + when debugGC and not hasThreadSupport: if framePtr != nil and framePtr.prev != nil: res.filename = framePtr.prev.filename res.line = framePtr.prev.line diff --git a/lib/system/hti.nim b/lib/system/hti.nim index d22109061a..c6ea0bc443 100755 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/system/systhread.nim b/lib/system/systhread.nim index fa2d75704d..d9b340ce23 100755 --- a/lib/system/systhread.nim +++ b/lib/system/systhread.nim @@ -23,9 +23,6 @@ else: inc(p, val) result = p -var - isMultiThreaded: bool # true when prog created at least 1 thread - proc atomicInc(memLoc: var int, x: int): int = when hasThreadSupport: result = sync_add_and_fetch(memLoc, x) diff --git a/tests/accept/run/texcsub.nim b/tests/accept/run/texcsub.nim index e78da8df62..3dba357f9d 100755 --- a/tests/accept/run/texcsub.nim +++ b/tests/accept/run/texcsub.nim @@ -1,7 +1,6 @@ discard """ file: "texcsub.nim" output: "caught!" - disabled: true """ # Test inheritance for exception matching: diff --git a/todo.txt b/todo.txt index 907fb790af..e892e69a6b 100755 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,4 @@ -* thread support: threadvar on Windows seems broken; - add --deadlock_prevention:on|off switch +* add --deadlock_prevention:on|off switch; timeout for locks * implicit ref/ptr->var conversion @@ -21,7 +20,6 @@ Bugs ---- - proc (x: int) is passable to proc (x: var int) !? - the parser allows empty object case branches -- Exception matching needs to take subclasses into account - pegs: the anchor '^' does not work because many procs use a linear search and matchLen() - BUG: generic assign still buggy diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 53bdb243e0..3c9d769ea2 100755 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -142,7 +142,7 @@ proc processFile(filename: string) = if t.first <= 0: break inc(line, countLines(buffer, i, t.first-1)) - var wholeMatch = buffer.copy(t.first, t.last) + var wholeMatch = buffer.substr(t.first, t.last) if optReplace notin options: highlight(buffer, wholeMatch, "", t, line, showRepl=false) @@ -168,15 +168,15 @@ proc processFile(filename: string) = else: highlight(buffer, wholeMatch, r, t, line, showRepl=reallyReplace) if reallyReplace: - result.add(buffer.copy(i, t.first-1)) + result.add(buffer.substr(i, t.first-1)) result.add(r) else: - result.add(buffer.copy(i, t.last)) + result.add(buffer.substr(i, t.last)) inc(line, countLines(buffer, t.first, t.last)) i = t.last+1 if optReplace in options: - result.add(copy(buffer, i)) + result.add(substr(buffer, i)) var f: TFile if open(f, filename, fmWrite): f.write(result) @@ -185,7 +185,7 @@ proc processFile(filename: string) = quit "cannot open file for overwriting: " & filename proc hasRightExt(filename: string, exts: seq[string]): bool = - var y = splitFile(filename).ext.copy(1) # skip leading '.' + var y = splitFile(filename).ext.substr(1) # skip leading '.' for x in items(exts): if os.cmpPaths(x, y) == 0: return true diff --git a/tools/niminst.nim b/tools/niminst.nim index e696b6b93c..c10de7d707 100755 --- a/tools/niminst.nim +++ b/tools/niminst.nim @@ -148,7 +148,7 @@ proc parseCmdLine(c: var TConfigData) = of "var": var idx = val.find('=') if idx < 0: quit("invalid command line") - c.vars[copy(val, 0, idx-1)] = copy(val, idx+1) + c.vars[substr(val, 0, idx-1)] = substr(val, idx+1) else: quit(Usage) of cmdEnd: break if c.infile.len == 0: quit(Usage) diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 7889591fcb..0e1bcc31ae 100755 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -76,7 +76,7 @@ proc parseCmdLine(c: var TConfigData) = of "var": var idx = val.find('=') if idx < 0: quit("invalid command line") - c.vars[copy(val, 0, idx-1)] = copy(val, idx+1) + c.vars[substr(val, 0, idx-1)] = substr(val, idx+1) else: quit(Usage) of cmdEnd: break if c.infile.len == 0: quit(Usage) diff --git a/web/news.txt b/web/news.txt index dcfa6e363a..db4b93fa21 100755 --- a/web/news.txt +++ b/web/news.txt @@ -21,6 +21,7 @@ Bugfixes copied. - Bugfix: The compiler does not emit very inaccurate floating point literals anymore. +- Bugfix: Subclasses are taken into account for ``try except`` matching. - Lots of other bugfixes: Too many to list them all.