system.nim refactorings for IC (#25295)

Generally useful refactoring as it produces better code.

(cherry picked from commit 0f7b378467)
This commit is contained in:
Andreas Rumpf
2025-11-19 16:27:31 +01:00
committed by narimiran
parent a5e73ff408
commit 431e01eaf2
13 changed files with 253 additions and 191 deletions

View File

@@ -19,12 +19,16 @@ import std/private/miscdollars
type InstantiationInfo = tuple[filename: string, line: int, column: int]
{.push overflowChecks: off, rangeChecks: off.}
proc `$`(info: InstantiationInfo): string =
# The +1 is needed here
# instead of overriding `$` (and changing its meaning), consider explicit name.
result = ""
result.toLocation(info.filename, info.line, info.column + 1)
{.pop.}
# ---------------------------------------------------------------------------

View File

@@ -29,18 +29,23 @@ const
# doAssert res == digits100
# ```
proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} =
{.push checks: off, stackTrace: off.}
when not defined(nimHasEnforceNoRaises):
{.pragma: enforceNoRaises.}
proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline, enforceNoRaises.} =
buf[pos] = digits100[2 * digits]
buf[pos+1] = digits100[2 * digits + 1]
#copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char)))
proc trailingZeros2Digits*(digits: uint32): int {.inline.} =
proc trailingZeros2Digits*(digits: uint32): int {.inline, enforceNoRaises.} =
trailingZeros100[digits]
when defined(js):
proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".}
func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} =
func addChars[T](result: var string, x: T, start: int, n: int) {.inline, enforceNoRaises.} =
let old = result.len
result.setLen old + n
template impl =
@@ -52,10 +57,10 @@ func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} =
{.noSideEffect.}:
copyMem result[old].addr, x[start].unsafeAddr, n
func addChars[T](result: var string, x: T) {.inline.} =
func addChars[T](result: var string, x: T) {.inline, enforceNoRaises.} =
addChars(result, x, 0, x.len)
func addIntImpl(result: var string, x: uint64) {.inline.} =
func addIntImpl(result: var string, x: uint64) {.inline, enforceNoRaises.} =
var tmp {.noinit.}: array[24, char]
var num = x
var next = tmp.len - 1
@@ -79,8 +84,6 @@ func addIntImpl(result: var string, x: uint64) {.inline.} =
dec next
addChars(result, tmp, next, tmp.len - next)
when not defined(nimHasEnforceNoRaises):
{.pragma: enforceNoRaises.}
func addInt*(result: var string, x: uint64) {.enforceNoRaises.} =
when nimvm: addIntImpl(result, x)

View File

@@ -4,7 +4,13 @@ template toLocation*(result: var string, file: string | cstring, line: int, col:
## avoids spurious allocations
# Hopefully this can be re-used everywhere so that if a user needs to customize,
# it can be done in a single place.
result.add file
when file is cstring:
var i = 0
while file[i] != '\0':
add(result, file[i])
inc i
else:
result.add file
if line > 0:
result.add "("
addInt(result, line)

View File

@@ -1740,6 +1740,28 @@ when not defined(nimscript):
when not declared(sysFatal):
include "system/fatal"
proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.}
## Writes and flushes the parameters to the standard output.
##
## Special built-in that takes a variable number of arguments. Each argument
## is converted to a string via `$`, so it works for user-defined
## types that have an overloaded `$` operator.
## It is roughly equivalent to `writeLine(stdout, x); flushFile(stdout)`, but
## available for the JavaScript target too.
##
## Unlike other IO operations this is guaranteed to be thread-safe as
## `echo` is very often used for debugging convenience. If you want to use
## `echo` inside a `proc without side effects
## <manual.html#pragmas-nosideeffect-pragma>`_ you can use `debugEcho
## <#debugEcho,varargs[typed,]>`_ instead.
proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect,
tags: [], raises: [].}
## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule,
## `debugEcho` pretends to be free of side effects, so that it can be used
## for debugging routines marked as `noSideEffect
## <manual.html#pragmas-nosideeffect-pragma>`_.
type
PFrame* = ptr TFrame ## Represents a runtime frame of the call stack;
## part of the debugger API.
@@ -1754,6 +1776,15 @@ type
when NimStackTraceMsgs:
frameMsgLen*: int ## end position in frameMsgBuf for this frame.
when notJSnotNims and not gotoBasedExceptions:
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point ON THE STACK
status: int
context: C_JmpBuf
SafePoint = TSafePoint
when defined(nimV2):
var
framePtr {.threadvar.}: PFrame
@@ -1766,6 +1797,113 @@ template newException*(exceptn: typedesc, message: string;
## to `message`. Returns the new exception object.
(ref exceptn)(msg: message, parent: parentException)
# we have to compute this here before turning it off in except.nim anyway ...
const NimStackTrace = compileOption("stacktrace")
const
usesDestructors = defined(gcDestructors) or defined(gcHooks)
include "system/gc_interface"
when notJSnotNims:
proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.}
## Allows you to override the behaviour of your application when CTRL+C
## is pressed. Only one such hook is supported.
##
## The handler runs inside a C signal handler and comes with similar
## limitations.
##
## Allocating memory and interacting with most system calls, including using
## `echo`, `string`, `seq`, raising or catching exceptions etc is undefined
## behavior and will likely lead to application crashes.
##
## The OS may call the ctrl-c handler from any thread, including threads
## that were not created by Nim, such as happens on Windows.
##
## ## Example:
##
## ```nim
## var stop: Atomic[bool]
## proc ctrlc() {.noconv.} =
## # Using atomics types is safe!
## stop.store(true)
##
## setControlCHook(ctrlc)
##
## while not stop.load():
## echo "Still running.."
## sleep(1000)
## ```
when not defined(noSignalHandler) and not defined(useNimRtl):
proc unsetControlCHook*()
## Reverts a call to setControlCHook.
when hostOS != "standalone":
proc getStackTrace*(): string {.gcsafe.}
## Gets the current stack trace. This only works for debug builds.
proc getStackTrace*(e: ref Exception): string {.gcsafe.}
## Gets the stack trace associated with `e`, which is the stack that
## lead to the `raise` statement. This only works for debug builds.
var
globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.}
## With this hook you can influence exception handling on a global level.
## If not nil, every 'raise' statement ends up calling this hook.
##
## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this.
##
## If `globalRaiseHook` returns false, the exception is caught and does
## not propagate further through the call stack.
localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.}
## With this hook you can influence exception handling on a
## thread local level.
## If not nil, every 'raise' statement ends up calling this hook.
##
## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this.
##
## If `localRaiseHook` returns false, the exception
## is caught and does not propagate further through the call stack.
outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].}
## Set this variable to provide a procedure that should be called
## in case of an `out of memory`:idx: event. The standard handler
## writes an error message and terminates the program.
##
## `outOfMemHook` can be used to raise an exception in case of OOM like so:
##
## ```nim
## var gOutOfMem: ref EOutOfMemory
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
## gOutOfMem.msg = "out of memory"
##
## proc handleOOM() =
## raise gOutOfMem
##
## system.outOfMemHook = handleOOM
## ```
##
## If the handler does not raise an exception, ordinary control flow
## continues and the program is terminated.
unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].}
## Set this variable to provide a procedure that should be called
## in case of an `unhandle exception` event. The standard handler
## writes an error message and terminates the program, except when
## using `--os:any`
{.push stackTrace: off, profiler: off.}
when defined(memtracker):
include "system/memtracker"
when hostOS == "standalone":
include "system/embedded"
else:
include "system/excpt"
{.pop.}
when not defined(nimPreviewSlimSystem):
import std/assertions
export assertions
@@ -1842,11 +1980,6 @@ proc `<`*[T: tuple](x, y: T): bool =
return false
include "system/gc_interface"
# we have to compute this here before turning it off in except.nim anyway ...
const NimStackTrace = compileOption("stacktrace")
import system/coro_detection
{.push checks: off.}
@@ -1855,53 +1988,6 @@ import system/coro_detection
# however, stack-traces are available for most parts
# of the code
when notJSnotNims:
var
globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.}
## With this hook you can influence exception handling on a global level.
## If not nil, every 'raise' statement ends up calling this hook.
##
## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this.
##
## If `globalRaiseHook` returns false, the exception is caught and does
## not propagate further through the call stack.
localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.}
## With this hook you can influence exception handling on a
## thread local level.
## If not nil, every 'raise' statement ends up calling this hook.
##
## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this.
##
## If `localRaiseHook` returns false, the exception
## is caught and does not propagate further through the call stack.
outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].}
## Set this variable to provide a procedure that should be called
## in case of an `out of memory`:idx: event. The standard handler
## writes an error message and terminates the program.
##
## `outOfMemHook` can be used to raise an exception in case of OOM like so:
##
## ```nim
## var gOutOfMem: ref EOutOfMemory
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
## gOutOfMem.msg = "out of memory"
##
## proc handleOOM() =
## raise gOutOfMem
##
## system.outOfMemHook = handleOOM
## ```
##
## If the handler does not raise an exception, ordinary control flow
## continues and the program is terminated.
unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].}
## Set this variable to provide a procedure that should be called
## in case of an `unhandle exception` event. The standard handler
## writes an error message and terminates the program, except when
## using `--os:any`
when defined(js) or defined(nimdoc):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
## Appends `y` to `x` in place.
@@ -1938,27 +2024,6 @@ elif hasAlloc:
inc(i)
{.pop.}
proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.}
## Writes and flushes the parameters to the standard output.
##
## Special built-in that takes a variable number of arguments. Each argument
## is converted to a string via `$`, so it works for user-defined
## types that have an overloaded `$` operator.
## It is roughly equivalent to `writeLine(stdout, x); flushFile(stdout)`, but
## available for the JavaScript target too.
##
## Unlike other IO operations this is guaranteed to be thread-safe as
## `echo` is very often used for debugging convenience. If you want to use
## `echo` inside a `proc without side effects
## <manual.html#pragmas-nosideeffect-pragma>`_ you can use `debugEcho
## <#debugEcho,varargs[typed,]>`_ instead.
proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect,
tags: [], raises: [].}
## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule,
## `debugEcho` pretends to be free of side effects, so that it can be used
## for debugging routines marked as `noSideEffect
## <manual.html#pragmas-nosideeffect-pragma>`_.
when hostOS == "standalone" and defined(nogc):
proc nimToCStringConv(s: NimString): cstring {.compilerproc, inline.} =
@@ -2028,6 +2093,16 @@ template unlikely*(val: bool): bool =
import system/dollars
export dollars
when notJSnotNims:
{.push stackTrace: off, profiler: off.}
include "system/chcks"
# we cannot compile this with stack tracing on
# as it would recurse endlessly!
include "system/integerops"
{.pop.}
when defined(nimAuditDelete):
{.pragma: auditDelete, deprecated: "review this call for out of bounds behavior".}
else:
@@ -2110,17 +2185,17 @@ when notJSnotNims:
nimZeroMem(p, size)
when declared(memTrackerOp):
memTrackerOp("zeroMem", p, size)
proc copyMem(dest, source: pointer, size: Natural) =
proc copyMem(dest, source: pointer, size: Natural) {.enforceNoRaises.} =
nimCopyMem(dest, source, size)
when declared(memTrackerOp):
memTrackerOp("copyMem", dest, size)
proc moveMem(dest, source: pointer, size: Natural) =
proc moveMem(dest, source: pointer, size: Natural) {.enforceNoRaises.} =
c_memmove(dest, source, csize_t(size))
when declared(memTrackerOp):
memTrackerOp("moveMem", dest, size)
proc equalMem(a, b: pointer, size: Natural): bool =
proc equalMem(a, b: pointer, size: Natural): bool {.enforceNoRaises.} =
nimCmpMem(a, b, size) == 0
proc cmpMem(a, b: pointer, size: Natural): int =
proc cmpMem(a, b: pointer, size: Natural): int {.enforceNoRaises.} =
nimCmpMem(a, b, size).int
when not defined(js) or defined(nimscript):
@@ -2173,15 +2248,6 @@ when not defined(js) and declared(alloc0) and declared(dealloc):
inc(i)
dealloc(a)
when notJSnotNims and not gotoBasedExceptions:
type
PSafePoint = ptr TSafePoint
TSafePoint {.compilerproc, final.} = object
prev: PSafePoint # points to next safe point ON THE STACK
status: int
context: C_JmpBuf
SafePoint = TSafePoint
when not defined(js):
when hasThreadSupport:
when hostOS != "standalone":
@@ -2194,63 +2260,6 @@ when not defined(js):
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
when declared(initGC): initGC()
when notJSnotNims:
proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.}
## Allows you to override the behaviour of your application when CTRL+C
## is pressed. Only one such hook is supported.
##
## The handler runs inside a C signal handler and comes with similar
## limitations.
##
## Allocating memory and interacting with most system calls, including using
## `echo`, `string`, `seq`, raising or catching exceptions etc is undefined
## behavior and will likely lead to application crashes.
##
## The OS may call the ctrl-c handler from any thread, including threads
## that were not created by Nim, such as happens on Windows.
##
## ## Example:
##
## ```nim
## var stop: Atomic[bool]
## proc ctrlc() {.noconv.} =
## # Using atomics types is safe!
## stop.store(true)
##
## setControlCHook(ctrlc)
##
## while not stop.load():
## echo "Still running.."
## sleep(1000)
## ```
when not defined(noSignalHandler) and not defined(useNimRtl):
proc unsetControlCHook*()
## Reverts a call to setControlCHook.
when hostOS != "standalone":
proc getStackTrace*(): string {.gcsafe.}
## Gets the current stack trace. This only works for debug builds.
proc getStackTrace*(e: ref Exception): string {.gcsafe.}
## Gets the stack trace associated with `e`, which is the stack that
## lead to the `raise` statement. This only works for debug builds.
{.push stackTrace: off, profiler: off.}
when defined(memtracker):
include "system/memtracker"
when hostOS == "standalone":
include "system/embedded"
else:
include "system/excpt"
include "system/chcks"
# we cannot compile this with stack tracing on
# as it would recurse endlessly!
include "system/integerops"
{.pop.}
when not defined(js):
# this is a hack: without this when statement, you would get:

View File

@@ -42,18 +42,22 @@ proc writeToStdErr(msg: string) {.inline.} =
# fix bug #13115: handles correctly '\0' unlike default implicit conversion to cstring
writeToStdErr(msg.cstring, msg.len)
proc cstrToStrBuiltin(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
when defined(genode):
template `$`(s: string): string = s
proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} =
var toWrite = true
if errorMessageWriter != nil:
try:
errorMessageWriter($data)
errorMessageWriter(cstrToStrBuiltin data)
toWrite = false
except:
discard
if toWrite:
when defined(genode):
# stderr not available by default, use the LOG session
echo data
echo cstrToStrBuiltin(data)
else:
writeToStdErr(data, length)
@@ -261,7 +265,10 @@ template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) =
var oldLen = s.len
s.toLocation(f.filename, f.line, 0)
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
add(s, f.procname)
var i = 0
while f.procname[i] != '\0':
add(s, f.procname[i])
inc i
when NimStackTraceMsgs:
when typeof(f) is StackTraceEntry:
add(s, f.frameMsg)
@@ -282,9 +289,35 @@ proc `$`(stackTraceEntries: seq[StackTraceEntry]): string =
elif s[i].line == reraisedFromEnd: result.add "]]\n"
else: addFrameEntry(result, s[i])
when hasSomeStackTrace:
const
Ten = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
proc auxWriteStackTrace(f: PFrame, s: var string) =
proc i2s(x: int64): string =
# quick reimplementation; optimized for code size, no dependencies
if x < 0:
if x == -9223372036854775808:
result = "-9223372036854775808"
else:
result = "-" & i2s(0-x)
elif x < 10:
result = Ten[int x] # saves allocations
else:
var y = x
while true:
result.add char((y mod 10) + int('0'))
y = y div 10
if y == 0: break
let last = result.len-1
var i = 0
let b = result.len div 2
while i < b:
let ch = result[i]
result[i] = result[last-i]
result[last-i] = ch
inc i
when hasSomeStackTrace:
proc auxWriteStackTrace(f: PFrame, s: var string) {.raises: [].} =
when hasThreadSupport:
var
tempFrames: array[maxStackTraceLines, PFrame] # but better than a threadvar
@@ -322,14 +355,14 @@ when hasSomeStackTrace:
for j in countdown(i-1, 0):
if tempFrames[j] == nil:
add(s, "(")
add(s, $skipped)
s.add(i2s(skipped))
add(s, " calls omitted) ...\n")
else:
addFrameEntry(s, tempFrames[j])
proc stackTraceAvailable*(): bool
proc rawWriteStackTrace(s: var string) =
proc rawWriteStackTrace(s: var string) {.raises: [].} =
when defined(nimStackTraceOverride):
add(s, "Traceback (most recent call last, using override)\n")
auxWriteStackTraceWithOverride(s)
@@ -388,7 +421,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
add(buf, "Error: unhandled exception: ")
add(buf, e.msg)
add(buf, " [")
add(buf, $e.name)
add(buf, cstrToStrBuiltin(e.name))
add(buf, "]\n")
if onUnhandledException != nil:
@@ -418,7 +451,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
xadd(buf, e.name, e.name.len)
add(buf, "]\n")
if onUnhandledException != nil:
onUnhandledException($cast[cstring](buf.addr))
onUnhandledException(cstrToStrBuiltin(cast[cstring](buf.addr)))
else:
showErrorMessage(cast[cstring](buf.addr), L)
@@ -515,8 +548,7 @@ proc reraiseException() {.compilerRtl.} =
else:
raiseExceptionAux(currException)
proc threadTrouble() =
# also forward declared, it is 'raises: []' hence the try-except.
proc threadTrouble() {.raises: [], gcsafe.} =
try:
if currException != nil: reportUnhandledError(currException)
except:
@@ -559,13 +591,16 @@ const nimCallDepthLimit {.intdefine.} = 2000
proc callDepthLimitReached() {.noinline.} =
writeStackTrace()
let msg = "Error: call depth limit reached in a debug build (" &
$nimCallDepthLimit & " function calls). You can change it with " &
"-d:nimCallDepthLimit=<int> but really try to avoid deep " &
"recursions instead.\n"
var msg = "Error: call depth limit reached in a debug build ("
msg.add(i2s(nimCallDepthLimit))
msg.add(" function calls). You can change it with " &
"-d:nimCallDepthLimit=<int> but really try to avoid deep " &
"recursions instead.\n")
showErrorMessage2(msg)
rawQuit(1)
{.push overflowChecks: off.}
proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} =
if framePtr == nil:
s.calldepth = 0
@@ -577,6 +612,8 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} =
framePtr = s
if s.calldepth == nimCallDepthLimit: callDepthLimitReached()
{.pop.}
when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
not defined(js) and not defined(nimscript) and
hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and
@@ -601,9 +638,9 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and
{.emit: "#endif".}
except Exception:
msg = currException.getStackTrace() & "Error: unhandled exception: " &
currException.msg & " [" & $currException.name & "]"
currException.msg & " [" & cstrToStrBuiltin(currException.name) & "]"
except StdException as e:
msg = "Error: unhandled cpp exception: " & $e.what()
msg = "Error: unhandled cpp exception: " & cstrToStrBuiltin(e.what())
except:
msg = "Error: unhandled unknown cpp exception"

