From f99c40f61bc47f98390aab42f686fcb697dc9ce8 Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Thu, 25 Sep 2014 23:29:02 +0200 Subject: [PATCH 1/2] Improve setjmp()/longjmp() performance. Exception handling for the C backend used setjmp()/longjmp() unconditionally. However, on POSIX systems, these functions save and restore the signal mask, adding considerable overhead to exception handling, even where no exceptions are involved. The compiler and library now try to use either _setjmp()/_longjmp() or sigsetjmp()/siglongjmp() where possible, marked by the defines "nimRawSetjmp" and "nimSigSetjmp", respectively. The define "nimStdSetjmp" can be used to revert to setjmp()/longjmp() instead. --- compiler/ccgstmts.nim | 9 ++++++++- compiler/cgen.nim | 2 +- compiler/condsyms.nim | 2 ++ lib/system/ansi_c.nim | 21 +++++++++++++++++---- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index cb9eebb32f..8b0a8e9bb5 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -832,7 +832,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = discard cgsym(p.module, "E_Base") linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) - linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + if isDefined("nimStdSetjmp"): + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) + elif isDefined("nimSigSetjmp"): + linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint) + elif isDefined("nimRawSetjmp"): + linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint) + else: + linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) startBlock(p, "if ($1.status == 0) {$n", [safePoint]) var length = sonsLen(t) add(p.nestedTryStmts, t) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 315b55801c..359fa33098 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -13,7 +13,7 @@ import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, - times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, + times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, semparallel diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index dc61d2f894..a2d8b35641 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -136,3 +136,5 @@ proc initDefines*() = declareSymbol("emulatedthreadvars") if platform.OS[targetOS].props.contains(ospLacksThreadVars): defineSymbol("emulatedthreadvars") + if isDefined("posix"): + defineSymbol("nimRawSetjmp") diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index e012697ae7..673d55582c 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -78,10 +78,23 @@ when defined(macosx): else: template SIGBUS: expr = SIGSEGV -proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {. - header: "", importc: "longjmp".} -proc c_setjmp(jmpb: C_JmpBuf): cint {. - header: "", importc: "setjmp".} +when defined(nimSigSetjmp) and not defined(nimStdSetjmp): + proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "siglongjmp".} + template c_setjmp(jmpb: C_JmpBuf): cint = + proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {. + header: "", importc: "sigsetjmp".} + c_sigsetjmp(jmpb, 0) +elif defined(nimRawSetjmp) and not defined(nimStdSetjmp): + proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "_longjmp".} + proc c_setjmp(jmpb: C_JmpBuf): cint {. + header: "", importc: "_setjmp".} +else: + proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "longjmp".} + proc c_setjmp(jmpb: C_JmpBuf): cint {. + header: "", importc: "setjmp".} proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {. importc: "signal", header: "".} From cb6441e73d976dcf59b1e55236887fe5d3a1d6ec Mon Sep 17 00:00:00 2001 From: Reimer Behrends Date: Sat, 27 Sep 2014 18:05:30 +0200 Subject: [PATCH 2/2] Use _setjmp()/_longjmp() only on BSD-like systems for now. --- compiler/condsyms.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a2d8b35641..238dbf5c79 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -136,5 +136,7 @@ proc initDefines*() = declareSymbol("emulatedthreadvars") if platform.OS[targetOS].props.contains(ospLacksThreadVars): defineSymbol("emulatedthreadvars") - if isDefined("posix"): + case targetOS + of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx: defineSymbol("nimRawSetjmp") + else: discard