diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/core/seqs.nim | 87 | ||||
-rw-r--r-- | lib/system.nim | 13 | ||||
-rw-r--r-- | lib/system/excpt.nim | 64 |
3 files changed, 65 insertions, 99 deletions
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index 914ca438c..b7f9fb153 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -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] diff --git a/lib/system.nim b/lib/system.nim index cb211e6a9..81d308073 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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. diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index ef9a6deaf..6e06b10f8 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -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,7 +333,53 @@ template unhandled(buf, body) = else: body -proc raiseExceptionAux(e: ref Exception) = +proc nimLeaveFinally() {.compilerRtl.} = + when defined(cpp) and not defined(noCppExceptions): + {.emit: "throw;".} + else: + template e: untyped = currException + if excHandler != nil: + 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 raiseExceptionAux(e: sink(ref Exception)) {.nodestroy.} = if localRaiseHook != nil: if not localRaiseHook(e): return if globalRaiseHook != nil: @@ -351,9 +398,8 @@ proc raiseExceptionAux(e: ref Exception) = pushCurrentException(e) else: if excHandler != nil: - if not excHandler.hasRaiseAction or excHandler.raiseAction(e): - pushCurrentException(e) - c_longjmp(excHandler.context, 1) + pushCurrentException(e) + c_longjmp(excHandler.context, 1) else: when hasSomeStackTrace: var buf = newStringOfCap(2000) @@ -367,6 +413,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 +439,8 @@ proc raiseExceptionAux(e: ref Exception) = showErrorMessage(tbuf()) quitOrDebug() -proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line: int) {.compilerRtl.} = +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.} = |