View File

@@ -1,6 +1,4 @@
# ----------------- GC interface ---------------------------------------------
const
usesDestructors = defined(gcDestructors) or defined(gcHooks)
when not usesDestructors:
{.pragma: nodestroy.}

View File

@@ -1,13 +1,13 @@
when notJSnotNims:
proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect,
tags: [], raises: [].}
tags: [], raises: [], enforceNoRaises.}
## Overwrites the contents of the memory at `p` with the value 0.
##
## Exactly `size` bytes will be overwritten. Like any procedure
## dealing with raw memory this is **unsafe**.
proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign,
tags: [], raises: [].}
tags: [], raises: [], enforceNoRaises.}
## Copies the contents from the memory at `source` to the memory
## at `dest`.
## Exactly `size` bytes will be copied. The memory
@@ -15,7 +15,7 @@ when notJSnotNims:
## memory this is **unsafe**.
proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign,
tags: [], raises: [].}
tags: [], raises: [], enforceNoRaises.}
## Copies the contents from the memory at `source` to the memory
## at `dest`.
##
@@ -25,7 +25,7 @@ when notJSnotNims:
## dealing with raw memory this is still **unsafe**, though.
proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect,
tags: [], raises: [].}
tags: [], raises: [], enforceNoRaises.}
## Compares the memory blocks `a` and `b`. `size` bytes will
## be compared.
##
@@ -34,7 +34,7 @@ when notJSnotNims:
## **unsafe**.
proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect,
tags: [], raises: [].}
tags: [], raises: [], enforceNoRaises.}
## Compares the memory blocks `a` and `b`. `size` bytes will
## be compared.
##

