ARC related bugfixes and refactorings (#12781)
This commit is contained in:
parent
9b0e874687
commit
3fbb3bfd3f
11 changed files with 381 additions and 367 deletions
|
|
@ -30,60 +30,6 @@ template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocato
|
|||
|
||||
# XXX make code memory safe for overflows in '*'
|
||||
|
||||
when false:
|
||||
# this is currently not part of Nim's type bound operators and so it's
|
||||
# built into the tracing proc generation just like before.
|
||||
proc `=trace`[T](s: NimSeqV2[T]) =
|
||||
for i in 0 ..< s.len: `=trace`(s.data[i])
|
||||
|
||||
#[
|
||||
Keep in mind that C optimizers are bad at detecting the connection
|
||||
between ``s.p != nil`` and ``s.len != 0`` and that these are intermingled
|
||||
with user-level code that accesses ``s.len`` only, never ``s.p`` directly.
|
||||
This means the check for whether ``s.p`` needs to be freed should
|
||||
be ``s.len == 0`` even though that feels slightly more awkward.
|
||||
]#
|
||||
|
||||
when not defined(nimV2):
|
||||
proc `=destroy`[T](s: var seq[T]) =
|
||||
var x = cast[ptr NimSeqV2[T]](addr s)
|
||||
var p = x.p
|
||||
if p != nil:
|
||||
mixin `=destroy`
|
||||
when not supportsCopyMem(T):
|
||||
for i in 0..<x.len: `=destroy`(p.data[i])
|
||||
if p.allocator != nil:
|
||||
p.allocator.dealloc(p.allocator, p, payloadSize(p.cap))
|
||||
x.p = nil
|
||||
x.len = 0
|
||||
|
||||
proc `=`[T](x: var seq[T]; y: seq[T]) =
|
||||
mixin `=destroy`
|
||||
var a = cast[ptr NimSeqV2[T]](addr x)
|
||||
var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
|
||||
|
||||
if a.p == b.p: return
|
||||
`=destroy`(x)
|
||||
a.len = b.len
|
||||
if b.p != nil:
|
||||
a.p = cast[type(a.p)](alloc(payloadSize(a.len)))
|
||||
when supportsCopyMem(T):
|
||||
if a.len > 0:
|
||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T))
|
||||
else:
|
||||
for i in 0..<a.len:
|
||||
a.p.data[i] = b.p.data[i]
|
||||
|
||||
proc `=sink`[T](x: var seq[T]; y: seq[T]) =
|
||||
mixin `=destroy`
|
||||
var a = cast[ptr NimSeqV2[T]](addr x)
|
||||
var b = cast[ptr NimSeqV2[T]](unsafeAddr y)
|
||||
if a.p != nil and a.p != b.p:
|
||||
`=destroy`(x)
|
||||
a.len = b.len
|
||||
a.p = b.p
|
||||
|
||||
|
||||
type
|
||||
PayloadBase = object
|
||||
cap: int
|
||||
|
|
@ -181,36 +127,3 @@ proc setLen[T](s: var seq[T], newlen: Natural) =
|
|||
if xu.p == nil or xu.p.cap < newlen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T)))
|
||||
xu.len = newlen
|
||||
|
||||
when false:
|
||||
proc resize[T](s: var NimSeqV2[T]) =
|
||||
let old = s.cap
|
||||
if old == 0: s.cap = 8
|
||||
else: s.cap = (s.cap * 3) shr 1
|
||||
s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T)))
|
||||
|
||||
proc reserveSlot[T](x: var NimSeqV2[T]): ptr T =
|
||||
if x.len >= x.cap: resize(x)
|
||||
result = addr(x.data[x.len])
|
||||
inc x.len
|
||||
|
||||
template add*[T](x: var NimSeqV2[T]; y: T) =
|
||||
reserveSlot(x)[] = y
|
||||
|
||||
template `[]`*[T](x: NimSeqV2[T]; i: Natural): T =
|
||||
assert i < x.len
|
||||
x.data[i]
|
||||
|
||||
template `[]=`*[T](x: NimSeqV2[T]; i: Natural; y: T) =
|
||||
assert i < x.len
|
||||
x.data[i] = y
|
||||
|
||||
proc `@`*[T](elems: sink openArray[T]): NimSeqV2[T] =
|
||||
result.cap = elems.len
|
||||
result.len = elems.len
|
||||
result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
|
||||
when supportsCopyMem(T):
|
||||
copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T))
|
||||
else:
|
||||
for i in 0..<result.len:
|
||||
result.data[i] = elems[i]
|
||||
|
|
|
|||
|
|
@ -3218,6 +3218,9 @@ proc `<`*[T: tuple](x, y: T): bool =
|
|||
const
|
||||
usesDestructors = defined(gcDestructors) or defined(gcHooks)
|
||||
|
||||
when not usesDestructors:
|
||||
{.pragma: nodestroy.}
|
||||
|
||||
when not defined(nimscript) and hasAlloc:
|
||||
type
|
||||
GC_Strategy* = enum ## The strategy the GC should use for the application.
|
||||
|
|
@ -3671,8 +3674,6 @@ when not defined(JS): #and not defined(nimscript):
|
|||
prev: PSafePoint # points to next safe point ON THE STACK
|
||||
status: int
|
||||
context: C_JmpBuf
|
||||
hasRaiseAction: bool
|
||||
raiseAction: proc (e: ref Exception): bool {.closure.}
|
||||
SafePoint = TSafePoint
|
||||
|
||||
when declared(initAllocator):
|
||||
|
|
@ -3776,11 +3777,15 @@ when not defined(JS): #and not defined(nimscript):
|
|||
## Retrieves the current exception; if there is none, `nil` is returned.
|
||||
result = currException
|
||||
|
||||
proc nimBorrowCurrentException(): ref Exception {.compilerRtl, inl, benign, nodestroy.} =
|
||||
# .nodestroy here so that we do not produce a write barrier as the
|
||||
# C codegen only uses it in a borrowed way:
|
||||
result = currException
|
||||
|
||||
proc getCurrentExceptionMsg*(): string {.inline, benign.} =
|
||||
## Retrieves the error message that was attached to the current
|
||||
## exception; if there is none, `""` is returned.
|
||||
var e = getCurrentException()
|
||||
return if e == nil: "" else: e.msg
|
||||
return if currException == nil: "" else: currException.msg
|
||||
|
||||
proc setCurrentException*(exc: ref Exception) {.inline, benign.} =
|
||||
## Sets the current exception.
|
||||
|
|
|
|||
|
|
@ -103,19 +103,20 @@ proc pushGcFrame*(s: GcFrame) {.compilerRtl, inl.} =
|
|||
gcFramePtr = s
|
||||
|
||||
proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
||||
s.hasRaiseAction = false
|
||||
s.prev = excHandler
|
||||
excHandler = s
|
||||
|
||||
proc popSafePoint {.compilerRtl, inl.} =
|
||||
excHandler = excHandler.prev
|
||||
|
||||
proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
|
||||
proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} =
|
||||
e.up = currException
|
||||
currException = e
|
||||
#showErrorMessage "A"
|
||||
|
||||
proc popCurrentException {.compilerRtl, inl.} =
|
||||
currException = currException.up
|
||||
#showErrorMessage "B"
|
||||
|
||||
proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
|
||||
# in cpp backend exceptions can pop-up in the different order they were raised, example #5628
|
||||
|
|
@ -332,28 +333,13 @@ template unhandled(buf, body) =
|
|||
else:
|
||||
body
|
||||
|
||||
proc raiseExceptionAux(e: ref Exception) =
|
||||
if localRaiseHook != nil:
|
||||
if not localRaiseHook(e): return
|
||||
if globalRaiseHook != nil:
|
||||
if not globalRaiseHook(e): return
|
||||
proc nimLeaveFinally() {.compilerRtl.} =
|
||||
when defined(cpp) and not defined(noCppExceptions):
|
||||
if e == currException:
|
||||
{.emit: "throw;".}
|
||||
else:
|
||||
pushCurrentException(e)
|
||||
raiseCounter.inc
|
||||
if raiseCounter == 0:
|
||||
raiseCounter.inc # skip zero at overflow
|
||||
e.raiseId = raiseCounter
|
||||
{.emit: "`e`->raise();".}
|
||||
elif defined(nimQuirky):
|
||||
pushCurrentException(e)
|
||||
{.emit: "throw;".}
|
||||
else:
|
||||
template e: untyped = currException
|
||||
if excHandler != nil:
|
||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
else:
|
||||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
|
|
@ -367,6 +353,7 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
unhandled(buf):
|
||||
showErrorMessage(buf)
|
||||
quitOrDebug()
|
||||
`=destroy`(buf)
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen) =
|
||||
|
|
@ -392,7 +379,68 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
showErrorMessage(tbuf())
|
||||
quitOrDebug()
|
||||
|
||||
proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line: int) {.compilerRtl.} =
|
||||
proc raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} =
|
||||
if localRaiseHook != nil:
|
||||
if not localRaiseHook(e): return
|
||||
if globalRaiseHook != nil:
|
||||
if not globalRaiseHook(e): return
|
||||
when defined(cpp) and not defined(noCppExceptions):
|
||||
if e == currException:
|
||||
{.emit: "throw;".}
|
||||
else:
|
||||
pushCurrentException(e)
|
||||
raiseCounter.inc
|
||||
if raiseCounter == 0:
|
||||
raiseCounter.inc # skip zero at overflow
|
||||
e.raiseId = raiseCounter
|
||||
{.emit: "`e`->raise();".}
|
||||
elif defined(nimQuirky):
|
||||
pushCurrentException(e)
|
||||
else:
|
||||
if excHandler != nil:
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
else:
|
||||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
if e.trace.len == 0: rawWriteStackTrace(buf)
|
||||
else: add(buf, $e.trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
add(buf, $e.name)
|
||||
add(buf, "]\n")
|
||||
unhandled(buf):
|
||||
showErrorMessage(buf)
|
||||
quitOrDebug()
|
||||
`=destroy`(buf)
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen) =
|
||||
if L + slen < high(buf):
|
||||
copyMem(addr(buf[L]), cstring(s), slen)
|
||||
inc L, slen
|
||||
template add(buf, s) =
|
||||
xadd(buf, s, s.len)
|
||||
var buf: array[0..2000, char]
|
||||
var L = 0
|
||||
if e.trace.len != 0:
|
||||
add(buf, $e.trace) # gc allocation
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
xadd(buf, e.name, e.name.len)
|
||||
add(buf, "]\n")
|
||||
when defined(nimNoArrayToCstringConversion):
|
||||
template tbuf(): untyped = addr buf
|
||||
else:
|
||||
template tbuf(): untyped = buf
|
||||
unhandled(tbuf()):
|
||||
showErrorMessage(tbuf())
|
||||
quitOrDebug()
|
||||
|
||||
proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring,
|
||||
line: int) {.compilerRtl, nodestroy.} =
|
||||
if e.name.isNil: e.name = ename
|
||||
when hasSomeStackTrace:
|
||||
if e.trace.len == 0:
|
||||
|
|
@ -406,7 +454,7 @@ proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line
|
|||
e.trace.add StackTraceEntry(procname: procname, filename: filename, line: line)
|
||||
raiseExceptionAux(e)
|
||||
|
||||
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
|
||||
proc raiseException(e: sink(ref Exception), ename: cstring) {.compilerRtl.} =
|
||||
raiseExceptionEx(e, ename, nil, nil, 0)
|
||||
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue