mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-26 17:24:02 +00:00
Resolve merge conflicts with devel branch refactoring (#25423)
The PR branch had merge conflicts with `devel` due to a major compiler refactoring that extracted type definitions from `compiler/ast.nim` into a new `compiler/astdef.nim` file. ## Changes - Resolved conflict in `compiler/ast.nim` by accepting `devel`'s refactored structure - Merged 763 commits from `devel` branch (commit range: `ce6a345..b3273e7`) - Preserved original PR changes removing deprecated symbols from `lib/core/macros.nim` The core PR functionality (removal of deprecated macros API since v0.18.1) remains intact while incorporating the upstream AST refactoring. <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
{.push profiler:off.}
|
||||
|
||||
include osalloc
|
||||
import std/private/syslocks
|
||||
|
||||
template track(op, address, size) =
|
||||
when defined(memTracker):
|
||||
@@ -837,6 +836,15 @@ when defined(gcDestructors):
|
||||
dec maxIters
|
||||
if it == nil: break
|
||||
|
||||
when defined(heaptrack):
|
||||
const heaptrackLib =
|
||||
when defined(heaptrack_inject):
|
||||
"libheaptrack_inject.so"
|
||||
else:
|
||||
"libheaptrack_preload.so"
|
||||
proc heaptrack_malloc(a: pointer, size: int) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
proc heaptrack_free(a: pointer) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
|
||||
proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
when defined(nimTypeNames):
|
||||
inc(a.allocCounter)
|
||||
@@ -959,6 +967,8 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
sysAssert(isAccessible(a, result), "rawAlloc 14")
|
||||
sysAssert(allocInv(a), "rawAlloc: end")
|
||||
when logAlloc: cprintf("var pointer_%p = alloc(%ld) # %p\n", result, requestedSize, addr a)
|
||||
when defined(heaptrack):
|
||||
heaptrack_malloc(result, requestedSize)
|
||||
|
||||
proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
|
||||
result = rawAlloc(a, requestedSize)
|
||||
@@ -967,6 +977,8 @@ proc rawAlloc0(a: var MemRegion, requestedSize: int): pointer =
|
||||
proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
when defined(nimTypeNames):
|
||||
inc(a.deallocCounter)
|
||||
when defined(heaptrack):
|
||||
heaptrack_free(p)
|
||||
#sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
|
||||
sysAssert(allocInv(a), "rawDealloc: begin")
|
||||
var c = pageAddr(p)
|
||||
|
||||
@@ -14,7 +14,7 @@ at offset 0 then. The ``ref`` object header is independent from the
|
||||
runtime type and only contains a reference count.
|
||||
]#
|
||||
|
||||
{.push raises: [].}
|
||||
{.push raises: [], rangeChecks: off.}
|
||||
|
||||
when defined(gcOrc):
|
||||
const
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
|
||||
{.push stack_trace: off.}
|
||||
|
||||
proc succ*[T: Ordinal, V: SomeInteger](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
|
||||
## Returns the `y`-th successor (default: 1) of the value `x`.
|
||||
##
|
||||
## If such a value does not exist, `OverflowDefect` is raised
|
||||
@@ -7,7 +9,7 @@ proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
|
||||
assert succ(5) == 6
|
||||
assert succ(5, 3) == 8
|
||||
|
||||
proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
|
||||
proc pred*[T: Ordinal, V: SomeInteger](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
|
||||
## Returns the `y`-th predecessor (default: 1) of the value `x`.
|
||||
##
|
||||
## If such a value does not exist, `OverflowDefect` is raised
|
||||
@@ -16,7 +18,7 @@ proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
|
||||
assert pred(5) == 4
|
||||
assert pred(5, 3) == 2
|
||||
|
||||
proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
|
||||
proc inc*[T: Ordinal, V: SomeInteger](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
|
||||
## Increments the ordinal `x` by `y`.
|
||||
##
|
||||
## If such a value does not exist, `OverflowDefect` is raised or a compile
|
||||
@@ -28,7 +30,7 @@ proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
|
||||
inc(i, 3)
|
||||
assert i == 6
|
||||
|
||||
proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} =
|
||||
proc dec*[T: Ordinal, V: SomeInteger](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} =
|
||||
## Decrements the ordinal `x` by `y`.
|
||||
##
|
||||
## If such a value does not exist, `OverflowDefect` is raised or a compile
|
||||
@@ -134,7 +136,10 @@ when defined(nimOldShiftRight):
|
||||
else:
|
||||
proc `shr`*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} =
|
||||
## Computes the `shift right` operation of `x` and `y`, filling
|
||||
## vacant bit positions with the sign bit.
|
||||
## vacant bit positions with the sign bit. `y` (the number of
|
||||
## positions to shift) is reduced to modulo `sizeof(x) * 8`.
|
||||
## That is `15'i32 shr 35` is equivalent to `15'i32 shr 3`
|
||||
## bitmasked to always be in the range `0 ..< sizeof(int)`.
|
||||
##
|
||||
## **Note**: `Operator precedence <manual.html#syntax-precedence>`_
|
||||
## is different than in *C*.
|
||||
@@ -156,7 +161,9 @@ else:
|
||||
|
||||
|
||||
proc `shl`*(x: int, y: SomeInteger): int {.magic: "ShlI", noSideEffect.} =
|
||||
## Computes the `shift left` operation of `x` and `y`.
|
||||
## Computes the `shift left` operation of `x` and `y`. `y` (the number of
|
||||
## positions to shift) is reduced to modulo `sizeof(x) * 8`.
|
||||
## That is `15'i32 shl 35` is equivalent to `15'i32 shl 3`.
|
||||
##
|
||||
## **Note**: `Operator precedence <manual.html#syntax-precedence>`_
|
||||
## is different than in *C*.
|
||||
@@ -170,7 +177,9 @@ proc `shl`*(x: int64, y: SomeInteger): int64 {.magic: "ShlI", noSideEffect.}
|
||||
|
||||
proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} =
|
||||
## Shifts right by pushing copies of the leftmost bit in from the left,
|
||||
## and let the rightmost bits fall off.
|
||||
## and let the rightmost bits fall off. `y` (the number of
|
||||
## positions to shift) is reduced to modulo `sizeof(x) * 8`.
|
||||
## That is `ashr(15'i32, 35)` is equivalent to `ashr(15'i32, 3)`.
|
||||
##
|
||||
## Note that `ashr` is not an operator so use the normal function
|
||||
## call syntax for it.
|
||||
@@ -179,7 +188,7 @@ proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} =
|
||||
## * `shr func<#shr,int,SomeInteger>`_
|
||||
runnableExamples:
|
||||
assert ashr(0b0001_0000'i8, 2) == 0b0000_0100'i8
|
||||
assert ashr(0b1000_0000'i8, 8) == 0b1111_1111'i8
|
||||
assert ashr(0b1000_0000'i8, 8) == 0b1000_0000'i8
|
||||
assert ashr(0b1000_0000'i8, 1) == 0b1100_0000'i8
|
||||
proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.}
|
||||
proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.}
|
||||
@@ -403,3 +412,5 @@ proc `%%`*(x, y: int8): int8 {.inline.} = cast[int8](cast[uint8](x) mod cast[u
|
||||
proc `%%`*(x, y: int16): int16 {.inline.} = cast[int16](cast[uint16](x) mod cast[uint16](y))
|
||||
proc `%%`*(x, y: int32): int32 {.inline.} = cast[int32](cast[uint32](x) mod cast[uint32](y))
|
||||
proc `%%`*(x, y: int64): int64 {.inline.} = cast[int64](cast[uint64](x) mod cast[uint64](y))
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -138,11 +138,11 @@
|
||||
## localChannelExample() # "Hello from the main thread!"
|
||||
## ```
|
||||
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
when not declared(ThisIsSystem):
|
||||
{.error: "You must not import this module explicitly".}
|
||||
|
||||
import std/private/syslocks
|
||||
|
||||
type
|
||||
pbytes = ptr UncheckedArray[byte]
|
||||
RawChannel {.pure, final.} = object ## msg queue for a thread
|
||||
@@ -365,23 +365,35 @@ proc sendImpl(q: PRawChannel, typ: PNimType, msg: pointer, noBlock: bool): bool
|
||||
releaseSys(q.lock)
|
||||
result = true
|
||||
|
||||
proc send*[TMsg](c: var Channel[TMsg], msg: sink TMsg) {.inline.} =
|
||||
## Sends a message to a thread. `msg` is deeply copied.
|
||||
discard sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), false)
|
||||
when defined(gcDestructors):
|
||||
when defined(gcDestructors):
|
||||
proc send*[TMsg](c: var Channel[TMsg], msg: sink TMsg) {.inline.} =
|
||||
## Sends a message to a thread.
|
||||
discard sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), false)
|
||||
wasMoved(msg)
|
||||
|
||||
proc trySend*[TMsg](c: var Channel[TMsg], msg: sink TMsg): bool {.inline.} =
|
||||
## Tries to send a message to a thread.
|
||||
##
|
||||
## `msg` is deeply copied. Doesn't block.
|
||||
##
|
||||
## Returns `false` if the message was not sent because number of pending items
|
||||
## in the channel exceeded `maxItems`.
|
||||
result = sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true)
|
||||
when defined(gcDestructors):
|
||||
proc trySend*[TMsg](c: var Channel[TMsg], msg: sink TMsg): bool {.inline.} =
|
||||
## Tries to send a message to a thread.
|
||||
##
|
||||
## Doesn't block.
|
||||
##
|
||||
## Returns `false` if the message was not sent because number of pending items
|
||||
## in the channel exceeded `maxItems`.
|
||||
result = sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true)
|
||||
if result:
|
||||
wasMoved(msg)
|
||||
else:
|
||||
proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) {.inline.} =
|
||||
## Sends a message to a thread. `msg` is deeply copied.
|
||||
discard sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), false)
|
||||
|
||||
proc trySend*[TMsg](c: var Channel[TMsg], msg: TMsg): bool {.inline.} =
|
||||
## Tries to send a message to a thread.
|
||||
##
|
||||
## `msg` is deeply copied. Doesn't block.
|
||||
##
|
||||
## Returns `false` if the message was not sent because number of pending items
|
||||
## in the channel exceeded `maxItems`.
|
||||
result = sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true)
|
||||
|
||||
proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
|
||||
q.ready = true
|
||||
@@ -390,7 +402,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
|
||||
q.ready = false
|
||||
if typ != q.elemType:
|
||||
releaseSys(q.lock)
|
||||
raise newException(ValueError, "cannot receive message of wrong type")
|
||||
raiseAssert "cannot receive message of wrong type"
|
||||
rawRecv(q, res, typ)
|
||||
if q.maxItems > 0 and q.count == q.maxItems - 1:
|
||||
# Parent thread is awaiting in send. Wake it up.
|
||||
@@ -455,3 +467,5 @@ proc ready*[TMsg](c: var Channel[TMsg]): bool =
|
||||
## new messages.
|
||||
var q = cast[PRawChannel](addr(c))
|
||||
result = q.ready
|
||||
|
||||
{.pop.}
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
# Implementation of some runtime checks.
|
||||
include system/indexerrors
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/formatfloat
|
||||
|
||||
proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
|
||||
when hostOS == "standalone":
|
||||
@@ -53,12 +51,6 @@ proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} =
|
||||
else:
|
||||
sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b)
|
||||
|
||||
proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} =
|
||||
when defined(standalone):
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
else:
|
||||
sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b)
|
||||
|
||||
proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} =
|
||||
# todo: better error reporting
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
@@ -97,16 +89,6 @@ proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} =
|
||||
result = 0
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
|
||||
proc chckRangeF(x, a, b: float): float =
|
||||
if x >= a and x <= b:
|
||||
return x
|
||||
else:
|
||||
result = 0.0
|
||||
when hostOS == "standalone":
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
else:
|
||||
sysFatal(RangeDefect, "value out of range: ", $x)
|
||||
|
||||
proc chckNil(p: pointer) =
|
||||
if p == nil:
|
||||
sysFatal(NilAccessDefect, "attempt to write to a nil address")
|
||||
@@ -164,3 +146,30 @@ when not defined(nimV2):
|
||||
when defined(nimV2):
|
||||
proc raiseObjectCaseTransition() {.compilerproc.} =
|
||||
sysFatal(FieldDefect, "assignment to discriminant changes object branch")
|
||||
|
||||
import std/formatfloat
|
||||
|
||||
when not defined(nimPreviewSlimSystem):
|
||||
export addFloat
|
||||
|
||||
func f2s(x: float | float32): string =
|
||||
## Outplace version of `addFloat`.
|
||||
result = ""
|
||||
result.addFloat(x)
|
||||
|
||||
|
||||
proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} =
|
||||
when defined(standalone):
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
else:
|
||||
sysFatal(RangeDefect, "value out of range: " & f2s(i) & " notin " & f2s(a) & " .. " & f2s(b))
|
||||
|
||||
proc chckRangeF(x, a, b: float): float =
|
||||
if x >= a and x <= b:
|
||||
return x
|
||||
else:
|
||||
result = 0.0
|
||||
when hostOS == "standalone":
|
||||
sysFatal(RangeDefect, "value out of range")
|
||||
else:
|
||||
sysFatal(RangeDefect, "value out of range: ", f2s(x))
|
||||
|
||||
@@ -85,9 +85,3 @@ func countSetBitsImpl*(x: SomeInteger): int {.inline.} =
|
||||
else:
|
||||
when sizeof(x) <= 4: result = countBitsImpl(x.uint32)
|
||||
else: result = countBitsImpl(x.uint64)
|
||||
|
||||
proc countBits32*(n: uint32): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc countBits64*(n: uint64): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# However, the interface has been designed to take platform differences into
|
||||
# account and been ported to all major platforms.
|
||||
|
||||
{.push stack_trace: off.}
|
||||
{.push stack_trace: off, checks: off.}
|
||||
|
||||
const
|
||||
NilLibHandle: LibHandle = nil
|
||||
|
||||
@@ -22,10 +22,6 @@ var
|
||||
## instead of `stdmsg.write` when printing stacktrace.
|
||||
## Unstable API.
|
||||
|
||||
when defined(windows):
|
||||
proc GetLastError(): int32 {.header: "<windows.h>", nodecl.}
|
||||
const ERROR_BAD_EXE_FORMAT = 193
|
||||
|
||||
when not defined(windows) or not defined(guiapp):
|
||||
proc writeToStdErr(msg: cstring) = rawWrite(cstderr, msg)
|
||||
proc writeToStdErr(msg: cstring, length: int) =
|
||||
@@ -42,18 +38,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 +261,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 +285,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 +351,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 +417,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 +447,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 +544,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 +587,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 +608,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 +634,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"
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ type
|
||||
waZctDecRef, waPush
|
||||
#, waDebug
|
||||
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].}
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [], gcsafe.}
|
||||
# A ref type can have a finalizer that is called before the object's
|
||||
# storage is freed.
|
||||
|
||||
@@ -481,17 +481,17 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||
{.pop.} # .stackTrace off
|
||||
{.pop.} # .profiler off
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline, raises: [].} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
@@ -500,7 +500,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
{.pop.}
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline, raises: [].} =
|
||||
# generates a new object and sets its reference counter to 1
|
||||
incTypeSize typ, size
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||
@@ -528,7 +528,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObjRC1(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
@@ -670,7 +670,7 @@ proc doOperation(p: pointer, op: WalkOp) =
|
||||
add(gch.tempStack, c)
|
||||
#of waDebug: debugGraph(c)
|
||||
|
||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl, raises: [].} =
|
||||
doOperation(d, WalkOp(op))
|
||||
|
||||
proc collectZCT(gch: var GcHeap): bool {.benign, raises: [].}
|
||||
|
||||
@@ -46,8 +46,8 @@ var
|
||||
newObjHook*: proc (typ: PNimType, size: int): pointer {.nimcall, tags: [], raises: [], gcsafe.}
|
||||
traverseObjHook*: proc (p: pointer, op: int) {.nimcall, tags: [], raises: [], gcsafe.}
|
||||
|
||||
proc nimGCvisit(p: pointer, op: int) {.inl, compilerRtl.} =
|
||||
proc nimGCvisit(p: pointer, op: int) {.inl, compilerRtl, raises: [].} =
|
||||
traverseObjHook(p, op)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.inl, compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.inl, compilerRtl, raises: [].} =
|
||||
result = newObjHook(typ, size)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# ----------------- GC interface ---------------------------------------------
|
||||
const
|
||||
usesDestructors = defined(gcDestructors) or defined(gcHooks)
|
||||
|
||||
when not usesDestructors:
|
||||
{.pragma: nodestroy.}
|
||||
|
||||
@@ -36,7 +36,7 @@ type
|
||||
# local
|
||||
waMarkPrecise # fast precise marking
|
||||
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].}
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [], gcsafe.}
|
||||
# A ref type can have a finalizer that is called before the object's
|
||||
# storage is freed.
|
||||
|
||||
@@ -289,23 +289,23 @@ when useCellIds:
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
when not defined(nimSeqsV2):
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
@@ -313,7 +313,7 @@ when not defined(nimSeqsV2):
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
@@ -346,7 +346,7 @@ when not defined(nimSeqsV2):
|
||||
result = cellToUsr(res)
|
||||
when defined(memProfiler): nimProfile(newsize-oldsize)
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl, raises: [].} =
|
||||
result = growObj(old, newsize, gch)
|
||||
|
||||
{.push profiler:off.}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
# "Stack GC" for embedded devices or ultra performance requirements.
|
||||
import std/private/syslocks
|
||||
|
||||
@@ -39,7 +41,7 @@ else:
|
||||
# We also support 'finalizers'.
|
||||
|
||||
type
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||
Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [], gcsafe.}
|
||||
# A ref type can have a finalizer that is called before the object's
|
||||
# storage is freed.
|
||||
|
||||
@@ -305,26 +307,26 @@ proc rawNewSeq(r: var MemRegion, typ: PNimType, size: int): pointer =
|
||||
res.region = addr(r)
|
||||
result = res +! sizeof(SeqHeader)
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
sysAssert typ.kind notin {tySequence, tyString}, "newObj cannot be used to construct seqs"
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
sysAssert typ.kind notin {tySequence, tyString}, "newObj cannot be used to construct seqs"
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
let size = roundup(align(GenericSeqSize, typ.base.align) + len * typ.base.size, MemAlign)
|
||||
result = rawNewSeq(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
proc newStr(typ: PNimType, len: int; init: bool): pointer {.compilerRtl.} =
|
||||
proc newStr(typ: PNimType, len: int; init: bool): pointer {.compilerRtl, raises: [].} =
|
||||
let size = roundup(len + GenericSeqSize, MemAlign)
|
||||
result = rawNewSeq(tlRegion, typ, size)
|
||||
if init: zeroMem(result, size)
|
||||
@@ -332,14 +334,14 @@ proc newStr(typ: PNimType, len: int; init: bool): pointer {.compilerRtl.} =
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
{.pop.}
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = rawNewObj(tlRegion, typ, size)
|
||||
zeroMem(result, size)
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl, raises: [].} =
|
||||
result = newSeq(typ, len)
|
||||
|
||||
proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer =
|
||||
proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer {.raises: [].} =
|
||||
let sh = cast[ptr SeqHeader](old -! sizeof(SeqHeader))
|
||||
let typ = sh.typ
|
||||
result = rawNewSeq(sh.region[], typ,
|
||||
@@ -351,7 +353,7 @@ proc growObj(regionUnused: var MemRegion; old: pointer, newsize: int): pointer =
|
||||
copyMem(result, old, oldsize)
|
||||
dealloc(sh.region[], old, roundup(oldsize, MemAlign))
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl, raises: [].} =
|
||||
result = growObj(tlRegion, old, newsize)
|
||||
|
||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||
@@ -434,3 +436,5 @@ proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||
|
||||
proc nimGCref(x: pointer) {.compilerproc.} = discard
|
||||
proc nimGCunref(x: pointer) {.compilerproc.} = discard
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -687,6 +687,14 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
|
||||
proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
|
||||
{.emit: "`x`.push(`c`);".}
|
||||
|
||||
proc nimAddStrStr(x, y: string) {.compilerproc, asmNoStackFrame.} =
|
||||
{.emit: """
|
||||
var L = `y`.length;
|
||||
for (var i = 0; i < L; ++i) {
|
||||
`x`.push(`y`[i]);
|
||||
}
|
||||
""".}
|
||||
|
||||
{.pop.}
|
||||
|
||||
proc tenToThePowerOf(b: int): BiggestFloat =
|
||||
|
||||
@@ -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.
|
||||
##
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
const useLibC = not defined(nimNoLibc)
|
||||
|
||||
when useLibC:
|
||||
import ansi_c
|
||||
import ansi_c
|
||||
|
||||
proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} =
|
||||
proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, inline, enforceNoRaises.} =
|
||||
when useLibC:
|
||||
c_memcpy(dest, source, cast[csize_t](size))
|
||||
else:
|
||||
@@ -16,7 +15,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 +26,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) {.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 {.nonReloadable, inline, enforceNoRaises.} =
|
||||
when useLibC:
|
||||
c_memcmp(a, b, cast[csize_t](size))
|
||||
else:
|
||||
@@ -42,7 +41,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 {.nonReloadable, inline, enforceNoRaises.} =
|
||||
if a.isNil: return 0
|
||||
when useLibC:
|
||||
cast[int](c_strlen(a))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
|
||||
proc boehmGCinit {.importc: "GC_init", boehmGC.}
|
||||
@@ -95,7 +95,7 @@ proc initGC() =
|
||||
when hasThreadSupport:
|
||||
boehmGC_allow_register_threads()
|
||||
|
||||
proc boehmgc_finalizer(obj: pointer, typedFinalizer: (proc(x: pointer) {.cdecl.})) =
|
||||
proc boehmgc_finalizer(obj: pointer, typedFinalizer: (proc(x: pointer) {.cdecl, raises: [], gcsafe.})) =
|
||||
typedFinalizer(obj)
|
||||
|
||||
|
||||
@@ -138,3 +138,5 @@ proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||
proc deallocOsPages() {.inline.} = discard
|
||||
|
||||
include "system/cellsets"
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
when defined(windows):
|
||||
const goLib = "libgo.dll"
|
||||
@@ -151,3 +152,5 @@ proc alloc0(r: var MemRegion, size: int): pointer =
|
||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||
proc deallocOsPages() {.inline.} = discard
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -20,7 +20,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||
result = alloc(size)
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc, raises: [].} =
|
||||
result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
@@ -60,10 +60,10 @@ elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
|
||||
|
||||
when defined(nogc):
|
||||
proc GC_getStatistics(): string = ""
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc, raises: [].} =
|
||||
result = alloc0(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc, raises: [].} =
|
||||
result = newObj(typ, align(GenericSeqSize, typ.align) + len * typ.base.size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
proc roundup(x, v: int): int {.inline.} =
|
||||
result = (x + (v-1)) and not (v-1)
|
||||
sysAssert(result >= x, "roundup: result < x")
|
||||
@@ -216,3 +218,5 @@ elif hostOS == "standalone" or defined(StandaloneHeapSize):
|
||||
|
||||
else:
|
||||
{.error: "Port memory manager to your platform".}
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
# set handling
|
||||
|
||||
|
||||
# IC: compilerprocs now must be defined in system.nim or threadpool.nim!
|
||||
proc countBits32*(n: uint32): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc countBits64*(n: uint64): int {.compilerproc, inline.} =
|
||||
result = countSetBitsImpl(n)
|
||||
|
||||
proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
|
||||
var i = 0
|
||||
result = 0
|
||||
|
||||
@@ -29,6 +29,8 @@ when defined(nimStackTraceOverride):
|
||||
proc (programCounters: seq[cuintptr_t], maxLength: cint): seq[StackTraceEntry] {.
|
||||
nimcall, gcsafe, raises: [], tags: [], noinline.}
|
||||
|
||||
|
||||
|
||||
# Default procedures (not normally used, because people opting in on this
|
||||
# override are supposed to register their own versions).
|
||||
var
|
||||
@@ -62,22 +64,34 @@ 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])))
|
||||
|
||||
proc patchStackTraceEntry(x: var StackTraceEntry) =
|
||||
x.procname = x.procnameStr.cstring
|
||||
x.filename = x.filenameStr.cstring
|
||||
|
||||
proc addStackTraceEntrySeq(result: var seq[StackTraceEntry]; s: seq[StackTraceEntry]) =
|
||||
for i in 0..<s.len:
|
||||
result.add(s[i])
|
||||
patchStackTraceEntry(result[result.high])
|
||||
|
||||
# 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))
|
||||
result.addStackTraceEntrySeq(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
|
||||
programCounters = @[]
|
||||
result.add(entry)
|
||||
result.add(entry[])
|
||||
patchStackTraceEntry(result[result.high])
|
||||
else:
|
||||
result.add(entry)
|
||||
result.add(entry[])
|
||||
patchStackTraceEntry(result[result.high])
|
||||
if programCounters.len > 0:
|
||||
result.add(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
|
||||
result.addStackTraceEntrySeq(stackTraceOverrideGetDebuggingInfo(programCounters, maxStackTraceLines))
|
||||
|
||||
@@ -9,19 +9,7 @@
|
||||
|
||||
## Default new string implementation used by Nim's core.
|
||||
|
||||
type
|
||||
NimStrPayloadBase = object
|
||||
cap: int
|
||||
|
||||
NimStrPayload {.core.} = object
|
||||
cap: int
|
||||
data: UncheckedArray[char]
|
||||
|
||||
NimStringV2 {.core.} = object
|
||||
len: int
|
||||
p: ptr NimStrPayload ## can be nil if len == 0.
|
||||
|
||||
const nimStrVersion {.core.} = 2
|
||||
{.push overflowChecks: off, rangeChecks: off.}
|
||||
|
||||
template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag
|
||||
|
||||
@@ -141,6 +129,10 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} =
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
|
||||
## Sets the `s` length to `newLen` zeroing memory on growth.
|
||||
## Terminating zero at `s[newLen]` for cstring compatibility is set
|
||||
## on length change, **excluding** `newLen == 0`.
|
||||
## Negative `newLen` is **not** bound to zero.
|
||||
if newLen == 0:
|
||||
discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations"
|
||||
else:
|
||||
@@ -223,3 +215,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.}
|
||||
|
||||
52
lib/system/sysmem.nim
Normal file
52
lib/system/sysmem.nim
Normal file
@@ -0,0 +1,52 @@
|
||||
{.push stack_trace: off.}
|
||||
|
||||
const useLibC = not defined(nimNoLibc)
|
||||
|
||||
proc nimCopyMem(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline, enforceNoRaises.} =
|
||||
when useLibC:
|
||||
c_memcpy(dest, source, cast[csize_t](size))
|
||||
else:
|
||||
let d = cast[ptr UncheckedArray[byte]](dest)
|
||||
let s = cast[ptr UncheckedArray[byte]](source)
|
||||
var i = 0
|
||||
while i < size:
|
||||
d[i] = s[i]
|
||||
inc i
|
||||
|
||||
proc nimSetMem(a: pointer, v: cint, size: Natural) {.nonReloadable, inline, enforceNoRaises.} =
|
||||
when useLibC:
|
||||
c_memset(a, v, cast[csize_t](size))
|
||||
else:
|
||||
let a = cast[ptr UncheckedArray[byte]](a)
|
||||
var i = 0
|
||||
let v = cast[byte](v)
|
||||
while i < size:
|
||||
a[i] = v
|
||||
inc i
|
||||
|
||||
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, enforceNoRaises.} =
|
||||
when useLibC:
|
||||
c_memcmp(a, b, cast[csize_t](size))
|
||||
else:
|
||||
let a = cast[ptr UncheckedArray[byte]](a)
|
||||
let b = cast[ptr UncheckedArray[byte]](b)
|
||||
var i = 0
|
||||
while i < size:
|
||||
let d = a[i].cint - b[i].cint
|
||||
if d != 0: return d
|
||||
inc i
|
||||
|
||||
proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline, enforceNoRaises.} =
|
||||
if a.isNil: return 0
|
||||
when useLibC:
|
||||
cast[int](c_strlen(a))
|
||||
else:
|
||||
var a = cast[ptr byte](a)
|
||||
while a[] != 0:
|
||||
a = cast[ptr byte](cast[uint](a) + 1)
|
||||
inc result
|
||||
|
||||
{.pop.}
|
||||
@@ -15,6 +15,7 @@
|
||||
# we don't use refcounts because that's a behaviour
|
||||
# the programmer may not want
|
||||
|
||||
{.push raises: [], gcsafe.}
|
||||
|
||||
proc dataPointer(a: PGenericSeq, elemAlign: int): pointer =
|
||||
cast[pointer](cast[int](a) +% align(GenericSeqSize, elemAlign))
|
||||
@@ -48,6 +49,8 @@ else:
|
||||
cast[NimString](newObjNoInit(addr(strDesc), size))
|
||||
|
||||
proc rawNewStringNoInit(space: int): NimString =
|
||||
## Returns a newly-allocated NimString with `reserved` set.
|
||||
## .. warning:: `len` and the terminating null-byte are not set!
|
||||
let s = max(space, 7)
|
||||
result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
|
||||
result.reserved = s
|
||||
@@ -55,11 +58,21 @@ proc rawNewStringNoInit(space: int): NimString =
|
||||
result.elemSize = 1
|
||||
|
||||
proc rawNewString(space: int): NimString {.compilerproc.} =
|
||||
## Returns a newly-allocated and *not* zeroed NimString
|
||||
## with everything required set:
|
||||
## - `reserved`
|
||||
## - `len` (0)
|
||||
## - terminating null-byte
|
||||
result = rawNewStringNoInit(space)
|
||||
result.len = 0
|
||||
result.data[0] = '\0'
|
||||
|
||||
proc mnewString(len: int): NimString {.compilerproc.} =
|
||||
## Returns a newly-allocated and zeroed NimString
|
||||
## with everything required set:
|
||||
## - `reserved`
|
||||
## - `len`
|
||||
## - terminating null-byte
|
||||
result = rawNewStringNoInit(len)
|
||||
result.len = len
|
||||
zeroMem(addr result.data[0], len + 1)
|
||||
@@ -91,29 +104,28 @@ proc toNimStr(str: cstring, len: int): NimString {.compilerproc.} =
|
||||
copyMem(addr(result.data), str, len)
|
||||
result.data[len] = '\0'
|
||||
|
||||
proc toOwnedCopy(src: NimString): NimString {.inline, raises: [].} =
|
||||
## Expects `src` to be not nil and initialized (len and terminating zero set)
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||
if str == nil: NimString(nil)
|
||||
else: toNimStr(str, str.len)
|
||||
|
||||
proc copyString(src: NimString): NimString {.compilerRtl.} =
|
||||
## Expects `src` to be initialized (len and terminating zero set)
|
||||
if src != nil:
|
||||
if (src.reserved and seqShallowFlag) != 0:
|
||||
result = src
|
||||
else:
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||
result = toOwnedCopy(src)
|
||||
sysAssert((seqShallowFlag and result.reserved) == 0, "copyString")
|
||||
when defined(nimShallowStrings):
|
||||
if (src.reserved and strlitFlag) != 0:
|
||||
result.reserved = (result.reserved and not strlitFlag) or seqShallowFlag
|
||||
|
||||
proc newOwnedString(src: NimString; n: int): NimString =
|
||||
result = rawNewStringNoInit(n)
|
||||
result.len = n
|
||||
copyMem(addr(result.data), addr(src.data), n)
|
||||
result.data[n] = '\0'
|
||||
|
||||
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
||||
if src != nil:
|
||||
if (src.reserved and seqShallowFlag) != 0:
|
||||
@@ -129,39 +141,20 @@ proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
||||
result.reserved = s
|
||||
when defined(gogc):
|
||||
result.elemSize = 1
|
||||
result.len = src.len
|
||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||
else:
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||
result = toOwnedCopy(src)
|
||||
sysAssert((seqShallowFlag and result.reserved) == 0, "copyStringRC1")
|
||||
when defined(nimShallowStrings):
|
||||
if (src.reserved and strlitFlag) != 0:
|
||||
result.reserved = (result.reserved and not strlitFlag) or seqShallowFlag
|
||||
|
||||
proc copyDeepString(src: NimString): NimString {.inline.} =
|
||||
proc copyDeepString(src: NimString): NimString {.inline, raises: [].} =
|
||||
if src != nil:
|
||||
result = rawNewStringNoInit(src.len)
|
||||
result.len = src.len
|
||||
copyMem(addr(result.data), addr(src.data), src.len + 1)
|
||||
result = toOwnedCopy(src)
|
||||
|
||||
proc addChar(s: NimString, c: char): NimString =
|
||||
# is compilerproc!
|
||||
if s == nil:
|
||||
result = rawNewStringNoInit(1)
|
||||
result.len = 0
|
||||
else:
|
||||
result = s
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = rawNewStringNoInit(r)
|
||||
result.len = s.len
|
||||
copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1)
|
||||
result.reserved = r
|
||||
result.data[result.len] = c
|
||||
result.data[result.len+1] = '\0'
|
||||
inc(result.len)
|
||||
|
||||
# These routines should be used like following:
|
||||
# The following resize- and append- routines should be used like following:
|
||||
# <Nim code>
|
||||
# s &= "Hello " & name & ", how do you feel?"
|
||||
#
|
||||
@@ -193,46 +186,61 @@ proc addChar(s: NimString, c: char): NimString =
|
||||
# s = rawNewString(0);
|
||||
|
||||
proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
||||
## Prepares `dest` for appending up to `addlen` new bytes.
|
||||
## .. warning:: Does not update `len`!
|
||||
if dest == nil:
|
||||
result = rawNewString(addlen)
|
||||
elif dest.len + addlen <= dest.space:
|
||||
return rawNewString(addlen)
|
||||
let futureLen = dest.len + addlen
|
||||
if futureLen <= dest.space:
|
||||
result = dest
|
||||
else: # slow path:
|
||||
let sp = max(resize(dest.space), dest.len + addlen)
|
||||
# growth strategy: next `resize` step or exact `futureLen` if jumping over
|
||||
let sp = max(resize(dest.space), futureLen)
|
||||
result = rawNewStringNoInit(sp)
|
||||
result.len = dest.len
|
||||
copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1)
|
||||
result.reserved = sp
|
||||
#result = rawNewString(sp)
|
||||
#copyMem(result, dest, dest.len + sizeof(TGenericSeq))
|
||||
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||
|
||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||
if src != nil:
|
||||
copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1)
|
||||
inc(dest.len, src.len)
|
||||
# newFutureLen > space => addlen is never zero, copy terminating null anyway
|
||||
copyMem(addr(result.data), addr(dest.data), dest.len + 1)
|
||||
|
||||
proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
|
||||
dest.data[dest.len] = c
|
||||
dest.data[dest.len+1] = '\0'
|
||||
inc(dest.len)
|
||||
|
||||
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||
let n = max(newLen, 0)
|
||||
proc addChar(s: NimString, c: char): NimString =
|
||||
# is compilerproc! used in `ccgexprs.nim`
|
||||
if s == nil:
|
||||
if n == 0:
|
||||
return s
|
||||
else:
|
||||
result = mnewString(n)
|
||||
elif n <= s.space:
|
||||
result = rawNewStringNoInit(1)
|
||||
result.len = 0
|
||||
else:
|
||||
result = s
|
||||
if s.len >= s.space: # len.inc would overflow (`>` just in case)
|
||||
let sp = resize(s.space)
|
||||
result = rawNewStringNoInit(sp)
|
||||
copyMem(addr(result.data), addr(s.data), s.len)
|
||||
result.len = s.len
|
||||
result.appendChar(c)
|
||||
|
||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||
## Raw, does not prepare `dest` space for copying
|
||||
if src != nil:
|
||||
copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1)
|
||||
inc(dest.len, src.len)
|
||||
|
||||
proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
|
||||
## Sets the `s` length to `newLen` zeroing memory on growth.
|
||||
## Terminating zero at `s[newLen]` for cstring compatibility is set
|
||||
## on any length change, including `newLen == 0`.
|
||||
## Negative `newLen` is bound to zero.
|
||||
let n = max(newLen, 0)
|
||||
if s == nil: # early return check
|
||||
return if n == 0: s else: mnewString(n) # sets everything required
|
||||
if n <= s.space:
|
||||
result = s # len and null-byte still need updating
|
||||
else:
|
||||
let sp = max(resize(s.space), n)
|
||||
result = rawNewStringNoInit(sp)
|
||||
result.len = s.len
|
||||
copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len)
|
||||
result = rawNewStringNoInit(sp) # len and null-byte not set
|
||||
copyMem(addr(result.data), addr(s.data), s.len)
|
||||
zeroMem(addr result.data[s.len], n - s.len)
|
||||
result.reserved = sp
|
||||
result.len = n
|
||||
result.data[n] = '\0'
|
||||
|
||||
@@ -252,14 +260,6 @@ proc incrSeq(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compiler
|
||||
result.reserved = r
|
||||
inc(result.len)
|
||||
|
||||
proc incrSeqV2(seq: PGenericSeq, elemSize, elemAlign: int): PGenericSeq {.compilerproc.} =
|
||||
# incrSeq version 2
|
||||
result = seq
|
||||
if result.len >= result.space:
|
||||
let r = resize(result.space)
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r))
|
||||
result.reserved = r
|
||||
|
||||
proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} =
|
||||
if s == nil:
|
||||
result = cast[PGenericSeq](newSeq(typ, 1))
|
||||
@@ -274,112 +274,68 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerproc.} =
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
|
||||
proc setLengthSeq(seq: PGenericSeq, elemSize, elemAlign, newLen: int): PGenericSeq {.
|
||||
compilerRtl, inl.} =
|
||||
result = seq
|
||||
if result.space < newLen:
|
||||
let r = max(resize(result.space), newLen)
|
||||
result = cast[PGenericSeq](growObj(result, align(GenericSeqSize, elemAlign) + elemSize * r))
|
||||
result.reserved = r
|
||||
elif newLen < result.len:
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin extGetCellType(result).base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
proc extendCapacityRaw(src: PGenericSeq; typ: PNimType;
|
||||
elemSize, elemAlign, newLen: int): PGenericSeq {.inline.} =
|
||||
## Reallocs `src` to fit `newLen` elements without any checks.
|
||||
## Capacity always increases to at least next `resize` step.
|
||||
let newCap = max(resize(src.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, newCap))
|
||||
copyMem(dataPointer(result, elemAlign), dataPointer(src, elemAlign), src.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
src.len = 0
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
result.len = newLen
|
||||
proc truncateRaw(src: PGenericSeq; baseFlags: set[TNimTypeFlag]; isTrivial: bool;
|
||||
elemSize, elemAlign, newLen: int): PGenericSeq {.inline.} =
|
||||
## Truncates `src` to `newLen` without any checks.
|
||||
## Does not set `src.len`
|
||||
# sysAssert src.space > newlen
|
||||
# sysAssert newLen < src.len
|
||||
result = src
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin baseFlags:
|
||||
for i in newLen..<result.len:
|
||||
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
if not isTrivial: # optimization for trivial types
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen),
|
||||
((result.len-%newLen) *% elemSize))
|
||||
|
||||
proc setLengthSeqUninit(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqUninit: type is not a seq"
|
||||
template setLengthSeqImpl(s: PGenericSeq, typ: PNimType, newLen: int; isTrivial: bool;
|
||||
doInit: static bool) =
|
||||
if s == nil:
|
||||
if newLen == 0:
|
||||
result = s
|
||||
else:
|
||||
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||
if newLen == 0: return s
|
||||
else: return cast[PGenericSeq](newSeq(typ, newLen)) # newSeq zeroes!
|
||||
else:
|
||||
let elemSize = typ.base.size
|
||||
let elemAlign = typ.base.align
|
||||
if s.space < newLen:
|
||||
let r = max(resize(s.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
elif newLen < s.len:
|
||||
result = s
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin typ.base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
if not isTrivial: # optimization for trivial types
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
result = if newLen > s.space:
|
||||
s.extendCapacityRaw(typ, elemSize, elemAlign, newLen)
|
||||
elif newLen < s.len:
|
||||
s.truncateRaw(typ.base.flags, isTrivial, elemSize, elemAlign, newLen)
|
||||
else:
|
||||
when doInit:
|
||||
zeroMem(dataPointer(s, elemAlign, elemSize, s.len), (newLen-%s.len) *% elemSize)
|
||||
s
|
||||
result.len = newLen
|
||||
|
||||
proc setLengthSeqUninit(s: PGenericSeq; typ: PNimType; newLen: int; isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqUninit: type is not a seq"
|
||||
setLengthSeqImpl(s, typ, newLen, isTrivial, doInit = false)
|
||||
|
||||
proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int, isTrivial: bool): PGenericSeq {.
|
||||
compilerRtl.} =
|
||||
sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq"
|
||||
if s == nil:
|
||||
if newLen == 0:
|
||||
result = s
|
||||
else:
|
||||
result = cast[PGenericSeq](newSeq(typ, newLen))
|
||||
else:
|
||||
let elemSize = typ.base.size
|
||||
let elemAlign = typ.base.align
|
||||
if s.space < newLen:
|
||||
let r = max(resize(s.space), newLen)
|
||||
result = cast[PGenericSeq](newSeq(typ, r))
|
||||
copyMem(dataPointer(result, elemAlign), dataPointer(s, elemAlign), s.len * elemSize)
|
||||
# since we steal the content from 's', it's crucial to set s's len to 0.
|
||||
s.len = 0
|
||||
elif newLen < s.len:
|
||||
result = s
|
||||
# we need to decref here, otherwise the GC leaks!
|
||||
when not defined(boehmGC) and not defined(nogc) and
|
||||
not defined(gcMarkAndSweep) and not defined(gogc) and
|
||||
not defined(gcRegions):
|
||||
if ntfNoRefs notin typ.base.flags:
|
||||
for i in newLen..result.len-1:
|
||||
forAllChildrenAux(dataPointer(result, elemAlign, elemSize, i),
|
||||
extGetCellType(result).base, waZctDecRef)
|
||||
|
||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||
# This is a tough problem, because even if we don't zeroMem here, in the
|
||||
# presence of user defined destructors, the user will expect the cell to be
|
||||
# "destroyed" thus creating the same problem. We can destroy the cell in the
|
||||
# finalizer of the sequence, but this makes destruction non-deterministic.
|
||||
if not isTrivial: # optimization for trivial types
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, newLen), (result.len-%newLen) *% elemSize)
|
||||
else:
|
||||
result = s
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize)
|
||||
result.len = newLen
|
||||
setLengthSeqImpl(s, typ, newLen, isTrivial, doInit = true)
|
||||
|
||||
func capacity*(self: string): int {.inline.} =
|
||||
## Returns the current capacity of the string.
|
||||
@@ -402,3 +358,5 @@ func capacity*[T](self: seq[T]): int {.inline.} =
|
||||
|
||||
let sek = cast[PGenericSeq](self)
|
||||
result = if sek != nil: sek.space else: 0
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user