View File

@@ -5,7 +5,7 @@ const useLibC = not defined(nimNoLibc)
when useLibC:
import ansi_c
proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} =
proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline, enforceNoRaises.} =
when useLibC:
c_memcpy(dest, source, cast[csize_t](size))
else:
@@ -16,7 +16,7 @@ proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compiler
d[i] = s[i]
inc i
proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} =
proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline, enforceNoRaises.} =
when useLibC:
c_memset(a, v, cast[csize_t](size))
else:
@@ -27,10 +27,10 @@ proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} =
a[i] = v
inc i
proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline.} =
proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline, enforceNoRaises.} =
nimSetMem(p, 0, size)
proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} =
proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline, enforceNoRaises.} =
when useLibC:
c_memcmp(a, b, cast[csize_t](size))
else:
@@ -42,7 +42,7 @@ proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadabl
if d != 0: return d
inc i
proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} =
proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline, enforceNoRaises.} =
if a.isNil: return 0
when useLibC:
cast[int](c_strlen(a))

View File

@@ -62,22 +62,23 @@ when defined(nimStackTraceOverride):
let programCounters = stackTraceOverrideGetProgramCounters(maxStackTraceLines)
if s.len == 0:
s = newSeqOfCap[StackTraceEntry](programCounters.len)
for programCounter in programCounters:
s.add(StackTraceEntry(programCounter: cast[uint](programCounter)))
for i in 0..<programCounters.len:
s.add(StackTraceEntry(programCounter: cast[uint](programCounters[i])))
# We may have more stack trace lines in the output, due to inlined procedures.
proc addDebuggingInfo*(s: seq[StackTraceEntry]): seq[StackTraceEntry] =
var programCounters: seq[cuintptr_t]
# We process program counters in groups from complete stack traces, because
# we have logic that keeps track of certain functions being inlined or not.
for entry in s:
for i in 0..<s.len:
let entry = addr s[i]
if entry.procname.isNil and entry.programCounter != 0:
programCounters.add(cast[cuintptr_t](entry.programCounter))
elif entry.procname.isNil and (entry.line == reraisedFromBegin or entry.line == reraisedFromEnd):
result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
programCounters = @[]
result.add(entry)
result.add(entry[])
else:
result.add(entry)
result.add(entry[])
if programCounters.len > 0:
result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))

View File

@@ -23,6 +23,8 @@ type
const nimStrVersion {.core.} = 2
{.push overflowChecks: off, rangeChecks: off.}
template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag
template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase)
@@ -227,3 +229,5 @@ func capacity*(self: string): int {.inline.} =
let str = cast[ptr NimStringV2](unsafeAddr self)
result = if str.p != nil: str.p.cap and not strlitFlag else: 0
{.pop.}

View File

@@ -2,7 +2,7 @@ var
nimThreadDestructionHandlers* {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}]
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions):
proc deallocOsPages() {.rtl, raises: [].}
proc threadTrouble() {.raises: [], gcsafe.}
# create for the main thread. Note: do not insert this data into the list
# of all threads; it's not to be stopped etc.
when not defined(useNimRtl):

View File

@@ -6,8 +6,8 @@ const expected = """
wrong trace:
t23536.nim(22) t23536
t23536.nim(17) foo
assertions.nim(41) failedAssertImpl
assertions.nim(36) raiseAssert
assertions.nim(45) failedAssertImpl
assertions.nim(40) raiseAssert
fatal.nim(53) sysFatal
"""

View File

@@ -4,8 +4,8 @@ discard """
t24974.nim(22) t24974
t24974.nim(19) d
t24974.nim(16) s
assertions.nim(41) failedAssertImpl
assertions.nim(36) raiseAssert
assertions.nim(45) failedAssertImpl
assertions.nim(40) raiseAssert
fatal.nim(53) sysFatal
Error: unhandled exception: t24974.nim(16, 26) `false` [AssertionDefect]
'''
@@ -19,4 +19,4 @@ proc d(): B =
if s(k): discard
quit 0
k
for _ in [0]: discard d()
for _ in [0]: discard d()