summary refs log tree commit diff stats
path: root/lib/system.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system.nim')
-rwxr-xr-xlib/system.nim607
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)``.