use CPU flag instead of thread local storage for the error indicator; progress

This commit is contained in:
araq
2024-06-02 11:53:01 +02:00
parent 05b29919e1
commit 7906c05824
4 changed files with 41 additions and 16 deletions

View File

@@ -731,9 +731,9 @@ proc raiseExit(p: BProc) =
if p.nestedTryStmts.len == 0:
p.flags.incl beforeRetNeeded
# easy case, simply goto 'ret':
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", [])
lineCg(p, cpsStmts, "NIM_ERR_JUMP(BeforeRet_);$n", [])
else:
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
lineCg(p, cpsStmts, "NIM_ERR_JUMP(LA$1_);$n",
[p.nestedTryStmts[^1].label])
proc finallyActions(p: BProc) =
@@ -1282,8 +1282,14 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
expr(p, t[0], d)
var endLabel = -1
if 1 < t.len and t[1].kind == nkExceptBranch:
startBlock(p, "if (NIM_UNLIKELY(*nimErr_)) {$n")
inc p.labels
endLabel = p.labels
#startBlock(p, "if (NIM_UNLIKELY(*nimErr_)) {$n")
linefmt(p, cpsStmts, "NIM_ERR_JUMP(LA$1_);$n", [lab])
linefmt(p, cpsStmts, "goto LA$1_;$n", [endLabel])
startBlock(p, "if (NIM_TRUE) {$n") # so that the `else` works out
else:
startBlock(p)
linefmt(p, cpsStmts, "LA$1_:;$n", [lab])
@@ -1303,7 +1309,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
if i > 1: lineF(p, cpsStmts, "else", [])
startBlock(p)
# we handled the exception, remember this:
linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", [])
linefmt(p, cpsStmts, "NIM_ERR_CLEAR();$n", [])
expr(p, t[i][0], d)
else:
var orExpr = newRopeAppender()
@@ -1322,7 +1328,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
if i > 1: line(p, cpsStmts, "else ")
startBlock(p, "if ($1) {$n", [orExpr])
# we handled the exception, remember this:
linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", [])
linefmt(p, cpsStmts, "NIM_ERR_CLEAR();$n", [])
expr(p, t[i][^1], d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
@@ -1332,6 +1338,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
inc(i)
discard pop(p.nestedTryStmts)
endBlock(p)
if endLabel >= 0:
linefmt(p, cpsStmts, "LA$1_:;$n", [endLabel])
if i < t.len and t[i].kind == nkFinally:
startBlock(p)
@@ -1342,7 +1350,17 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
else:
# pretend we did handle the error for the safe execution of the 'finally' section:
p.procSec(cpsLocals).add(ropecg(p.module, "NIM_BOOL oldNimErrFin$1_;$n", [lab]))
linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = NIM_FALSE;$n", [lab])
inc p.labels, 2
let fLabel = p.labels-1
let tLabel = p.labels
linefmt(p, cpsStmts, "NIM_ERR_JUMP(LA$1_);$n", [tLabel])
linefmt(p, cpsStmts, "oldNimErrFin$1_ = NIM_FALSE; goto LA$2_;$n", [lab, fLabel])
linefmt(p, cpsStmts, "LA$2_: oldNimErrFin$1_ = NIM_TRUE; LA$3_: ;$n", [lab, tLabel, fLabel])
linefmt(p, cpsStmts, "NIM_ERR_CLEAR();$n", [])
#linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; NIM_ERR_CLEAR();$n", [lab])
genStmts(p, t[i][0])
# this is correct for all these cases:
# 1. finally is run during ordinary control flow
@@ -1350,7 +1368,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
# error back to nil.
# 3. finally is run for exception handling code without any 'except'
# handler present or only handlers that did not match.
linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab])
linefmt(p, cpsStmts, "if (oldNimErrFin$1_) { NIM_ERR_SET(); } else { NIM_ERR_CLEAR(); }$n", [lab])
endBlock(p)
raiseExit(p)
if hasExcept: inc p.withinTryWithExcept

View File

@@ -1172,8 +1172,9 @@ proc genProcBody(p: BProc; procBody: PNode) =
genStmts(p, procBody) # modifies p.locals, p.init, etc.
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
p.flags.incl nimErrorFlagDeclared
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_ERR_FLAG();$n", []))
if not isDefined(p.config, "nimUseCpuFlag"):
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
sfNoReturn in s.flags and m.config.exc != excGoto
@@ -1459,6 +1460,9 @@ proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
if conf.isDefined("nimEmulateOverflowChecks"):
result.add("#define NIM_EmulateOverflowChecks\L")
if conf.isDefined("nimUseCpuFlag"):
result.add("#define NIM_UseCpuFlag\L")
proc headerTop(): Rope =
result = "/* Generated by Nim Compiler v$1 */$N" % [rope(VersionAsString)]

View File

@@ -594,25 +594,28 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, "P
#define NIM_NOALIAS __restrict
/* __restrict is said to work for all the C(++) compilers out there that we support */
#if defined(__GNUC__)
# define NIM_ERR_FLAG() /* nothing to declare: uses HW flag */
# define NIM_ERR_JUMP(lab) __asm__ goto("jc %l0" \
#if defined(NIM_UseCpuFlag)
# if defined(__x86_64__) || defined(__i386__)
# define NIM_ERR_FLAG() /* nothing to declare: uses HW flag */
# define NIM_ERR_JUMP(lab) __asm__ goto("jc %l0" \
: \
: \
: \
: lab)
# define NIM_ERR_SET() __asm__ volatile("stc" \
# define NIM_ERR_SET() __asm__ volatile("stc" \
: \
: \
: "cc" \
)
# define NIM_ERR_CLEAR() __asm__ volatile("clc" \
# define NIM_ERR_CLEAR() __asm__ volatile("clc" \
: \
: \
: "cc" \
)
# else
# error "CPU flags not implemented for your platform"
# endif
#else
# define NIM_ERR_FLAG() NIM_BOOL* nimErr_
# define NIM_ERR_JUMP(lab) if (NIM_UNLIKELY(*nimErr_)) goto lab

View File

@@ -472,7 +472,7 @@ proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
elif quirkyExceptions or gotoBasedExceptions:
pushCurrentException(e)
when gotoBasedExceptions:
inc nimInErrorMode
nimInErrorMode = true
else:
if excHandler != nil:
pushCurrentException(e)