diff options
Diffstat (limited to 'lib/system.nim')
-rwxr-xr-x | lib/system.nim | 607 |
1 files changed, 333 insertions, 274 deletions
diff --git a/lib/system.nim b/lib/system.nim index 9fa5258ce..b4c265f62 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -38,7 +38,8 @@ type char* {.magic: Char.} ## built-in 8 bit character type (unsigned) string* {.magic: String.} ## built-in string type cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type - pointer* {.magic: Pointer.} ## built-in pointer type + pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr`` + ## operator to get a pointer to a variable const on* = true ## alias for ``true`` @@ -116,7 +117,13 @@ proc new*(T: typedesc): ref T = ## creates a new object of type ``T`` and returns a safe (traced) ## reference to it as result value new(result) - + +proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.} + ## creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. This is **unsafe** as it allocates an object + ## of the passed ``size``. This should only be used for optimization + ## purposes when you know what you're doing! + proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} ## leaked implementation detail. Do not use. @@ -1060,86 +1067,87 @@ proc substr*(s: string, first, last: int): string {. ## is used instead: This means ``substr`` can also be used to `cut`:idx: ## or `limit`:idx: a string's length. -proc zeroMem*(p: Pointer, size: int) {.importc, noDecl.} - ## 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: int) {.importc: "memcpy", noDecl.} - ## copies the contents from the memory at ``source`` to the memory - ## at ``dest``. Exactly ``size`` bytes will be copied. The memory - ## regions may not overlap. Like any procedure dealing with raw - ## memory this is *unsafe*. - -proc moveMem*(dest, source: Pointer, size: int) {.importc: "memmove", noDecl.} - ## copies the contents from the memory at ``source`` to the memory - ## at ``dest``. Exactly ``size`` bytes will be copied. The memory - ## regions may overlap, ``moveMem`` handles this case appropriately - ## and is thus somewhat more safe than ``copyMem``. Like any procedure - ## dealing with raw memory this is still *unsafe*, though. - -proc equalMem*(a, b: Pointer, size: int): bool {. - importc: "equalMem", noDecl, noSideEffect.} - ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will - ## be compared. If the blocks are equal, true is returned, false - ## otherwise. Like any procedure dealing with raw memory this is - ## *unsafe*. - -proc alloc*(size: int): pointer {.noconv, rtl, tags: [].} - ## allocates a new memory block with at least ``size`` bytes. The - ## block has to be freed with ``realloc(block, 0)`` or - ## ``dealloc(block)``. The block is not initialized, so reading - ## from it before writing to it is undefined behaviour! - ## The allocated memory belongs to its allocating thread! - ## Use `allocShared` to allocate from a shared heap. -proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].} - ## allocates a new memory block with at least ``size`` bytes. The - ## block has to be freed with ``realloc(block, 0)`` or - ## ``dealloc(block)``. The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``alloc``. - ## The allocated memory belongs to its allocating thread! - ## Use `allocShared0` to allocate from a shared heap. -proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].} - ## grows or shrinks a given memory block. If p is **nil** then a new - ## memory block is returned. In either way the block has at least - ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** - ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to - ## be freed with ``dealloc``. - ## The allocated memory belongs to its allocating thread! - ## Use `reallocShared` to reallocate from a shared heap. -proc dealloc*(p: Pointer) {.noconv, rtl, tags: [].} - ## frees the memory allocated with ``alloc``, ``alloc0`` or - ## ``realloc``. This procedure is dangerous! If one forgets to - ## free the memory a leak occurs; if one tries to access freed - ## memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. - ## The freed memory must belong to its allocating thread! - ## Use `deallocShared` to deallocate from a shared heap. - -proc allocShared*(size: int): pointer {.noconv, rtl.} - ## allocates a new memory block on the shared heap with at - ## least ``size`` bytes. The block has to be freed with - ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block - ## is not initialized, so reading from it before writing to it is - ## undefined behaviour! -proc allocShared0*(size: int): pointer {.noconv, rtl.} - ## allocates a new memory block on the shared heap with at - ## least ``size`` bytes. The block has to be freed with - ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. - ## The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``allocShared``. -proc reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.} - ## grows or shrinks a given memory block on the heap. If p is **nil** - ## then a new memory block is returned. In either way the block has at least - ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** - ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the - ## block has to be freed with ``deallocShared``. -proc deallocShared*(p: Pointer) {.noconv, rtl.} - ## frees the memory allocated with ``allocShared``, ``allocShared0`` or - ## ``reallocShared``. This procedure is dangerous! If one forgets to - ## free the memory a leak occurs; if one tries to access freed - ## memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. +when not defined(nimrodVM): + proc zeroMem*(p: Pointer, size: int) {.importc, noDecl.} + ## 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: int) {.importc: "memcpy", noDecl.} + ## copies the contents from the memory at ``source`` to the memory + ## at ``dest``. Exactly ``size`` bytes will be copied. The memory + ## regions may not overlap. Like any procedure dealing with raw + ## memory this is *unsafe*. + + proc moveMem*(dest, source: Pointer, size: int) {.importc: "memmove", noDecl.} + ## copies the contents from the memory at ``source`` to the memory + ## at ``dest``. Exactly ``size`` bytes will be copied. The memory + ## regions may overlap, ``moveMem`` handles this case appropriately + ## and is thus somewhat more safe than ``copyMem``. Like any procedure + ## dealing with raw memory this is still *unsafe*, though. + + proc equalMem*(a, b: Pointer, size: int): bool {. + importc: "equalMem", noDecl, noSideEffect.} + ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will + ## be compared. If the blocks are equal, true is returned, false + ## otherwise. Like any procedure dealing with raw memory this is + ## *unsafe*. + + proc alloc*(size: int): pointer {.noconv, rtl, tags: [].} + ## allocates a new memory block with at least ``size`` bytes. The + ## block has to be freed with ``realloc(block, 0)`` or + ## ``dealloc(block)``. The block is not initialized, so reading + ## from it before writing to it is undefined behaviour! + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared` to allocate from a shared heap. + proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].} + ## allocates a new memory block with at least ``size`` bytes. The + ## block has to be freed with ``realloc(block, 0)`` or + ## ``dealloc(block)``. The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``alloc``. + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared0` to allocate from a shared heap. + proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].} + ## grows or shrinks a given memory block. If p is **nil** then a new + ## memory block is returned. In either way the block has at least + ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** + ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to + ## be freed with ``dealloc``. + ## The allocated memory belongs to its allocating thread! + ## Use `reallocShared` to reallocate from a shared heap. + proc dealloc*(p: Pointer) {.noconv, rtl, tags: [].} + ## frees the memory allocated with ``alloc``, ``alloc0`` or + ## ``realloc``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + ## The freed memory must belong to its allocating thread! + ## Use `deallocShared` to deallocate from a shared heap. + + proc allocShared*(size: int): pointer {.noconv, rtl.} + ## allocates a new memory block on the shared heap with at + ## least ``size`` bytes. The block has to be freed with + ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block + ## is not initialized, so reading from it before writing to it is + ## undefined behaviour! + proc allocShared0*(size: int): pointer {.noconv, rtl.} + ## allocates a new memory block on the shared heap with at + ## least ``size`` bytes. The block has to be freed with + ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. + ## The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``allocShared``. + proc reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.} + ## grows or shrinks a given memory block on the heap. If p is **nil** + ## then a new memory block is returned. In either way the block has at least + ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil** + ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the + ## block has to be freed with ``deallocShared``. + proc deallocShared*(p: Pointer) {.noconv, rtl.} + ## frees the memory allocated with ``allocShared``, ``allocShared0`` or + ## ``reallocShared``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## swaps the values `a` and `b`. This is often more efficient than @@ -1215,15 +1223,16 @@ const # GC interface: -proc getOccupiedMem*(): int {.rtl.} - ## returns the number of bytes that are owned by the process and hold data. +when not defined(nimrodVM): + proc getOccupiedMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process and hold data. -proc getFreeMem*(): int {.rtl.} - ## returns the number of bytes that are owned by the process, but do not - ## hold any meaningful data. + proc getFreeMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process, but do not + ## hold any meaningful data. -proc getTotalMem*(): int {.rtl.} - ## returns the number of bytes that are owned by the process. + proc getTotalMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process. iterator countdown*[T](a, b: T, step = 1): T {.inline.} = @@ -1452,15 +1461,51 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = result = s[L] setLen(s, L) -proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = +proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {. + deprecated.} = ## The well-known ``map`` operation from functional programming. Applies ## `op` to every item in `data` and returns the result as a sequence. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. newSeq(result, data.len) for i in 0..data.len-1: result[i] = op(data[i]) -proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = +proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {. + deprecated.} = ## The well-known ``map`` operation from functional programming. Applies - ## `op` to every item in `data`. + ## `op` to every item in `data` modifying it directly. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. + for i in 0..data.len-1: op(data[i]) + +proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = + ## Returns a new sequence with the results of `op` applied to every item in + ## `data`. + ## + ## Since the input is not modified you can use this version of ``map`` to + ## transform the type of the elements in the input sequence. Example: + ## + ## .. code-block:: nimrod + ## let + ## a = @[1, 2, 3, 4] + ## b = map(a, proc(x: int): string = $x) + ## assert b == @["1", "2", "3", "4"] + newSeq(result, data.len) + for i in 0..data.len-1: result[i] = op(data[i]) + +proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = + ## Applies `op` to every item in `data` modifying it directly. + ## + ## Note that this version of ``map`` requires your input and output types to + ## be the same, since they are modified in-place. Example: + ## + ## .. code-block:: nimrod + ## var a = @["1", "2", "3", "4"] + ## echo repr(a) + ## # --> ["1", "2", "3", "4"] + ## map(a, proc(x: var string) = x &= "42") + ## echo repr(a) + ## # --> ["142", "242", "342", "442"] for i in 0..data.len-1: op(data[i]) iterator fields*[T: tuple](x: T): TObject {. @@ -1541,41 +1586,42 @@ when false: # ----------------- GC interface --------------------------------------------- -proc GC_disable*() {.rtl, inl.} - ## disables the GC. If called n-times, n calls to `GC_enable` are needed to - ## reactivate the GC. Note that in most circumstances one should only disable - ## the mark and sweep phase with `GC_disableMarkAndSweep`. +when not defined(nimrodVM): + proc GC_disable*() {.rtl, inl.} + ## disables the GC. If called n-times, n calls to `GC_enable` are needed to + ## reactivate the GC. Note that in most circumstances one should only disable + ## the mark and sweep phase with `GC_disableMarkAndSweep`. -proc GC_enable*() {.rtl, inl.} - ## enables the GC again. + proc GC_enable*() {.rtl, inl.} + ## enables the GC again. -proc GC_fullCollect*() {.rtl.} - ## forces a full garbage collection pass. - ## Ordinary code does not need to call this (and should not). + proc GC_fullCollect*() {.rtl.} + ## forces a full garbage collection pass. + ## Ordinary code does not need to call this (and should not). -type - TGC_Strategy* = enum ## the strategy the GC should use for the application - gcThroughput, ## optimize for throughput - gcResponsiveness, ## optimize for responsiveness (default) - gcOptimizeTime, ## optimize for speed - gcOptimizeSpace ## optimize for memory footprint - -proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl, deprecated.} - ## tells the GC the desired strategy for the application. - ## **Deprecated** since version 0.8.14. This has always been a nop. - -proc GC_enableMarkAndSweep*() {.rtl.} -proc GC_disableMarkAndSweep*() {.rtl.} - ## the current implementation uses a reference counting garbage collector - ## with a seldomly run mark and sweep phase to free cycles. The mark and - ## sweep phase may take a long time and is not needed if the application - ## does not create cycles. Thus the mark and sweep phase can be deactivated - ## and activated separately from the rest of the GC. - -proc GC_getStatistics*(): string {.rtl.} - ## returns an informative string about the GC's activity. This may be useful - ## for tweaking. - + type + TGC_Strategy* = enum ## the strategy the GC should use for the application + gcThroughput, ## optimize for throughput + gcResponsiveness, ## optimize for responsiveness (default) + gcOptimizeTime, ## optimize for speed + gcOptimizeSpace ## optimize for memory footprint + + proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl, deprecated.} + ## tells the GC the desired strategy for the application. + ## **Deprecated** since version 0.8.14. This has always been a nop. + + proc GC_enableMarkAndSweep*() {.rtl.} + proc GC_disableMarkAndSweep*() {.rtl.} + ## the current implementation uses a reference counting garbage collector + ## with a seldomly run mark and sweep phase to free cycles. The mark and + ## sweep phase may take a long time and is not needed if the application + ## does not create cycles. Thus the mark and sweep phase can be deactivated + ## and activated separately from the rest of the GC. + + proc GC_getStatistics*(): string {.rtl.} + ## returns an informative string about the GC's activity. This may be useful + ## for tweaking. + proc GC_ref*[T](x: ref T) {.magic: "GCref".} proc GC_ref*[T](x: seq[T]) {.magic: "GCref".} proc GC_ref*(x: string) {.magic: "GCref".} @@ -1701,28 +1747,29 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".} ## get type information for `x`. Ordinary code should not use this, but ## the `typeinfo` module instead. -when not defined(EcmaScript) and not defined(NimrodVM): +when not defined(EcmaScript): #and not defined(NimrodVM): {.push stack_trace: off, profiler:off.} - proc initGC() - when not defined(boehmgc) and not defined(useMalloc): - proc initAllocator() {.inline.} + when not defined(NimrodVM): + proc initGC() + when not defined(boehmgc) and not defined(useMalloc): + proc initAllocator() {.inline.} - proc initStackBottom() {.inline, compilerproc.} = - # WARNING: This is very fragile! An array size of 8 does not work on my - # Linux 64bit system. Very strange, but we are at the will of GCC's - # optimizer... - when defined(setStackBottom): - var locals {.volatile.}: pointer - locals = addr(locals) - setStackBottom(locals) + proc initStackBottom() {.inline, compilerproc.} = + # WARNING: This is very fragile! An array size of 8 does not work on my + # Linux 64bit system. -- That's because the stack direction is the other + # way round. + when defined(setStackBottom): + var locals {.volatile.}: pointer + locals = addr(locals) + setStackBottom(locals) - var - strDesc: TNimType + var + strDesc: TNimType - strDesc.size = sizeof(string) - strDesc.kind = tyString - strDesc.flags = {ntfAcyclic} + strDesc.size = sizeof(string) + strDesc.kind = tyString + strDesc.flags = {ntfAcyclic} include "system/ansi_c" @@ -1730,28 +1777,27 @@ when not defined(EcmaScript) and not defined(NimrodVM): result = int(c_strcmp(x, y)) const pccHack = if defined(pcc): "_" else: "" # Hack for PCC - when defined(windows): - # work-around C's sucking abstraction: - # BUGFIX: stdin and stdout should be binary files! - proc setmode(handle, mode: int) {.importc: pccHack & "setmode", - header: "<io.h>".} - proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", - header: "<fcntl.h>".} - var - O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int - - # we use binary mode in Windows: - setmode(fileno(c_stdin), O_BINARY) - setmode(fileno(c_stdout), O_BINARY) - - when defined(endb): - proc endbStep() + when not defined(NimrodVM): + when defined(windows): + # work-around C's sucking abstraction: + # BUGFIX: stdin and stdout should be binary files! + proc setmode(handle, mode: int) {.importc: pccHack & "setmode", + header: "<io.h>".} + proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", + header: "<fcntl.h>".} + var + O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int + + # we use binary mode in Windows: + setmode(fileno(c_stdin), O_BINARY) + setmode(fileno(c_stdout), O_BINARY) + + when defined(endb): + proc endbStep() # ----------------- IO Part ------------------------------------------------ - type - CFile {.importc: "FILE", nodecl, final.} = object # empty record for - # data hiding + CFile {.importc: "FILE", nodecl, final, incompletestruct.} = object TFile* = ptr CFile ## The type representing a file handle. TFileMode* = enum ## The file mode when opening a file. @@ -1777,7 +1823,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## The standard error stream. ## ## Note: In my opinion, this should not be used -- the concept of a - ## separate error stream is a design flaw of UNIX. A seperate *message + ## separate error stream is a design flaw of UNIX. A separate *message ## stream* is a good idea, but since it is named ``stderr`` there are few ## programs out there that distinguish properly between ``stdout`` and ## ``stderr``. So, that's what you get if you don't name your variables @@ -1934,31 +1980,32 @@ when not defined(EcmaScript) and not defined(NimrodVM): # ------------------------------------------------------------------------- - proc allocCStringArray*(a: openArray[string]): cstringArray = - ## creates a NULL terminated cstringArray from `a`. The result has to - ## be freed with `deallocCStringArray` after it's not needed anymore. - result = cast[cstringArray](alloc0((a.len+1) * sizeof(cstring))) - for i in 0 .. a.high: - # XXX get rid of this string copy here: - var x = a[i] - result[i] = cast[cstring](alloc0(x.len+1)) - copyMem(result[i], addr(x[0]), x.len) - - proc deallocCStringArray*(a: cstringArray) = - ## frees a NULL terminated cstringArray. - var i = 0 - while a[i] != nil: - dealloc(a[i]) - inc(i) - dealloc(a) - - proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.} - ## atomic increment of `memLoc`. Returns the value after the operation. - - proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable.} - ## atomic decrement of `memLoc`. Returns the value after the operation. + when not defined(NimrodVM): + proc allocCStringArray*(a: openArray[string]): cstringArray = + ## creates a NULL terminated cstringArray from `a`. The result has to + ## be freed with `deallocCStringArray` after it's not needed anymore. + result = cast[cstringArray](alloc0((a.len+1) * sizeof(cstring))) + for i in 0 .. a.high: + # XXX get rid of this string copy here: + var x = a[i] + result[i] = cast[cstring](alloc0(x.len+1)) + copyMem(result[i], addr(x[0]), x.len) + + proc deallocCStringArray*(a: cstringArray) = + ## frees a NULL terminated cstringArray. + var i = 0 + while a[i] != nil: + dealloc(a[i]) + inc(i) + dealloc(a) + + proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.} + ## atomic increment of `memLoc`. Returns the value after the operation. + + proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable.} + ## atomic decrement of `memLoc`. Returns the value after the operation. - include "system/atomics" + include "system/atomics" type PSafePoint = ptr TSafePoint @@ -1974,71 +2021,76 @@ when not defined(EcmaScript) and not defined(NimrodVM): when hasThreadSupport: include "system/syslocks" include "system/threads" - elif not defined(nogc): + elif not defined(nogc) and not defined(NimrodVM): when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() initGC() - proc setControlCHook*(hook: proc () {.noconv.}) - ## allows you to override the behaviour of your application when CTRL+C - ## is pressed. Only one such hook is supported. - - proc writeStackTrace*() {.tags: [FWriteIO].} - ## writes the current stack trace to ``stderr``. This is only works - ## for debug builds. - when hostOS != "standalone": - proc getStackTrace*(): string - ## gets the current stack trace. This only works for debug builds. - - proc getStackTrace*(e: ref E_Base): string - ## gets the stack trace associated with `e`, which is the stack that - ## lead to the ``raise`` statement. This only works for debug builds. + when not defined(NimrodVM): + proc setControlCHook*(hook: proc () {.noconv.}) + ## allows you to override the behaviour of your application when CTRL+C + ## is pressed. Only one such hook is supported. - {.push stack_trace: off, profiler:off.} - when hostOS == "standalone": - include "system/embedded" - else: - include "system/excpt" - - # we cannot compile this with stack tracing on - # as it would recurse endlessly! - include "system/arithm" - {.pop.} # stack trace + proc writeStackTrace*() {.tags: [FWriteIO].} + ## writes the current stack trace to ``stderr``. This is only works + ## for debug builds. + when hostOS != "standalone": + proc getStackTrace*(): string + ## gets the current stack trace. This only works for debug builds. + + proc getStackTrace*(e: ref E_Base): string + ## gets the stack trace associated with `e`, which is the stack that + ## lead to the ``raise`` statement. This only works for debug builds. + + {.push stack_trace: off, profiler:off.} + when hostOS == "standalone": + include "system/embedded" + else: + include "system/excpt" + + # we cannot compile this with stack tracing on + # as it would recurse endlessly! + include "system/arithm" + {.pop.} # stack trace {.pop.} # stack trace - when hostOS != "standalone": include "system/dyncalls" - include "system/sets" + when hostOS != "standalone" and not defined(NimrodVM): + include "system/dyncalls" + when not defined(NimrodVM): + include "system/sets" - const - GenericSeqSize = (2 * sizeof(int)) - - proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = - sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") - var d: int - var a = cast[TAddress](aa) - case n.typ.size - of 1: d = ze(cast[ptr int8](a +% n.offset)[]) - of 2: d = ze(cast[ptr int16](a +% n.offset)[]) - of 4: d = int(cast[ptr int32](a +% n.offset)[]) - else: sysAssert(false, "getDiscriminant: invalid n.typ.size") - return d - - proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode = - var discr = getDiscriminant(aa, n) - if discr <% n.len: - result = n.sons[discr] - if result == nil: result = n.sons[n.len] - # n.sons[n.len] contains the ``else`` part (but may be nil) - else: - result = n.sons[n.len] - - include "system/mmdisp" - {.push stack_trace: off, profiler:off.} - when hostOS != "standalone": include "system/sysstr" - {.pop.} - - include "system/sysio" - when hasThreadSupport: - include "system/channels" + const + GenericSeqSize = (2 * sizeof(int)) + + proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = + sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") + var d: int + var a = cast[TAddress](aa) + case n.typ.size + of 1: d = ze(cast[ptr int8](a +% n.offset)[]) + of 2: d = ze(cast[ptr int16](a +% n.offset)[]) + of 4: d = int(cast[ptr int32](a +% n.offset)[]) + else: sysAssert(false, "getDiscriminant: invalid n.typ.size") + return d + + proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode = + var discr = getDiscriminant(aa, n) + if discr <% n.len: + result = n.sons[discr] + if result == nil: result = n.sons[n.len] + # n.sons[n.len] contains the ``else`` part (but may be nil) + else: + result = n.sons[n.len] + + include "system/mmdisp" + {.push stack_trace: off, profiler:off.} + when hostOS != "standalone": include "system/sysstr" + {.pop.} + + include "system/sysio" + when hasThreadSupport: + include "system/channels" + else: + include "system/sysio" iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} = ## Iterate over any line in the file named `filename`. @@ -2053,7 +2105,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield TaintedString(res) - when hostOS != "standalone": + when hostOS != "standalone" and not defined(NimrodVM): include "system/assign" include "system/repr" @@ -2078,43 +2130,46 @@ when not defined(EcmaScript) and not defined(NimrodVM): excHandler.raiseAction = action {.push stack_trace: off, profiler:off.} - when defined(endb): + when defined(endb) and not defined(NimrodVM): include "system/debugger" when defined(profiler) or defined(memProfiler): include "system/profiler" {.pop.} # stacktrace - proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} - ## can be used to mark a condition to be likely. This is a hint for the - ## optimizer. - - proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} - ## can be used to mark a condition to be unlikely. This is a hint for the - ## optimizer. + when not defined(NimrodVM): + proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} + ## can be used to mark a condition to be likely. This is a hint for the + ## optimizer. - proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = - ## retrieves the raw proc pointer of the closure `x`. This is - ## useful for interfacing closures with C. - {.emit: """ - `result` = `x`.ClPrc; - """.} - - proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = - ## retrieves the raw environment pointer of the closure `x`. This is - ## useful for interfacing closures with C. - {.emit: """ - `result` = `x`.ClEnv; - """.} - - proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = - ## can be used to determine if a first class iterator has finished. - {.emit: """ - `result` = *((NI*) `x`.ClEnv) < 0; - """.} - -elif defined(ecmaScript) or defined(NimrodVM): + proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} + ## can be used to mark a condition to be unlikely. This is a hint for the + ## optimizer. + + proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = + ## retrieves the raw proc pointer of the closure `x`. This is + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClPrc; + """.} + + proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = + ## retrieves the raw environment pointer of the closure `x`. This is + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClEnv; + """.} + + proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = + ## can be used to determine if a first class iterator has finished. + {.emit: """ + `result` = *((NI*) `x`.ClEnv) < 0; + """.} + +elif defined(ecmaScript): # Stubs: + proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil + proc GC_disable() = nil proc GC_enable() = nil proc GC_fullCollect() = nil @@ -2145,6 +2200,10 @@ elif defined(ecmaScript) or defined(NimrodVM): if x == y: return 0 if x < y: return -1 return 1 + + when defined(nimffi): + include "system/sysio" + proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = ## a shorthand for ``echo(errormsg); quit(errorcode)``. |