summary refs log tree commit diff stats
path: root/nimlib/system
diff options
context:
space:
mode:
Diffstat (limited to 'nimlib/system')
-rwxr-xr-xnimlib/system/alloc.nim596
-rwxr-xr-xnimlib/system/ansi_c.nim105
-rwxr-xr-xnimlib/system/arithm.nim316
-rwxr-xr-xnimlib/system/assign.nim120
-rwxr-xr-xnimlib/system/cellsets.nim196
-rwxr-xr-xnimlib/system/cntbits.nim12
-rwxr-xr-xnimlib/system/debugger.nim500
-rwxr-xr-xnimlib/system/dyncalls.nim127
-rwxr-xr-xnimlib/system/ecmasys.nim531
-rwxr-xr-xnimlib/system/excpt.nim285
-rwxr-xr-xnimlib/system/gc.nim647
-rwxr-xr-xnimlib/system/hti.nim58
-rwxr-xr-xnimlib/system/mm.nim189
-rwxr-xr-xnimlib/system/profiler.nim61
-rwxr-xr-xnimlib/system/repr.nim249
-rwxr-xr-xnimlib/system/sets.nim28
-rwxr-xr-xnimlib/system/sysio.nim184
-rwxr-xr-xnimlib/system/sysstr.nim289
18 files changed, 4493 insertions, 0 deletions
diff --git a/nimlib/system/alloc.nim b/nimlib/system/alloc.nim
new file mode 100755
index 000000000..95feff854
--- /dev/null
+++ b/nimlib/system/alloc.nim
@@ -0,0 +1,596 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Low level allocator for Nimrod. Has been designed to support the GC.
+# TODO: 
+# - eliminate "used" field
+# - make searching for block O(1)
+
+# ------------ platform specific chunk allocation code -----------------------
+
+when defined(posix): 
+  const
+    PROT_READ  = 1             # page can be read 
+    PROT_WRITE = 2             # page can be written 
+    MAP_PRIVATE = 2            # Changes are private 
+  
+  when defined(linux) or defined(aix):
+    const MAP_ANONYMOUS = 0x20       # don't use a file
+  elif defined(macosx) or defined(bsd):
+    const MAP_ANONYMOUS = 0x1000
+  elif defined(solaris): 
+    const MAP_ANONYMOUS = 0x100
+  else:
+    {.error: "Port memory manager to your platform".}
+
+  proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
+            off: int): pointer {.header: "<sys/mman.h>".}
+
+  proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
+  
+  proc osAllocPages(size: int): pointer {.inline.} = 
+    result = mmap(nil, size, PROT_READ or PROT_WRITE, 
+                           MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+    if result == nil or result == cast[pointer](-1):
+      raiseOutOfMem()
+      
+  proc osDeallocPages(p: pointer, size: int) {.inline} =
+    when reallyOsDealloc: munmap(p, size)
+  
+elif defined(windows): 
+  const
+    MEM_RESERVE = 0x2000 
+    MEM_COMMIT = 0x1000
+    MEM_TOP_DOWN = 0x100000
+    PAGE_READWRITE = 0x04
+
+    MEM_DECOMMIT = 0x4000
+    MEM_RELEASE = 0x8000
+
+  proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
+                    flProtect: int32): pointer {.
+                    header: "<windows.h>", stdcall.}
+  
+  proc VirtualFree(lpAddress: pointer, dwSize: int, 
+                   dwFreeType: int32) {.header: "<windows.h>", stdcall.}
+  
+  proc osAllocPages(size: int): pointer {.inline.} = 
+    result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
+                          PAGE_READWRITE)
+    if result == nil: raiseOutOfMem()
+
+  proc osDeallocPages(p: pointer, size: int) {.inline.} = 
+    # according to Microsoft, 0 is the only correct value here:
+    when reallyOsDealloc: VirtualFree(p, 0, MEM_RELEASE)
+
+else: 
+  {.error: "Port memory manager to your platform".}
+
+# --------------------- end of non-portable code -----------------------------
+
+# We manage *chunks* of memory. Each chunk is a multiple of the page size.
+# Each chunk starts at an address that is divisible by the page size. Chunks
+# that are bigger than ``ChunkOsReturn`` are returned back to the operating
+# system immediately.
+
+const
+  ChunkOsReturn = 256 * PageSize
+  InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
+  SmallChunkSize = PageSize
+
+type 
+  PTrunk = ptr TTrunk
+  TTrunk {.final.} = object 
+    next: PTrunk         # all nodes are connected with this pointer
+    key: int             # start address at bit 0
+    bits: array[0..IntsPerTrunk-1, int] # a bit vector
+  
+  TTrunkBuckets = array[0..1023, PTrunk]
+  TIntSet {.final.} = object 
+    data: TTrunkBuckets
+  
+type
+  TAlignType = biggestFloat
+  TFreeCell {.final, pure.} = object
+    next: ptr TFreeCell  # next free cell in chunk (overlaid with refcount)
+    zeroField: int       # 0 means cell is not used (overlaid with typ field)
+                         # 1 means cell is manually managed pointer
+
+  PChunk = ptr TBaseChunk
+  PBigChunk = ptr TBigChunk
+  PSmallChunk = ptr TSmallChunk
+  TBaseChunk {.pure.} = object
+    prevSize: int        # size of previous chunk; for coalescing
+    size: int            # if < PageSize it is a small chunk
+    used: bool           # later will be optimized into prevSize...
+  
+  TSmallChunk = object of TBaseChunk
+    next, prev: PSmallChunk  # chunks of the same size
+    freeList: ptr TFreeCell
+    free: int            # how many bytes remain    
+    acc: int             # accumulator for small object allocation
+    data: TAlignType     # start of usable memory
+  
+  TBigChunk = object of TBaseChunk # not necessarily > PageSize!
+    next: PBigChunk      # chunks of the same (or bigger) size
+    prev: PBigChunk
+    align: int
+    data: TAlignType     # start of usable memory
+
+template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
+template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
+
+proc roundup(x, v: int): int {.inline.} = 
+  result = (x + (v-1)) and not (v-1)
+  assert(result >= x)
+  #return ((-x) and (v-1)) +% x
+
+assert(roundup(14, PageSize) == PageSize)
+assert(roundup(15, 8) == 16)
+assert(roundup(65, 8) == 72)
+
+# ------------- chunk table ---------------------------------------------------
+# We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk
+# endings of big chunks. This is needed by the merging operation. The only
+# remaining operation is best-fit for big chunks. Since there is a size-limit
+# for big chunks (because greater than the limit means they are returned back
+# to the OS), a fixed size array can be used. 
+
+type
+  PLLChunk = ptr TLLChunk
+  TLLChunk {.pure.} = object ## *low-level* chunk
+    size: int                # remaining size
+    acc: int                 # accumulator
+    
+  TAllocator {.final, pure.} = object
+    llmem: PLLChunk
+    currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
+    freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
+    freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
+    chunkStarts: TIntSet
+   
+proc incCurrMem(a: var TAllocator, bytes: int) {.inline.} = 
+  inc(a.currMem, bytes)
+
+proc decCurrMem(a: var TAllocator, bytes: int) {.inline.} =
+  a.maxMem = max(a.maxMem, a.currMem)
+  dec(a.currMem, bytes)
+
+proc getMaxMem(a: var TAllocator): int =
+  # Since we update maxPagesCount only when freeing pages, 
+  # maxPagesCount may not be up to date. Thus we use the
+  # maximum of these both values here:
+  return max(a.currMem, a.maxMem)
+   
+var
+  allocator: TAllocator
+    
+proc llAlloc(a: var TAllocator, size: int): pointer =
+  # *low-level* alloc for the memory managers data structures. Deallocation
+  # is never done.
+  if a.llmem == nil or size > a.llmem.size:
+    var request = roundup(size+sizeof(TLLChunk), PageSize)
+    a.llmem = cast[PLLChunk](osAllocPages(request))
+    incCurrMem(a, request)
+    a.llmem.size = request - sizeof(TLLChunk)
+    a.llmem.acc = sizeof(TLLChunk)
+  result = cast[pointer](cast[TAddress](a.llmem) + a.llmem.acc)
+  dec(a.llmem.size, size)
+  inc(a.llmem.acc, size)
+  zeroMem(result, size)
+  
+proc IntSetGet(t: TIntSet, key: int): PTrunk = 
+  var it = t.data[key and high(t.data)]
+  while it != nil: 
+    if it.key == key: return it
+    it = it.next
+  result = nil
+
+proc IntSetPut(t: var TIntSet, key: int): PTrunk = 
+  result = IntSetGet(t, key)
+  if result == nil:
+    result = cast[PTrunk](llAlloc(allocator, sizeof(result^)))
+    result.next = t.data[key and high(t.data)]
+    t.data[key and high(t.data)] = result
+    result.key = key
+
+proc Contains(s: TIntSet, key: int): bool = 
+  var t = IntSetGet(s, key shr TrunkShift)
+  if t != nil: 
+    var u = key and TrunkMask
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+  else: 
+    result = false
+  
+proc Incl(s: var TIntSet, key: int) = 
+  var t = IntSetPut(s, key shr TrunkShift)
+  var u = key and TrunkMask
+  t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
+
+proc Excl(s: var TIntSet, key: int) = 
+  var t = IntSetGet(s, key shr TrunkShift)
+  if t != nil:
+    var u = key and TrunkMask
+    t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
+        (1 shl (u and IntMask))
+
+proc ContainsOrIncl(s: var TIntSet, key: int): bool = 
+  var t = IntSetGet(s, key shr TrunkShift)
+  if t != nil: 
+    var u = key and TrunkMask
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+    if not result: 
+      t.bits[u shr IntShift] = t.bits[u shr IntShift] or
+          (1 shl (u and IntMask))
+  else: 
+    Incl(s, key)
+    result = false
+   
+# ------------- chunk management ----------------------------------------------
+proc pageIndex(c: PChunk): int {.inline.} = 
+  result = cast[TAddress](c) shr PageShift
+
+proc pageIndex(p: pointer): int {.inline.} = 
+  result = cast[TAddress](p) shr PageShift
+
+proc pageAddr(p: pointer): PChunk {.inline.} = 
+  result = cast[PChunk](cast[TAddress](p) and not PageMask)
+  assert(Contains(allocator.chunkStarts, pageIndex(result)))
+
+var lastSize = PageSize
+
+proc requestOsChunks(a: var TAllocator, size: int): PBigChunk = 
+  incCurrMem(a, size)
+  inc(a.freeMem, size)
+  result = cast[PBigChunk](osAllocPages(size))
+  assert((cast[TAddress](result) and PageMask) == 0)
+  #zeroMem(result, size)
+  result.next = nil
+  result.prev = nil
+  result.used = false
+  result.size = size
+  # update next.prevSize:
+  var nxt = cast[TAddress](result) +% size
+  assert((nxt and PageMask) == 0)
+  var next = cast[PChunk](nxt)
+  if pageIndex(next) in a.chunkStarts:
+    #echo("Next already allocated!")
+    next.prevSize = size
+  # set result.prevSize:
+  var prv = cast[TAddress](result) -% lastSize
+  assert((nxt and PageMask) == 0)
+  var prev = cast[PChunk](prv)
+  if pageIndex(prev) in a.chunkStarts and prev.size == lastSize:
+    #echo("Prev already allocated!")
+    result.prevSize = lastSize
+  else:
+    result.prevSize = 0 # unknown
+  lastSize = size # for next request
+
+proc freeOsChunks(a: var TAllocator, p: pointer, size: int) = 
+  # update next.prevSize:
+  var c = cast[PChunk](p)
+  var nxt = cast[TAddress](p) +% c.size
+  assert((nxt and PageMask) == 0)
+  var next = cast[PChunk](nxt)
+  if pageIndex(next) in a.chunkStarts:
+    next.prevSize = 0 # XXX used
+  excl(a.chunkStarts, pageIndex(p))
+  osDeallocPages(p, size)
+  decCurrMem(a, size)
+  dec(a.freeMem, size)
+  #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
+
+proc isAccessible(p: pointer): bool {.inline.} = 
+  result = Contains(allocator.chunkStarts, pageIndex(p))
+
+proc contains[T](list, x: T): bool = 
+  var it = list
+  while it != nil:
+    if it == x: return true
+    it = it.next
+    
+proc writeFreeList(a: TAllocator) =
+  var it = a.freeChunksList
+  c_fprintf(c_stdout, "freeChunksList: %p\n", it)
+  while it != nil: 
+    c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", 
+              it, it.next, it.prev)
+    it = it.next
+
+proc ListAdd[T](head: var T, c: T) {.inline.} = 
+  assert(c notin head)
+  assert c.prev == nil
+  assert c.next == nil
+  c.next = head
+  if head != nil: 
+    assert head.prev == nil
+    head.prev = c
+  head = c
+
+proc ListRemove[T](head: var T, c: T) {.inline.} =
+  assert(c in head)
+  if c == head: 
+    head = c.next
+    assert c.prev == nil
+    if head != nil: head.prev = nil
+  else:
+    assert c.prev != nil
+    c.prev.next = c.next
+    if c.next != nil: c.next.prev = c.prev
+  c.next = nil
+  c.prev = nil
+  
+proc isSmallChunk(c: PChunk): bool {.inline.} = 
+  return c.size <= SmallChunkSize-smallChunkOverhead()
+  #return c.size < SmallChunkSize
+  
+proc chunkUnused(c: PChunk): bool {.inline.} = 
+  result = not c.used
+  
+proc updatePrevSize(a: var TAllocator, c: PBigChunk, 
+                    prevSize: int) {.inline.} = 
+  var ri = cast[PChunk](cast[TAddress](c) +% c.size)
+  assert((cast[TAddress](ri) and PageMask) == 0)
+  if isAccessible(ri):
+    ri.prevSize = prevSize
+  
+proc freeBigChunk(a: var TAllocator, c: PBigChunk) = 
+  var c = c
+  assert(c.size >= PageSize)
+  inc(a.freeMem, c.size)
+  when coalescRight:
+    var ri = cast[PChunk](cast[TAddress](c) +% c.size)
+    assert((cast[TAddress](ri) and PageMask) == 0)
+    if isAccessible(ri) and chunkUnused(ri):
+      assert(not isSmallChunk(ri))
+      if not isSmallChunk(ri):
+        ListRemove(a.freeChunksList, cast[PBigChunk](ri))
+        inc(c.size, ri.size)
+        excl(a.chunkStarts, pageIndex(ri))
+  when coalescLeft:
+    if c.prevSize != 0: 
+      var le = cast[PChunk](cast[TAddress](c) -% c.prevSize)
+      assert((cast[TAddress](le) and PageMask) == 0)
+      if isAccessible(le) and chunkUnused(le):
+        assert(not isSmallChunk(le))
+        if not isSmallChunk(le):
+          ListRemove(a.freeChunksList, cast[PBigChunk](le))
+          inc(le.size, c.size)
+          excl(a.chunkStarts, pageIndex(c))
+          c = cast[PBigChunk](le)
+
+  if c.size < ChunkOsReturn: 
+    incl(a.chunkStarts, pageIndex(c))
+    updatePrevSize(a, c, c.size)
+    ListAdd(a.freeChunksList, c)
+    c.used = false
+  else:
+    freeOsChunks(a, c, c.size)
+
+proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) = 
+  var rest = cast[PBigChunk](cast[TAddress](c) +% size)
+  if rest in a.freeChunksList: 
+    c_fprintf(c_stdout, "to add: %p\n", rest)
+    writeFreeList(allocator)
+    assert false
+  rest.size = c.size - size
+  rest.used = false
+  rest.next = nil
+  rest.prev = nil
+  rest.prevSize = size
+  updatePrevSize(a, c, rest.size)
+  c.size = size
+  incl(a.chunkStarts, pageIndex(rest))
+  ListAdd(a.freeChunksList, rest)
+
+proc getBigChunk(a: var TAllocator, size: int): PBigChunk = 
+  # use first fit for now:
+  assert((size and PageMask) == 0)
+  assert(size > 0)
+  result = a.freeChunksList
+  block search:
+    while result != nil:
+      #if not chunkUnused(result): 
+      #  c_fprintf(c_stdout, "%lld\n", int(result.used))
+      assert chunkUnused(result)
+      if result.size == size: 
+        ListRemove(a.freeChunksList, result)
+        break search
+      elif result.size > size:
+        #c_fprintf(c_stdout, "res size: %lld; size: %lld\n", result.size, size)
+        ListRemove(a.freeChunksList, result)
+        splitChunk(a, result, size)
+        break search
+      result = result.next
+      assert result != a.freeChunksList
+    if size < InitialMemoryRequest: 
+      result = requestOsChunks(a, InitialMemoryRequest)
+      splitChunk(a, result, size)
+    else:
+      result = requestOsChunks(a, size)
+  result.prevSize = 0 # XXX why is this needed?
+  result.used = true
+  incl(a.chunkStarts, pageIndex(result))
+  dec(a.freeMem, size)
+
+proc getSmallChunk(a: var TAllocator): PSmallChunk = 
+  var res = getBigChunk(a, PageSize)
+  assert res.prev == nil
+  assert res.next == nil
+  result = cast[PSmallChunk](res)
+
+# -----------------------------------------------------------------------------
+
+proc getCellSize(p: pointer): int {.inline.} = 
+  var c = pageAddr(p)
+  result = c.size
+  
+proc rawAlloc(a: var TAllocator, requestedSize: int): pointer =
+  assert(roundup(65, 8) == 72)
+  assert requestedSize >= sizeof(TFreeCell)
+  var size = roundup(requestedSize, MemAlign)
+  #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
+  if size <= SmallChunkSize-smallChunkOverhead(): 
+    # allocate a small block: for small chunks, we use only its next pointer
+    var s = size div MemAlign
+    var c = a.freeSmallChunks[s]
+    if c == nil: 
+      c = getSmallChunk(a)
+      c.freeList = nil
+      assert c.size == PageSize
+      c.size = size
+      c.acc = size
+      c.free = SmallChunkSize - smallChunkOverhead() - size
+      c.next = nil
+      c.prev = nil
+      ListAdd(a.freeSmallChunks[s], c)
+      result = addr(c.data)
+      assert((cast[TAddress](result) and (MemAlign-1)) == 0)
+    else:
+      assert c.next != c
+      #if c.size != size:
+      #  c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
+      assert c.size == size
+      if c.freeList == nil:
+        assert(c.acc + smallChunkOverhead() + size <= SmallChunkSize) 
+        result = cast[pointer](cast[TAddress](addr(c.data)) +% c.acc)
+        inc(c.acc, size)      
+      else:
+        result = c.freeList
+        assert(c.freeList.zeroField == 0)
+        c.freeList = c.freeList.next
+      dec(c.free, size)
+      assert((cast[TAddress](result) and (MemAlign-1)) == 0)
+    if c.free < size: 
+      ListRemove(a.freeSmallChunks[s], c)
+  else:
+    size = roundup(requestedSize+bigChunkOverhead(), PageSize)
+    # allocate a large block
+    var c = getBigChunk(a, size)
+    assert c.prev == nil
+    assert c.next == nil
+    assert c.size == size
+    result = addr(c.data)
+    assert((cast[TAddress](result) and (MemAlign-1)) == 0)
+  assert(isAccessible(result))
+
+proc rawDealloc(a: var TAllocator, p: pointer) = 
+  var c = pageAddr(p)
+  if isSmallChunk(c):
+    # `p` is within a small chunk:
+    var c = cast[PSmallChunk](c)
+    var s = c.size
+    var f = cast[ptr TFreeCell](p)
+    #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
+    assert(f.zeroField != 0)
+    f.zeroField = 0
+    f.next = c.freeList
+    c.freeList = f
+    when overwriteFree: 
+      # set to 0xff to check for usage after free bugs:
+      c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, 
+               s -% sizeof(TFreeCell))
+    # check if it is not in the freeSmallChunks[s] list:
+    if c.free < s:
+      assert c notin a.freeSmallChunks[s div memAlign]
+      # add it to the freeSmallChunks[s] array:
+      ListAdd(a.freeSmallChunks[s div memAlign], c)
+      inc(c.free, s)
+    else:
+      inc(c.free, s)
+      if c.free == SmallChunkSize-smallChunkOverhead():
+        ListRemove(a.freeSmallChunks[s div memAlign], c)
+        c.size = SmallChunkSize
+        freeBigChunk(a, cast[PBigChunk](c))
+  else:
+    # set to 0xff to check for usage after free bugs:
+    when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead())
+    # free big chunk
+    freeBigChunk(a, cast[PBigChunk](c))
+
+proc isAllocatedPtr(a: TAllocator, p: pointer): bool = 
+  if isAccessible(p):
+    var c = pageAddr(p)
+    if not chunkUnused(c):
+      if isSmallChunk(c):
+        var c = cast[PSmallChunk](c)
+        var offset = (cast[TAddress](p) and (PageSize-1)) -% 
+                     smallChunkOverhead()
+        result = (c.acc >% offset) and (offset %% c.size == 0) and
+          (cast[ptr TFreeCell](p).zeroField >% 1)
+      else:
+        var c = cast[PBigChunk](c)
+        result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
+
+# ---------------------- interface to programs -------------------------------
+
+proc alloc(size: int): pointer =
+  result = rawAlloc(allocator, size+sizeof(TFreeCell))
+  cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
+  assert(not isAllocatedPtr(allocator, result))
+  result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell))
+
+proc alloc0(size: int): pointer =
+  result = alloc(size)
+  zeroMem(result, size)
+
+proc dealloc(p: pointer) =
+  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+  assert(cast[ptr TFreeCell](x).zeroField == 1)
+  rawDealloc(allocator, x)
+  assert(not isAllocatedPtr(allocator, x))
+
+proc ptrSize(p: pointer): int =
+  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+  result = pageAddr(x).size - sizeof(TFreeCell)
+
+proc realloc(p: pointer, newsize: int): pointer =
+  if newsize > 0:
+    result = alloc(newsize)
+    if p != nil:
+      copyMem(result, p, ptrSize(p))
+      dealloc(p)
+  elif p != nil:
+    dealloc(p)
+
+proc countFreeMem(): int =
+  # only used for assertions
+  var it = allocator.freeChunksList
+  while it != nil:
+    inc(result, it.size)
+    it = it.next
+
+proc getFreeMem(): int = 
+  result = allocator.freeMem
+  #assert(result == countFreeMem())
+
+proc getTotalMem(): int = return allocator.currMem
+proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
+
+when isMainModule:
+  const iterations = 4000_000
+  incl(allocator.chunkStarts, 11)
+  assert 11 in allocator.chunkStarts
+  excl(allocator.chunkStarts, 11)
+  assert 11 notin allocator.chunkStarts
+  var p: array [1..iterations, pointer]
+  for i in 7..7:
+    var x = i * 8
+    for j in 1.. iterations:
+      p[j] = alloc(allocator, x)
+    for j in 1..iterations:
+      assert isAllocatedPtr(allocator, p[j])
+    echo($i, " used memory: ", $(allocator.currMem))
+    for j in countdown(iterations, 1):
+      #echo("j: ", $j)
+      dealloc(allocator, p[j])
+      assert(not isAllocatedPtr(allocator, p[j]))
+    echo($i, " after freeing: ", $(allocator.currMem))
+    
diff --git a/nimlib/system/ansi_c.nim b/nimlib/system/ansi_c.nim
new file mode 100755
index 000000000..e9300949b
--- /dev/null
+++ b/nimlib/system/ansi_c.nim
@@ -0,0 +1,105 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include file contains headers of Ansi C procs
+# and definitions of Ansi C types in Nimrod syntax
+# All symbols are prefixed with 'c_' to avoid ambiguities
+
+{.push hints:off}
+
+proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".}
+proc c_memcmp(a, b: CString, size: cint): cint {.
+  nodecl, noSideEffect, importc: "memcmp".}
+proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
+proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".}
+proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".}
+
+type
+  C_TextFile {.importc: "FILE", nodecl, final.} = object   # empty record for
+                                                           # data hiding
+  C_BinaryFile {.importc: "FILE", nodecl, final.} = object
+  C_TextFileStar = ptr CTextFile
+  C_BinaryFileStar = ptr CBinaryFile
+
+  C_JmpBuf {.importc: "jmp_buf".} = array[0..31, int]
+
+var
+  c_stdin {.importc: "stdin", noDecl.}: C_TextFileStar
+  c_stdout {.importc: "stdout", noDecl.}: C_TextFileStar
+  c_stderr {.importc: "stderr", noDecl.}: C_TextFileStar
+
+var # constants faked as variables:
+  SIGINT {.importc: "SIGINT", nodecl.}: cint
+  SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
+  SIGABRT {.importc: "SIGABRT", nodecl.}: cint
+  SIGFPE {.importc: "SIGFPE", nodecl.}: cint
+  SIGILL {.importc: "SIGILL", nodecl.}: cint
+
+when defined(macosx):
+  var
+    SIGBUS {.importc: "SIGBUS", nodecl.}: cint
+      # hopefully this does not lead to new bugs
+else:
+  var
+    SIGBUS {.importc: "SIGSEGV", nodecl.}: cint
+      # only Mac OS X has this shit
+
+proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.nodecl, importc: "longjmp".}
+proc c_setjmp(jmpb: var C_JmpBuf): cint {.nodecl, importc: "setjmp".}
+
+proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
+  importc: "signal", header: "<signal.h>".}
+proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
+
+proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", noDecl.}
+proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring  {.
+  importc: "fgets", noDecl.}
+proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", nodecl.}
+proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", nodecl.}
+proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc", nodecl.}
+proc c_fprintf(f: C_TextFileStar, frmt: CString) {.
+  importc: "fprintf", nodecl, varargs.}
+
+proc c_fopen(filename, mode: cstring): C_TextFileStar {.
+  importc: "fopen", nodecl.}
+proc c_fclose(f: C_TextFileStar) {.importc: "fclose", nodecl.}
+
+proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.}
+  # we use it only in a way that cannot lead to security issues
+
+proc c_fread(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
+  importc: "fread", noDecl.}
+proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
+  importc: "fseek", noDecl.}
+
+proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
+  importc: "fwrite", noDecl.}
+
+proc c_exit(errorcode: cint) {.importc: "exit", nodecl.}
+proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.}
+proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.}
+proc c_abort() {.importc: "abort", nodecl.}
+proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.}
+
+proc c_malloc(size: int): pointer {.importc: "malloc", nodecl.}
+proc c_free(p: pointer) {.importc: "free", nodecl.}
+proc c_realloc(p: pointer, newsize: int): pointer {.importc: "realloc", nodecl.}
+
+var errno {.importc, header: "<errno.h>".}: cint ## error variable
+proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
+
+proc c_remove(filename: CString): cint {.importc: "remove", noDecl.}
+proc c_rename(oldname, newname: CString): cint {.importc: "rename", noDecl.}
+
+proc c_system(cmd: CString): cint {.importc: "system", header: "<stdlib.h>".}
+proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.}
+proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.}
+
+{.pop}
+
diff --git a/nimlib/system/arithm.nim b/nimlib/system/arithm.nim
new file mode 100755
index 000000000..f097ee794
--- /dev/null
+++ b/nimlib/system/arithm.nim
@@ -0,0 +1,316 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# simple integer arithmetic with overflow checking
+
+proc raiseOverflow {.compilerproc, noinline, noreturn.} =
+  # a single proc to reduce code size to a minimum
+  raise newException(EOverflow, "over- or underflow")
+
+proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
+  raise newException(EDivByZero, "divison by zero")
+
+proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  result = a +% b
+  if (result xor a) >= int64(0) or (result xor b) >= int64(0):
+    return result
+  raiseOverflow()
+
+proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  result = a -% b
+  if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
+    return result
+  raiseOverflow()
+
+proc negInt64(a: int64): int64 {.compilerProc, inline.} =
+  if a != low(int64): return -a
+  raiseOverflow()
+
+proc absInt64(a: int64): int64 {.compilerProc, inline.} =
+  if a != low(int64):
+    if a >= 0: return a
+    else: return -a
+  raiseOverflow()
+
+proc divInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  if b == int64(0):
+    raiseDivByZero()
+  if a == low(int64) and b == int64(-1):
+    raiseOverflow()
+  return a div b
+
+proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  if b == int64(0):
+    raiseDivByZero()
+  return a mod b
+
+#
+# This code has been inspired by Python's source code.
+# The native int product x*y is either exactly right or *way* off, being
+# just the last n bits of the true product, where n is the number of bits
+# in an int (the delivered product is the true product plus i*2**n for
+# some integer i).
+#
+# The native float64 product x*y is subject to three
+# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
+# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
+# But, unlike the native int product, it's not in *range* trouble:  even
+# if sizeof(int)==32 (256-bit ints), the product easily fits in the
+# dynamic range of a float64. So the leading 50 (or so) bits of the float64
+# product are correct.
+#
+# We check these two ways against each other, and declare victory if they're
+# approximately the same. Else, because the native int product is the only
+# one that can lose catastrophic amounts of information, it's the native int
+# product that must have overflowed.
+#
+proc mulInt64(a, b: int64): int64 {.compilerproc.} =
+  var
+    resAsFloat, floatProd: float64
+  result = a *% b
+  floatProd = toBiggestFloat(a) # conversion
+  floatProd = floatProd * toBiggestFloat(b)
+  resAsFloat = toBiggestFloat(result)
+
+  # Fast path for normal case: small multiplicands, and no info
+  # is lost in either method.
+  if resAsFloat == floatProd: return result
+
+  # Somebody somewhere lost info. Close enough, or way off? Note
+  # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
+  # The difference either is or isn't significant compared to the
+  # true value (of which floatProd is a good approximation).
+
+  # abs(diff)/abs(prod) <= 1/32 iff
+  #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
+  if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+    return result
+  raiseOverflow()
+
+
+proc absInt(a: int): int {.compilerProc, inline.} =
+  if a != low(int):
+    if a >= 0: return a
+    else: return -a
+  raiseOverflow()
+
+const
+  asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or
+               defined(dmc) or defined(gcc) or defined(llvm_gcc))
+    # my Version of Borland C++Builder does not have
+    # tasm32, which is needed for assembler blocks
+    # this is why Borland is not included in the 'when'
+
+when asmVersion and not defined(gcc) and not defined(llvm_gcc):
+  # assembler optimized versions for compilers that
+  # have an intel syntax assembler:
+  proc addInt(a, b: int): int {.compilerProc, pure.} =
+    # a in eax, and b in edx
+    asm """
+        mov eax, `a`
+        add eax, `b`
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+
+  proc subInt(a, b: int): int {.compilerProc, pure.} =
+    asm """
+        mov eax, `a`
+        sub eax, `b`
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+
+  proc negInt(a: int): int {.compilerProc, pure.} =
+    asm """
+        mov eax, `a`
+        neg eax
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+
+  proc divInt(a, b: int): int {.compilerProc, pure.} =
+    asm """
+        mov eax, `a`
+        mov ecx, `b`
+        xor edx, edx
+        idiv ecx
+        jno  theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+
+  proc modInt(a, b: int): int {.compilerProc, pure.} =
+    asm """
+        mov eax, `a`
+        mov ecx, `b`
+        xor edx, edx
+        idiv ecx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        mov eax, edx
+    """
+
+  proc mulInt(a, b: int): int {.compilerProc, pure.} =
+    asm """
+        mov eax, `a`
+        mov ecx, `b`
+        xor edx, edx
+        imul ecx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+
+elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
+  proc addInt(a, b: int): int {.compilerProc, inline.} =
+    # don't use a pure proc here!
+    asm """
+      "addl %%ecx, %%eax\n"
+      "jno 1\n"
+      "call _raiseOverflow\n"
+      "1: \n"
+      :"=a"(`result`)
+      :"a"(`a`), "c"(`b`)
+    """
+
+  proc subInt(a, b: int): int {.compilerProc, inline.} =
+    asm """ "subl %%ecx,%%eax\n"
+            "jno 1\n"
+            "call _raiseOverflow\n"
+            "1: \n"
+           :"=a"(`result`)
+           :"a"(`a`), "c"(`b`)
+    """
+
+  proc mulInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "imull %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+  proc negInt(a: int): int {.compilerProc, inline.} =
+    asm """ "negl %%eax\n"
+            "jno 1\n"
+            "call _raiseOverflow\n"
+            "1: \n"
+           :"=a"(`result`)
+           :"a"(`a`)
+    """
+
+  proc divInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "idivl %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+  proc modInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "idivl %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+             "movl %%edx, %%eax"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+# Platform independant versions of the above (slower!)
+when not defined(addInt):
+  proc addInt(a, b: int): int {.compilerProc, inline.} =
+    result = a +% b
+    if (result xor a) >= 0 or (result xor b) >= 0:
+      return result
+    raiseOverflow()
+
+when not defined(subInt):
+  proc subInt(a, b: int): int {.compilerProc, inline.} =
+    result = a -% b
+    if (result xor a) >= 0 or (result xor not b) >= 0:
+      return result
+    raiseOverflow()
+
+when not defined(negInt):
+  proc negInt(a: int): int {.compilerProc, inline.} =
+    if a != low(int): return -a
+    raiseOverflow()
+
+when not defined(divInt):
+  proc divInt(a, b: int): int {.compilerProc, inline.} =
+    if b == 0:
+      raiseDivByZero()
+    if a == low(int) and b == -1:
+      raiseOverflow()
+    return a div b
+
+when not defined(modInt):
+  proc modInt(a, b: int): int {.compilerProc, inline.} =
+    if b == 0:
+      raiseDivByZero()
+    return a mod b
+
+when not defined(mulInt):
+  #
+  # This code has been inspired by Python's source code.
+  # The native int product x*y is either exactly right or *way* off, being
+  # just the last n bits of the true product, where n is the number of bits
+  # in an int (the delivered product is the true product plus i*2**n for
+  # some integer i).
+  #
+  # The native float64 product x*y is subject to three
+  # rounding errors: on a sizeof(int)==8 box, each cast to double can lose
+  # info, and even on a sizeof(int)==4 box, the multiplication can lose info.
+  # But, unlike the native int product, it's not in *range* trouble:  even
+  # if sizeof(int)==32 (256-bit ints), the product easily fits in the
+  # dynamic range of a float64. So the leading 50 (or so) bits of the float64
+  # product are correct.
+  #
+  # We check these two ways against each other, and declare victory if
+  # they're approximately the same. Else, because the native int product is
+  # the only one that can lose catastrophic amounts of information, it's the
+  # native int product that must have overflowed.
+  #
+  proc mulInt(a, b: int): int {.compilerProc.} =
+    var
+      resAsFloat, floatProd: float
+
+    result = a *% b
+    floatProd = toFloat(a) * toFloat(b)
+    resAsFloat = toFloat(result)
+
+    # Fast path for normal case: small multiplicands, and no info
+    # is lost in either method.
+    if resAsFloat == floatProd: return result
+
+    # Somebody somewhere lost info. Close enough, or way off? Note
+    # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
+    # The difference either is or isn't significant compared to the
+    # true value (of which floatProd is a good approximation).
+
+    # abs(diff)/abs(prod) <= 1/32 iff
+    #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
+    if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+      return result
+    raiseOverflow()
diff --git a/nimlib/system/assign.nim b/nimlib/system/assign.nim
new file mode 100755
index 000000000..44d2e5c64
--- /dev/null
+++ b/nimlib/system/assign.nim
@@ -0,0 +1,120 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#when defined(debugGC):
+#  {.define: logAssign.}
+proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
+proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
+  var
+    d = cast[TAddress](dest)
+    s = cast[TAddress](src)
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+                  n.typ)
+  of nkList:
+    for i in 0..n.len-1:
+      genericAssignAux(dest, src, n.sons[i])
+  of nkCase:
+    copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+            n.typ.size)
+    var m = selectBranch(src, n)
+    if m != nil: genericAssignAux(dest, src, m)
+
+proc genericAssign(dest, src: Pointer, mt: PNimType) =
+  var
+    d = cast[TAddress](dest)
+    s = cast[TAddress](src)
+
+  assert(mt != nil)
+  case mt.Kind
+  of tySequence:
+    var s2 = cast[ppointer](src)^
+    var seq = cast[PGenericSeq](s2)
+    if s2 == nil:  # this can happen! nil sequences are allowed
+      var x = cast[ppointer](dest)
+      x^ = nil
+      return
+    assert(dest != nil)
+    unsureAsgnRef(cast[ppointer](dest),
+                  newObj(mt, seq.len * mt.base.size + GenericSeqSize))
+    var dst = cast[taddress](cast[ppointer](dest)^)
+    for i in 0..seq.len-1:
+      genericAssign(
+        cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+        cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
+                     GenericSeqSize),
+        mt.Base)
+    var dstseq = cast[PGenericSeq](dst)
+    dstseq.len = seq.len
+    dstseq.space = seq.len
+  of tyObject, tyTuple, tyPureObject:
+    # we don't need to copy m_type field for tyObject, as they are equal anyway
+    genericAssignAux(dest, src, mt.node)
+  of tyArray, tyArrayConstr:
+    for i in 0..(mt.size div mt.base.size)-1:
+      genericAssign(cast[pointer](d +% i*% mt.base.size),
+                    cast[pointer](s +% i*% mt.base.size), mt.base)
+  of tyString: # a leaf
+    var s2 = cast[ppointer](s)^
+    if s2 != nil: # nil strings are possible!
+      unsureAsgnRef(cast[ppointer](dest), copyString(cast[NimString](s2)))
+    else:
+      var x = cast[ppointer](dest)
+      x^ = nil
+      return
+  of tyRef:  # BUGFIX: a long time this has been forgotten!
+    unsureAsgnRef(cast[ppointer](dest), cast[ppointer](s)^)
+  else:
+    copyMem(dest, src, mt.size) # copy raw bits
+
+proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
+  var src = src # ugly, but I like to stress the parser sometimes :-)
+  genericAssign(dest, addr(src), mt)
+
+proc genericAssignOpenArray(dest, src: pointer, len: int,
+                            mt: PNimType) {.compilerproc.} =
+  var
+    d = cast[TAddress](dest)
+    s = cast[TAddress](src)
+  for i in 0..len-1:
+    genericAssign(cast[pointer](d +% i*% mt.base.size),
+                  cast[pointer](s +% i*% mt.base.size), mt.base)
+
+proc objectInit(dest: Pointer, typ: PNimType) {.compilerProc.}
+proc objectInitAux(dest: Pointer, n: ptr TNimNode) =
+  var d = cast[TAddress](dest)
+  case n.kind
+  of nkNone: assert(false)
+  of nkSLot: objectInit(cast[pointer](d +% n.offset), n.typ)
+  of nkList:
+    for i in 0..n.len-1:
+      objectInitAux(dest, n.sons[i])
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: objectInitAux(dest, m)
+
+proc objectInit(dest: Pointer, typ: PNimType) =
+  # the generic init proc that takes care of initialization of complex
+  # objects on the stack or heap
+  var d = cast[TAddress](dest)
+  case typ.kind
+  of tyObject:
+    # iterate over any structural type
+    # here we have to init the type field:
+    var pint = cast[ptr PNimType](dest)
+    pint^ = typ
+    objectInitAux(dest, typ.node)
+  of tyTuple, tyPureObject:
+    objectInitAux(dest, typ.node)
+  of tyArray, tyArrayConstr:
+    for i in 0..(typ.size div typ.base.size)-1:
+      objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
+  else: nil # nothing to do
diff --git a/nimlib/system/cellsets.nim b/nimlib/system/cellsets.nim
new file mode 100755
index 000000000..0ce83864c
--- /dev/null
+++ b/nimlib/system/cellsets.nim
@@ -0,0 +1,196 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Efficient set of pointers for the GC (and repr)
+
+type
+  TCell {.pure.} = object
+    refcount: int  # the refcount and some flags
+    typ: PNimType
+    when debugGC:
+      filename: cstring
+      line: int
+
+  PCell = ptr TCell
+
+  PPageDesc = ptr TPageDesc
+  TBitIndex = range[0..UnitsPerPage-1]
+  TPageDesc {.final, pure.} = object
+    next: PPageDesc # all nodes are connected with this pointer
+    key: TAddress   # start address at bit 0
+    bits: array[TBitIndex, int] # a bit vector
+
+  PPageDescArray = ptr array[0..1000_000, PPageDesc]
+  TCellSet {.final, pure.} = object
+    counter, max: int
+    head: PPageDesc
+    data: PPageDescArray
+
+  PCellArray = ptr array[0..100_000_000, PCell]
+  TCellSeq {.final, pure.} = object
+    len, cap: int
+    d: PCellArray
+
+# ------------------- cell set handling ---------------------------------------
+
+proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
+  for i in 0 .. s.len-1:
+    if s.d[i] == c: return True
+  return False
+
+proc add(s: var TCellSeq, c: PCell) {.inline.} =
+  if s.len >= s.cap:
+    s.cap = s.cap * 3 div 2
+    var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
+    copyMem(d, s.d, s.len * sizeof(PCell))
+    dealloc(s.d)
+    s.d = d
+    # XXX: realloc?
+  s.d[s.len] = c
+  inc(s.len)
+
+proc init(s: var TCellSeq, cap: int = 1024) =
+  s.len = 0
+  s.cap = cap
+  s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
+
+proc deinit(s: var TCellSeq) = 
+  dealloc(s.d)
+  s.d = nil
+  s.len = 0
+  s.cap = 0
+
+const
+  InitCellSetSize = 1024 # must be a power of two!
+
+proc Init(s: var TCellSet) =
+  s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
+  s.max = InitCellSetSize-1
+  s.counter = 0
+  s.head = nil
+
+proc Deinit(s: var TCellSet) =
+  var it = s.head
+  while it != nil:
+    var n = it.next
+    dealloc(it)
+    it = n
+  s.head = nil # play it safe here
+  dealloc(s.data)
+  s.data = nil
+  s.counter = 0
+
+proc nextTry(h, maxHash: int): int {.inline.} =
+  result = ((5*h) + 1) and maxHash
+  # For any initial h in range(maxHash), repeating that maxHash times
+  # generates each int in range(maxHash) exactly once (see any text on
+  # random-number generation for proof).
+  
+proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while t.data[h] != nil:
+    if t.data[h].key == key: return t.data[h]
+    h = nextTry(h, t.max)
+  return nil
+
+proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
+  var h = cast[int](desc.key) and t.max
+  while data[h] != nil:
+    assert(data[h] != desc)
+    h = nextTry(h, t.max)
+  assert(data[h] == nil)
+  data[h] = desc
+
+proc CellSetEnlarge(t: var TCellSet) =
+  var oldMax = t.max
+  t.max = ((t.max+1)*2)-1
+  var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
+  for i in 0 .. oldmax:
+    if t.data[i] != nil:
+      CellSetRawInsert(t, n, t.data[i])
+  dealloc(t.data)
+  t.data = n
+
+proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while true:
+    var x = t.data[h]
+    if x == nil: break
+    if x.key == key: return x
+    h = nextTry(h, t.max)
+
+  if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
+    CellSetEnlarge(t)
+  inc(t.counter)
+  h = cast[int](key) and t.max
+  while t.data[h] != nil: h = nextTry(h, t.max)
+  assert(t.data[h] == nil)
+  # the new page descriptor goes into result
+  result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
+  result.next = t.head
+  result.key = key
+  t.head = result
+  t.data[h] = result
+
+# ---------- slightly higher level procs --------------------------------------
+
+proc contains(s: TCellSet, cell: PCell): bool =
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+  else:
+    result = false
+
+proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
+  var u = cast[TAddress](cell)
+  var t = CellSetPut(s, u shr PageShift)
+  u = (u %% PageSize) /% MemAlign
+  t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
+
+proc excl(s: var TCellSet, cell: PCell) =
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
+                              not (1 shl (u and IntMask)))
+
+proc containsOrIncl(s: var TCellSet, cell: PCell): bool = 
+  var u = cast[TAddress](cell)
+  var t = CellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+    if not result: 
+      t.bits[u shr IntShift] = t.bits[u shr IntShift] or
+          (1 shl (u and IntMask))
+  else: 
+    Incl(s, cell)
+    result = false
+
+iterator elements(t: TCellSet): PCell {.inline.} =
+  # while traversing it is forbidden to add pointers to the tree!
+  var r = t.head
+  while r != nil:
+    var i = 0
+    while i <= high(r.bits):
+      var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
+      # modifying operations are not allowed during traversation
+      var j = 0
+      while w != 0:         # test all remaining bits for zero
+        if (w and 1) != 0:  # the bit is set!
+          yield cast[PCell]((r.key shl PageShift) or
+                              (i shl IntShift +% j) *% MemAlign)
+        inc(j)
+        w = w shr 1
+      inc(i)
+    r = r.next
+
diff --git a/nimlib/system/cntbits.nim b/nimlib/system/cntbits.nim
new file mode 100755
index 000000000..281b96dd0
--- /dev/null
+++ b/nimlib/system/cntbits.nim
@@ -0,0 +1,12 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+
+
diff --git a/nimlib/system/debugger.nim b/nimlib/system/debugger.nim
new file mode 100755
index 000000000..01d8bd8a2
--- /dev/null
+++ b/nimlib/system/debugger.nim
@@ -0,0 +1,500 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the embedded debugger that can be linked
+# with the application. We should not use dynamic memory here as that
+# would interfere with the GC and trigger ON/OFF errors if the
+# user program corrupts memory. Unfortunately, for dispaying
+# variables we use the ``system.repr()`` proc which uses Nimrod
+# strings and thus allocates memory from the heap. Pity, but
+# I do not want to implement ``repr()`` twice. We also cannot deactivate
+# the GC here as that might run out of memory too quickly...
+
+type
+  TDbgState = enum
+    dbOff,        # debugger is turned off
+    dbStepInto,   # debugger is in tracing mode
+    dbStepOver,
+    dbSkipCurrent,
+    dbQuiting,    # debugger wants to quit
+    dbBreakpoints # debugger is only interested in breakpoints
+
+  TDbgBreakpoint {.final.} = object
+    low, high: int   # range from low to high; if disabled
+                     # both low and high are set to their negative values
+                     # this makes the check faster and safes memory
+    filename: string
+    name: string     # name of breakpoint
+
+  TVarSlot {.compilerproc, final.} = object # variable slots used for debugger:
+    address: pointer
+    typ: PNimType
+    name: cstring   # for globals this is "module.name"
+
+  PExtendedFrame = ptr TExtendedFrame
+  TExtendedFrame {.final.} = object  # If the debugger is enabled the compiler
+                                     # provides an extended frame. Of course
+                                     # only slots that are
+                                     # needed are allocated and not 10_000,
+                                     # except for the global data description.
+    f: TFrame
+    slots: array[0..10_000, TVarSlot]
+
+var
+  dbgInSignal: bool # wether the debugger is in the signal handler
+  dbgIn: TFile # debugger input stream
+  dbgUser: string = "s" # buffer for user input; first command is ``step_into``
+                        # needs to be global cause we store the last command
+                        # in it
+  dbgState: TDbgState = dbStepInto # state of debugger
+  dbgBP: array[0..127, TDbgBreakpoint] # breakpoints
+  dbgBPlen: int = 0
+
+  dbgSkipToFrame: PFrame # frame to be skipped to
+
+  dbgGlobalData: TExtendedFrame # this reserves much space, but
+                                # for now it is the most practical way
+
+  maxDisplayRecDepth: int = 5 # do not display too much data!
+
+proc findBreakpoint(name: string): int =
+  # returns -1 if not found
+  for i in countdown(dbgBPlen-1, 0):
+    if name == dbgBP[i].name: return i
+  return -1
+
+proc ListBreakPoints() =
+  write(stdout, "*** endb| Breakpoints:\n")
+  for i in 0 .. dbgBPlen-1:
+    write(stdout, dbgBP[i].name & ": " & $abs(dbgBP[i].low) & ".." &
+                  $abs(dbgBP[i].high) & dbgBP[i].filename)
+    if dbgBP[i].low < 0:
+      write(stdout, " [disabled]\n")
+    else:
+      write(stdout, "\n")
+  write(stdout, "***\n")
+
+proc openAppend(filename: string): TFile =
+  if open(result, filename, fmAppend):
+    write(result, "----------------------------------------\n")
+
+proc dbgRepr(p: pointer, typ: PNimType): string =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  cl.recDepth = maxDisplayRecDepth
+  # locks for the GC turned out to be a bad idea...
+  # inc(recGcLock)
+  result = ""
+  reprAux(result, p, typ, cl)
+  # dec(recGcLock)
+  deinitReprClosure(cl)
+
+proc writeVariable(stream: TFile, slot: TVarSlot) =
+  write(stream, slot.name)
+  write(stream, " = ")
+  writeln(stream, dbgRepr(slot.address, slot.typ))
+
+proc ListFrame(stream: TFile, f: PExtendedFrame) =
+  write(stream, "*** endb| Frame (" & $f.f.len &  " slots):\n")
+  for i in 0 .. f.f.len-1:
+    writeVariable(stream, f.slots[i])
+  write(stream, "***\n")
+
+proc ListVariables(stream: TFile, f: PExtendedFrame) =
+  write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n")
+  for i in 0 .. f.f.len-1:
+    writeln(stream, f.slots[i].name)
+  write(stream, "***\n")
+
+proc debugOut(msg: cstring) =
+  # the *** *** markers are for easy recognition of debugger
+  # output for external frontends.
+  write(stdout, "*** endb| ")
+  write(stdout, msg)
+  write(stdout, "***\n")
+
+proc dbgFatal(msg: cstring) =
+  debugOut(msg)
+  dbgAborting = True # the debugger wants to abort
+  quit(1)
+
+proc findVariable(frame: PExtendedFrame, varname: cstring): int =
+  for i in 0 .. frame.f.len - 1:
+    if c_strcmp(frame.slots[i].name, varname) == 0: return i
+  return -1
+
+proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
+  if dbgFramePointer != nil:
+    write(stdout, "*** endb| now in proc: ")
+    write(stdout, dbgFramePointer.procname)
+    write(stdout, " ***\n")
+  else:
+    write(stdout, "*** endb| (procedure name not available) ***\n")
+
+proc dbgShowExecutionPoint() =
+  write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line &
+                ") " & $framePtr.procname & " ***\n")
+
+when defined(windows) or defined(dos) or defined(os2):
+  {.define: FileSystemCaseInsensitive.}
+
+proc fileMatches(c, bp: cstring): bool =
+  # bp = breakpoint filename
+  # c = current filename
+  # we consider it a match if bp is a suffix of c
+  # and the character for the suffix does not exist or
+  # is one of: \  /  :
+  # depending on the OS case does not matter!
+  var blen: int = c_strlen(bp)
+  var clen: int = c_strlen(c)
+  if blen > clen: return false
+  # check for \ /  :
+  if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}:
+    return false
+  var i = 0
+  while i < blen:
+    var x, y: char
+    x = bp[i]
+    y = c[i+clen-blen]
+    when defined(FileSystemCaseInsensitive):
+      if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
+      if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
+    if x != y: return false
+    inc(i)
+  return true
+
+proc dbgBreakpointReached(line: int): int =
+  for i in 0..dbgBPlen-1:
+    if line >= dbgBP[i].low and line <= dbgBP[i].high and
+        fileMatches(framePtr.filename, dbgBP[i].filename): return i
+  return -1
+
+proc scanAndAppendWord(src: string, a: var string, start: int): int =
+  result = start
+  # skip whitespace:
+  while src[result] in {'\t', ' '}: inc(result)
+  while True:
+    case src[result]
+    of 'a'..'z', '0'..'9': add(a, src[result])
+    of '_': nil # just skip it
+    of 'A'..'Z': add(a, chr(ord(src[result]) - ord('A') + ord('a')))
+    else: break
+    inc(result)
+
+proc scanWord(src: string, a: var string, start: int): int =
+  a = ""
+  result = scanAndAppendWord(src, a, start)
+
+proc scanFilename(src: string, a: var string, start: int): int =
+  result = start
+  a = ""
+  # skip whitespace:
+  while src[result] in {'\t', ' '}: inc(result)
+  while src[result] notin {'\t', ' ', '\0'}:
+    add(a, src[result])
+    inc(result)
+
+proc scanNumber(src: string, a: var int, start: int): int =
+  result = start
+  a = 0
+  while src[result] in {'\t', ' '}: inc(result)
+  while true:
+    case src[result]
+    of '0'..'9': a = a * 10 + ord(src[result]) - ord('0')
+    of '_': nil # skip underscores (nice for long line numbers)
+    else: break
+    inc(result)
+
+proc dbgHelp() =
+  debugOut("""
+list of commands (see the manual for further help):
+              GENERAL
+h, help                 display this help message
+q, quit                 quit the debugger and the program
+<ENTER>                 repeat the previous debugger command
+              EXECUTING
+s, step                 single step, stepping into routine calls
+n, next                 single step, without stepping into routine calls
+f, skipcurrent          continue execution until the current routine finishes
+c, continue             continue execution until the next breakpoint
+i, ignore               continue execution, ignore all breakpoints
+              BREAKPOINTS
+b, break <name> [fromline [toline]] [file]
+                        set a new breakpoint named 'name' for line and file
+                        if line or file are omitted the current one is used
+breakpoints             display the entire breakpoint list
+disable <name>          disable a breakpoint
+enable  <name>          enable a breakpoint
+              DATA DISPLAY
+e, eval <expr>          evaluate the expression <expr>
+o, out <file> <expr>    evaluate <expr> and write it to <file>
+w, where                display the current execution point
+stackframe [file]       display current stack frame [and write it to file]
+u, up                   go up in the call stack
+d, down                 go down in the call stack
+bt, backtrace           display the entire call stack
+l, locals               display available local variables
+g, globals              display available global variables
+maxdisplay <integer>    set the display's recursion maximum
+""")
+
+proc InvalidCommand() =
+  debugOut("[Warning] invalid command ignored (type 'h' for help) ")
+
+proc hasExt(s: string): bool =
+  # returns true if s has a filename extension
+  for i in countdown(len(s)-1, 0):
+    if s[i] == '.': return true
+  return false
+
+proc setBreakPoint(s: string, start: int) =
+  var dbgTemp: string
+  var i = scanWord(s, dbgTemp, start)
+  if i <= start:
+    InvalidCommand()
+    return
+  if dbgBPlen >= high(dbgBP):
+    debugOut("[Warning] no breakpoint could be set; out of breakpoint space ")
+    return
+  var x = dbgBPlen
+  inc(dbgBPlen)
+  dbgBP[x].name = dbgTemp
+  i = scanNumber(s, dbgBP[x].low, i)
+  if dbgBP[x].low == 0:
+    # set to current line:
+    dbgBP[x].low = framePtr.line
+  i = scanNumber(s, dbgBP[x].high, i)
+  if dbgBP[x].high == 0: # set to low:
+    dbgBP[x].high = dbgBP[x].low
+  i = scanFilename(s, dbgTemp, i)
+  if not (dbgTemp.len == 0):
+    if not hasExt(dbgTemp): add(dbgTemp, ".nim")
+    dbgBP[x].filename = dbgTemp
+  else: # use current filename
+    dbgBP[x].filename = $framePtr.filename
+  # skip whitespace:
+  while s[i] in {' ', '\t'}: inc(i)
+  if s[i] != '\0':
+    dec(dbgBPLen) # remove buggy breakpoint
+    InvalidCommand()
+
+proc BreakpointSetEnabled(s: string, start, enabled: int) =
+  var dbgTemp: string
+  var i = scanWord(s, dbgTemp, start)
+  if i <= start:
+    InvalidCommand()
+    return
+  var x = findBreakpoint(dbgTemp)
+  if x < 0: debugOut("[Warning] breakpoint does not exist ")
+  elif enabled * dbgBP[x].low < 0: # signs are different?
+    dbgBP[x].low = -dbgBP[x].low
+    dbgBP[x].high = -dbgBP[x].high
+
+proc dbgEvaluate(stream: TFile, s: string, start: int,
+                 currFrame: PExtendedFrame) =
+  var dbgTemp: string
+  var i = scanWord(s, dbgTemp, start)
+  while s[i] in {' ', '\t'}: inc(i)
+  var f = currFrame
+  if s[i] == '.':
+    inc(i) # skip '.'
+    add(dbgTemp, '.')
+    i = scanAndAppendWord(s, dbgTemp, i)
+    # search for global var:
+    f = addr(dbgGlobalData)
+  if s[i] != '\0':
+    debugOut("[Warning] could not parse expr ")
+    return
+  var j = findVariable(f, dbgTemp)
+  if j < 0:
+    debugOut("[Warning] could not find variable ")
+    return
+  writeVariable(stream, f.slots[j])
+
+proc dbgOut(s: string, start: int, currFrame: PExtendedFrame) =
+  var dbgTemp: string
+  var i = scanFilename(s, dbgTemp, start)
+  if dbgTemp.len == 0:
+    InvalidCommand()
+    return
+  var stream = openAppend(dbgTemp)
+  if stream == nil:
+    debugOut("[Warning] could not open or create file ")
+    return
+  dbgEvaluate(stream, s, i, currFrame)
+  close(stream)
+
+proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
+  var dbgTemp: string
+  var i = scanFilename(s, dbgTemp, start)
+  if dbgTemp.len == 0:
+    # just write it to stdout:
+    ListFrame(stdout, currFrame)
+  else:
+    var stream = openAppend(dbgTemp)
+    if stream == nil:
+      debugOut("[Warning] could not open or create file ")
+      return
+    ListFrame(stream, currFrame)
+    close(stream)
+
+proc CommandPrompt() =
+  # if we return from this routine, user code executes again
+  var
+    again = True
+    dbgFramePtr = framePtr # for going down and up the stack
+    dbgDown = 0 # how often we did go down
+
+  while again:
+    write(stdout, "*** endb| >>")
+    var tmp = readLine(stdin)
+    if tmp.len > 0: dbgUser = tmp
+    # now look what we have to do:
+    var dbgTemp: string
+    var i = scanWord(dbgUser, dbgTemp, 0)
+    case dbgTemp
+    of "": InvalidCommand()
+    of "s", "step":
+      dbgState = dbStepInto
+      again = false
+    of "n", "next":
+      dbgState = dbStepOver
+      dbgSkipToFrame = framePtr
+      again = false
+    of "f", "skipcurrent":
+      dbgState = dbSkipCurrent
+      dbgSkipToFrame = framePtr.prev
+      again = false
+    of "c", "continue":
+      dbgState = dbBreakpoints
+      again = false
+    of "i", "ignore":
+      dbgState = dbOff
+      again = false
+    of "h", "help":
+      dbgHelp()
+    of "q", "quit":
+      dbgState = dbQuiting
+      dbgAborting = True
+      again = false
+      quit(1) # BUGFIX: quit with error code > 0
+    of "e", "eval":
+      dbgEvaluate(stdout, dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
+    of "o", "out":
+      dbgOut(dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
+    of "stackframe":
+      dbgStackFrame(dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
+    of "w", "where":
+      dbgShowExecutionPoint()
+    of "l", "locals":
+      ListVariables(stdout, cast[PExtendedFrame](dbgFramePtr))
+    of "g", "globals":
+      ListVariables(stdout, addr(dbgGlobalData))
+    of "u", "up":
+      if dbgDown <= 0:
+        debugOut("[Warning] cannot go up any further ")
+      else:
+        dbgFramePtr = framePtr
+        for j in 0 .. dbgDown-2: # BUGFIX
+          dbgFramePtr = dbgFramePtr.prev
+        dec(dbgDown)
+      dbgShowCurrentProc(dbgFramePtr)
+    of "d", "down":
+      if dbgFramePtr != nil:
+        inc(dbgDown)
+        dbgFramePtr = dbgFramePtr.prev
+        dbgShowCurrentProc(dbgFramePtr)
+      else:
+        debugOut("[Warning] cannot go down any further ")
+    of "bt", "backtrace":
+      WriteStackTrace()
+    of "b", "break":
+      setBreakPoint(dbgUser, i)
+    of "breakpoints":
+      ListBreakPoints()
+    of "disable":
+      BreakpointSetEnabled(dbgUser, i, -1)
+    of "enable":
+      BreakpointSetEnabled(dbgUser, i, +1)
+    of "maxdisplay":
+      var parsed: int
+      i = scanNumber(dbgUser, parsed, i)
+      if dbgUser[i-1] in {'0'..'9'}:
+        if parsed == 0: maxDisplayRecDepth = -1
+        else: maxDisplayRecDepth = parsed
+      else:
+        InvalidCommand()
+    else:
+      InvalidCommand()
+
+proc endbStep() =
+  # we get into here if an unhandled exception has been raised
+  # XXX: do not allow the user to run the program any further?
+  # XXX: BUG: the frame is lost here!
+  dbgShowExecutionPoint()
+  CommandPrompt()
+
+proc checkForBreakpoint() =
+  var i = dbgBreakpointReached(framePtr.line)
+  if i >= 0:
+    write(stdout, "*** endb| reached ")
+    write(stdout, dbgBP[i].name)
+    write(stdout, " in ")
+    write(stdout, framePtr.filename)
+    write(stdout, "(")
+    write(stdout, framePtr.line)
+    write(stdout, ") ")
+    write(stdout, framePtr.procname)
+    write(stdout, " ***\n")
+    CommandPrompt()
+
+# interface to the user program:
+
+proc dbgRegisterBreakpoint(line: int,
+                           filename, name: cstring) {.compilerproc.} =
+  var x = dbgBPlen
+  inc(dbgBPlen)
+  dbgBP[x].name = $name
+  dbgBP[x].filename = $filename
+  dbgBP[x].low = line
+  dbgBP[x].high = line
+
+proc dbgRegisterGlobal(name: cstring, address: pointer,
+                       typ: PNimType) {.compilerproc.} =
+  var i = dbgGlobalData.f.len
+  if i >= high(dbgGlobalData.slots):
+    debugOut("[Warning] cannot register global ")
+    return
+  dbgGlobalData.slots[i].name = name
+  dbgGlobalData.slots[i].typ = typ
+  dbgGlobalData.slots[i].address = address
+  inc(dbgGlobalData.f.len)
+
+proc endb(line: int) {.compilerproc.} =
+  # This proc is called before every Nimrod code line!
+  # Thus, it must have as few parameters as possible to keep the
+  # code size small!
+  # Check if we are at an enabled breakpoint or "in the mood"
+  framePtr.line = line # this is done here for smaller code size!
+  if dbgLineHook != nil: dbgLineHook()
+  case dbgState
+  of dbStepInto:
+    # we really want the command prompt here:
+    dbgShowExecutionPoint()
+    CommandPrompt()
+  of dbSkipCurrent, dbStepOver: # skip current routine
+    if framePtr == dbgSkipToFrame:
+      dbgShowExecutionPoint()
+      CommandPrompt()
+    else: # breakpoints are wanted though (I guess)
+      checkForBreakpoint()
+  of dbBreakpoints: # debugger is only interested in breakpoints
+    checkForBreakpoint()
+  else: nil
diff --git a/nimlib/system/dyncalls.nim b/nimlib/system/dyncalls.nim
new file mode 100755
index 000000000..0946ee355
--- /dev/null
+++ b/nimlib/system/dyncalls.nim
@@ -0,0 +1,127 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the ability to call native procs from libraries.
+# It is not possible to do this in a platform independant way, unfortunately.
+# However, the interface has been designed to take platform differences into
+# account and been ported to all major platforms.
+
+type
+  TLibHandle = pointer       # private type
+  TProcAddr = pointer        # libary loading and loading of procs:
+
+const
+  NilLibHandle: TLibHandle = nil
+
+proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
+proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
+proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
+
+proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} =
+  raise newException(EInvalidLibrary, "could not load: " & path)
+
+# this code was inspired from Lua's source code:
+# Lua - An Extensible Extension Language
+# Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
+# http://www.lua.org
+# mailto:info@lua.org
+
+when defined(posix):
+  #
+  # =========================================================================
+  # This is an implementation based on the dlfcn interface.
+  # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+  # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+  # as an emulation layer on top of native functions.
+  # =========================================================================
+  #
+
+  # c stuff:
+  var
+    RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
+
+  proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
+  proc dlopen(path: CString, mode: int): TLibHandle {.
+      importc, header: "<dlfcn.h>".}
+  proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
+      importc, header: "<dlfcn.h>".}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    dlclose(lib)
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    result = dlopen(path, RTLD_NOW)
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    result = dlsym(lib, name)
+    if result == nil: nimLoadLibraryError($name)
+
+elif defined(windows) or defined(dos):
+  #
+  # =======================================================================
+  # Native Windows Implementation
+  # =======================================================================
+  #
+  type
+    THINSTANCE {.importc: "HINSTANCE".} = pointer
+
+  proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
+  proc winLoadLibrary(path: cstring): THINSTANCE {.
+      importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
+  proc GetProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
+      importc: "GetProcAddress", header: "<windows.h>", stdcall.}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    FreeLibrary(cast[THINSTANCE](lib))
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    result = cast[TLibHandle](winLoadLibrary(path))
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    result = GetProcAddress(cast[THINSTANCE](lib), name)
+    if result == nil: nimLoadLibraryError($name)
+
+elif defined(mac):
+  #
+  # =======================================================================
+  # Native Mac OS X / Darwin Implementation
+  # =======================================================================
+  #
+  {.error: "no implementation for dyncalls yet".}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
+
+  var
+    dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    var
+      img: NSObjectFileImage
+      ret: NSObjectFileImageReturnCode
+      modul: NSModule
+    # this would be a rare case, but prevents crashing if it happens
+    result = nil
+    if dyld_present != 0:
+      ret = NSCreateObjectFileImageFromFile(path, addr(img))
+      if ret == NSObjectFileImageSuccess:
+        modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
+                                        NSLINKMODULE_OPTION_RETURN_ON_ERROR)
+        NSDestroyObjectFileImage(img)
+        result = TLibHandle(modul)
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    var
+      nss: NSSymbol
+    nss = NSLookupSymbolInModule(NSModule(lib), name)
+    result = TProcAddr(NSAddressOfSymbol(nss))
+    if result == nil: nimLoadLibraryError($name)
+
+else:
+  {.error: "no implementation for dyncalls".}
diff --git a/nimlib/system/ecmasys.nim b/nimlib/system/ecmasys.nim
new file mode 100755
index 000000000..c0d0a5fd6
--- /dev/null
+++ b/nimlib/system/ecmasys.nim
@@ -0,0 +1,531 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Stubs for the GC interface:
+
+proc GC_disable() = nil
+proc GC_enable() = nil
+proc GC_fullCollect() = nil
+proc GC_setStrategy(strategy: TGC_Strategy) = nil
+proc GC_enableMarkAndSweep() = nil
+proc GC_disableMarkAndSweep() = nil
+proc GC_getStatistics(): string = return ""
+
+proc getOccupiedMem(): int = return -1
+proc getFreeMem(): int = return -1
+proc getTotalMem(): int = return -1
+
+proc alert(s: cstring) {.importc, nodecl.}
+
+type
+  PSafePoint = ptr TSafePoint
+  TSafePoint {.compilerproc, final.} = object
+    prev: PSafePoint # points to next safe point
+    exc: ref E_Base
+
+  PCallFrame = ptr TCallFrame
+  TCallFrame {.importc, nodecl, final.} = object
+    prev: PCallFrame
+    procname: CString
+    line: int # current line number
+    filename: CString
+
+var
+  framePtr {.importc, nodecl, volatile.}: PCallFrame
+  excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
+    # list of exception handlers
+    # a global variable for the root of all try blocks
+
+{.push stacktrace: off.}
+proc nimBoolToStr(x: bool): string {.compilerproc.} =
+  if x: result = "true"
+  else: result = "false"
+
+proc nimCharToStr(x: char): string {.compilerproc.} =
+  result = newString(1)
+  result[0] = x
+
+proc getCurrentExceptionMsg(): string =
+  if excHandler != nil: return $excHandler.exc.msg
+  return ""
+
+proc auxWriteStackTrace(f: PCallFrame): string =
+  type
+    TTempFrame = tuple[procname: CString, line: int]
+  var
+    it = f
+    i = 0
+    total = 0
+    tempFrames: array [0..63, TTempFrame]
+  while it != nil and i <= high(tempFrames):
+    tempFrames[i].procname = it.procname
+    tempFrames[i].line = it.line
+    inc(i)
+    inc(total)
+    it = it.prev
+  while it != nil:
+    inc(total)
+    it = it.prev
+  result = ""
+  # if the buffer overflowed print '...':
+  if total != i:
+    add(result, "(")
+    add(result, $(total-i))
+    add(result, " calls omitted) ...\n")
+  for j in countdown(i-1, 0):
+    add(result, tempFrames[j].procname)
+    if tempFrames[j].line > 0:
+      add(result, ", line: ")
+      add(result, $tempFrames[j].line)
+    add(result, "\n")
+
+proc rawWriteStackTrace(): string =
+  if framePtr == nil:
+    result = "No stack traceback available\n"
+  else:
+    result = "Traceback (most recent call last)\n"& auxWriteStackTrace(framePtr)
+    framePtr = nil
+
+proc raiseException(e: ref E_Base, ename: cstring) {.compilerproc, pure.} =
+  e.name = ename
+  if excHandler != nil:
+    excHandler.exc = e
+  else:
+    var buf = rawWriteStackTrace()
+    if e.msg != nil and e.msg[0] != '\0':
+      add(buf, "Error: unhandled exception: ")
+      add(buf, e.msg)
+    else:
+      add(buf, "Error: unhandled exception")
+    add(buf, " [")
+    add(buf, ename)
+    add(buf, "]\n")
+    alert(buf)
+  asm """throw `e`;"""
+
+proc reraiseException() =
+  if excHandler == nil:
+    raise newException(ENoExceptionToReraise, "no exception to reraise")
+  else:
+    asm """throw excHandler.exc;"""
+
+proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
+  raise newException(EOverflow, "over- or underflow")
+
+proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} =
+  raise newException(EDivByZero, "divison by zero")
+
+proc raiseRangeError() {.compilerproc, noreturn.} =
+  raise newException(EOutOfRange, "value out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn.} =
+  raise newException(EInvalidIndex, "index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
+  raise newException(EInvalidField, f & " is not accessible")
+
+
+
+proc SetConstr() {.varargs, pure, compilerproc.} =
+  asm """
+    var result = {};
+    for (var i = 0; i < arguments.length; ++i) {
+      var x = arguments[i];
+      if (typeof(x) == "object") {
+        for (var j = x[0]; j <= x[1]; ++j) {
+          result[j] = true;
+        }
+      } else {
+        result[x] = true;
+      }
+    }
+    return result;
+  """
+
+proc cstrToNimstr(c: cstring): string {.pure, compilerproc.} =
+  asm """
+    var result = [];
+    for (var i = 0; i < `c`.length; ++i) {
+      result[i] = `c`.charCodeAt(i);
+    }
+    result[result.length] = 0; // terminating zero
+    return result;
+  """
+
+proc toEcmaStr(s: string): cstring {.pure, compilerproc.} =
+  asm """
+    var len = `s`.length-1;
+    var result = new Array(len);
+    var fcc = String.fromCharCode;
+    for (var i = 0; i < len; ++i) {
+      result[i] = fcc(`s`[i]);
+    }
+    return result.join("");
+  """
+
+proc mnewString(len: int): string {.pure, compilerproc.} =
+  asm """
+    var result = new Array(`len`+1);
+    result[0] = 0;
+    result[`len`] = 0;
+    return result;
+  """
+
+proc SetCard(a: int): int {.compilerproc, pure.} =
+  # argument type is a fake
+  asm """
+    var result = 0;
+    for (var elem in `a`) { ++result; }
+    return result;
+  """
+
+proc SetEq(a, b: int): bool {.compilerproc, pure.} =
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    for (var elem in `b`) { if (!`a`[elem]) return false; }
+    return true;
+  """
+
+proc SetLe(a, b: int): bool {.compilerproc, pure.} =
+  asm """
+    for (var elem in `a`) { if (!`b`[elem]) return false; }
+    return true;
+  """
+
+proc SetLt(a, b: int): bool {.compilerproc.} =
+  result = SetLe(a, b) and not SetEq(a, b)
+
+proc SetMul(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc SetPlus(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) { result[elem] = true; }
+    for (var elem in `b`) { result[elem] = true; }
+    return result;
+  """
+
+proc SetMinus(a, b: int): int {.compilerproc, pure.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (!`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc cmpStrings(a, b: string): int {.pure, compilerProc.} =
+  asm """
+    if (`a` == `b`) return 0;
+    if (!`a`) return -1;
+    if (!`b`) return 1;
+    for (var i = 0; i < `a`.length-1; ++i) {
+      var result = `a`[i] - `b`[i];
+      if (result != 0) return result;
+    }
+    return 0;
+  """
+
+proc cmp(x, y: string): int = return cmpStrings(x, y)
+
+proc eqStrings(a, b: string): bool {.pure, compilerProc.} =
+  asm """
+    if (`a == `b`) return true;
+    if ((!`a`) || (!`b`)) return false;
+    var alen = `a`.length;
+    if (alen != `b`.length) return false;
+    for (var i = 0; i < alen; ++i)
+      if (`a`[i] != `b`[i]) return false;
+    return true;
+  """
+
+type
+  TDocument {.importc.} = object of TObject
+    write: proc (text: cstring)
+    writeln: proc (text: cstring)
+    createAttribute: proc (identifier: cstring): ref TNode
+    createElement: proc (identifier: cstring): ref TNode
+    createTextNode: proc (identifier: cstring): ref TNode
+    getElementById: proc (id: cstring): ref TNode
+    getElementsByName: proc (name: cstring): seq[ref TNode]
+    getElementsByTagName: proc (name: cstring): seq[ref TNode]
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+  TNode* {.importc.} = object of TObject
+    attributes*: seq[ref TNode]
+    childNodes*: seq[ref TNode]
+    data*: cstring
+    firstChild*: ref TNode
+    lastChild*: ref TNode
+    nextSibling*: ref TNode
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: ref TNode
+    previousSibling*: ref TNode
+    appendChild*: proc (child: ref TNode)
+    appendData*: proc (data: cstring)
+    cloneNode*: proc (copyContent: bool)
+    deleteData*: proc (start, len: int)
+    getAttribute*: proc (attr: cstring): cstring
+    getAttributeNode*: proc (attr: cstring): ref TNode
+    getElementsByTagName*: proc (): seq[ref TNode]
+    hasChildNodes*: proc (): bool
+    insertBefore*: proc (newNode, before: ref TNode)
+    insertData*: proc (position: int, data: cstring)
+    removeAttribute*: proc (attr: cstring)
+    removeAttributeNode*: proc (attr: ref TNode)
+    removeChild*: proc (child: ref TNode)
+    replaceChild*: proc (newNode, oldNode: ref TNode)
+    replaceData*: proc (start, len: int, text: cstring)
+    setAttribute*: proc (name, value: cstring)
+    setAttributeNode*: proc (attr: ref TNode)
+    
+var
+  document {.importc, nodecl.}: ref TDocument
+
+proc ewriteln(x: cstring) = 
+  var node = document.getElementsByTagName("body")[0]
+  if node != nil: 
+    node.appendChild(document.createTextNode(x))
+    node.appendChild(document.createElement("br"))
+  else: 
+    raise newException(EInvalidValue, "<body> element does not exist yet!")
+
+proc echo*(x: int) = ewriteln($x)
+proc echo*(x: float) = ewriteln($x)
+proc echo*(x: bool) = ewriteln(if x: cstring("true") else: cstring("false"))
+proc echo*(x: string) = ewriteln(x)
+proc echo*(x: cstring) = ewriteln(x)
+
+proc echo[Ty](x: Ty) =
+  echo(x)
+
+proc echo[Ty](x: openArray[Ty]) =
+  for a in items(x): echo(a)
+
+# Arithmetic:
+proc addInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc subInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc mulInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 2147483647 || result < -2147483648) raiseOverflow();
+    return result;
+  """
+
+proc divInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 2147483647) raiseOverflow();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 2147483647) raiseOverflow();
+    return Math.floor(`a` % `b`);
+  """
+
+
+
+proc addInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc subInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc mulInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) raiseOverflow();
+    return result;
+  """
+
+proc divInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt64(a, b: int): int {.pure, compilerproc.} =
+  asm """
+    if (`b` == 0) raiseDivByZero();
+    if (`b` == -1 && `a` == 9223372036854775807) raiseOverflow();
+    return Math.floor(`a` % `b`);
+  """
+
+proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
+proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
+
+proc internalAssert(file: cstring, line: int) {.pure, compilerproc.} =
+  var
+    e: ref EAssertionFailed
+  new(e)
+  asm """`e`.message = "[Assertion failure] file: "+`file`+", line: "+`line`"""
+  raise e
+
+include hti
+
+proc isFatPointer(ti: PNimType): bool =
+  # This has to be consistent with the code generator!
+  return ti.base.kind notin {tyRecord, tyRecordConstr, tyObject,
+    tyArray, tyArrayConstr, tyPureObject, tyTuple,
+    tyEmptySet, tyOpenArray, tySet, tyVar, tyRef, tyPtr}
+
+proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
+
+proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
+  of nkList:
+    for i in 0..n.len-1:
+      NimCopyAux(dest, src, n.sons[i])
+  of nkCase:
+    asm """
+      `dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);
+      for (var i = 0; i < `n`.sons.length; ++i) {
+        NimCopyAux(`dest`, `src`, `n`.sons[i][1]);
+      }
+    """
+
+proc NimCopy(x: pointer, ti: PNimType): pointer =
+  case ti.kind
+  of tyPtr, tyRef, tyVar, tyNil:
+    if not isFatPointer(ti):
+      result = x
+    else:
+      asm """
+        `result` = [null, 0];
+        `result`[0] = `x`[0];
+        `result`[1] = `x`[1];
+      """
+  of tyEmptySet, tySet:
+    asm """
+      `result` = {};
+      for (var key in `x`) { `result`[key] = `x`[key]; }
+    """
+  of tyPureObject, tyTuple, tyObject:
+    if ti.base != nil: result = NimCopy(x, ti.base)
+    elif ti.kind == tyObject:
+      asm "`result` = {m_type: `ti`};"
+    else:
+      asm "`result` = {};"
+    NimCopyAux(result, x, ti.node)
+  of tySequence, tyArrayConstr, tyOpenArray, tyArray:
+    asm """
+      `result` = new Array(`x`.length);
+      for (var i = 0; i < `x`.length; ++i) {
+        `result`[i] = NimCopy(`x`[i], `ti`.base);
+      }
+    """
+  of tyString:
+    asm "`result` = `x`.slice(0);"
+  else:
+    result = x
+
+
+proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
+                 pure, compilerproc.} =
+  # types are fake
+  asm """
+    var result = new Array(`len`);
+    for (var i = 0; i < `len`; ++i) result[i] = NimCopy(`value`, `typ`);
+    return result;
+  """
+
+proc chckIndx(i, a, b: int): int {.compilerproc.} =
+  if i >= a and i <= b: return i
+  else: raiseIndexError()
+
+proc chckRange(i, a, b: int): int {.compilerproc.} =
+  if i >= a and i <= b: return i
+  else: raiseRangeError()
+
+proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return # optimized fast path
+  while x != subclass:
+    if x == nil:
+      raise newException(EInvalidObjectConversion, "invalid object conversion")
+    x = x.base
+
+{.pop.}
+
+#proc AddU($1, $2)
+#SubU($1, $2)
+#MulU($1, $2)
+#DivU($1, $2)
+#ModU($1, $2)
+#AddU64($1, $2)
+#SubU64($1, $2)
+#MulU64($1, $2)
+#DivU64($1, $2)
+#ModU64($1, $2)
+#LeU($1, $2)
+#LtU($1, $2)
+#LeU64($1, $2)
+#LtU64($1, $2)
+#Ze($1)
+#Ze64($1)
+#ToU8($1)
+#ToU16($1)
+#ToU32($1)
+
+#NegInt($1)
+#NegInt64($1)
+#AbsInt($1)
+#AbsInt64($1)
diff --git a/nimlib/system/excpt.nim b/nimlib/system/excpt.nim
new file mode 100755
index 000000000..293491fe9
--- /dev/null
+++ b/nimlib/system/excpt.nim
@@ -0,0 +1,285 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Exception handling code. This is difficult because it has
+# to work if there is no more memory. Thus we have to use
+# a static string. Do not use ``sprintf``, etc. as they are
+# unsafe!
+
+when not defined(windows) or not defined(guiapp):
+  proc writeToStdErr(msg: CString) = write(stdout, msg)
+
+else:
+  proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
+    header: "<windows.h>", nodecl.}
+
+  proc writeToStdErr(msg: CString) =
+    discard MessageBoxA(0, msg, nil, 0)
+
+proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.}
+proc reraiseException() {.compilerproc.}
+
+proc registerSignalHandler() {.compilerproc.}
+
+proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
+proc chckRange(i, a, b: int): int {.inline, compilerproc.}
+proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
+proc chckNil(p: pointer) {.inline, compilerproc.}
+
+type
+  PSafePoint = ptr TSafePoint
+  TSafePoint {.compilerproc, final.} = object
+    prev: PSafePoint # points to next safe point ON THE STACK
+    exc: ref E_Base
+    status: int
+    context: C_JmpBuf
+
+var
+  excHandler {.compilerproc.}: PSafePoint = nil
+    # list of exception handlers
+    # a global variable for the root of all try blocks
+
+proc reraiseException() =
+  if excHandler == nil:
+    raise newException(ENoExceptionToReraise, "no exception to reraise")
+  else:
+    c_longjmp(excHandler.context, 1)
+
+type
+  PFrame = ptr TFrame
+  TFrame {.importc, nodecl, final.} = object
+    prev: PFrame
+    procname: CString
+    line: int # current line number
+    filename: CString
+    len: int  # length of slots (when not debugging always zero)
+
+var
+  buf: string       # cannot be allocated on the stack!
+  assertBuf: string # we need a different buffer for
+                    # assert, as it raises an exception and
+                    # exception handler needs the buffer too
+
+  framePtr {.exportc.}: PFrame
+
+  tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
+  
+  stackTraceNewLine* = "\n" ## undocumented feature
+
+proc auxWriteStackTrace(f: PFrame, s: var string) =
+  const 
+    firstCalls = 32
+  var
+    it = f
+    i = 0
+    total = 0
+  while it != nil and i <= high(tempFrames)-(firstCalls-1):
+    # the (-1) is for a nil entry that marks where the '...' should occur
+    tempFrames[i] = it
+    inc(i)
+    inc(total)
+    it = it.prev
+  var b = it
+  while it != nil:
+    inc(total)
+    it = it.prev
+  for j in 1..total-i-(firstCalls-1): 
+    if b != nil: b = b.prev
+  if total != i:
+    tempFrames[i] = nil
+    inc(i)
+  while b != nil and i <= high(tempFrames):
+    tempFrames[i] = b
+    inc(i)
+    b = b.prev
+  for j in countdown(i-1, 0):
+    if tempFrames[j] == nil: 
+      add(s, "(")
+      add(s, $(total-i-1))
+      add(s, " calls omitted) ...")
+    else:
+      add(s, $tempFrames[j].procname)
+      if tempFrames[j].line > 0:
+        add(s, ", line: ")
+        add(s, $tempFrames[j].line)
+    add(s, stackTraceNewLine)
+
+proc rawWriteStackTrace(s: var string) =
+  if framePtr == nil:
+    add(s, "No stack traceback available")
+    add(s, stackTraceNewLine)
+  else:
+    add(s, "Traceback (most recent call last)")
+    add(s, stackTraceNewLine)
+    auxWriteStackTrace(framePtr, s)
+
+proc quitOrDebug() {.inline.} =
+  when not defined(endb):
+    quit(1)
+  else:
+    endbStep() # call the debugger
+
+proc raiseException(e: ref E_Base, ename: CString) =
+  GC_disable() # a bad thing is an error in the GC while raising an exception
+  e.name = ename
+  if excHandler != nil:
+    excHandler.exc = e
+    c_longjmp(excHandler.context, 1)
+  else:
+    if not isNil(buf):
+      setLen(buf, 0)
+      rawWriteStackTrace(buf)
+      if e.msg != nil and e.msg[0] != '\0':
+        add(buf, "Error: unhandled exception: ")
+        add(buf, $e.msg)
+      else:
+        add(buf, "Error: unhandled exception")
+      add(buf, " [")
+      add(buf, $ename)
+      add(buf, "]\n")
+      writeToStdErr(buf)
+    else:
+      writeToStdErr(ename)
+    quitOrDebug()
+  GC_enable()
+
+var
+  gAssertionFailed: ref EAssertionFailed
+
+proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
+  if not cond:
+    #c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
+    #quit(1)
+    GC_disable() # BUGFIX: `$` allocates a new string object!
+    if not isNil(assertBuf):
+      # BUGFIX: when debugging the GC, assertBuf may be nil
+      setLen(assertBuf, 0)
+      add(assertBuf, "[Assertion failure] file: ")
+      add(assertBuf, file)
+      add(assertBuf, " line: ")
+      add(assertBuf, $line)
+      add(assertBuf, "\n")
+      gAssertionFailed.msg = assertBuf
+    GC_enable()
+    if gAssertionFailed != nil:
+      raise gAssertionFailed
+    else:
+      c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
+      quit(1)
+
+proc WriteStackTrace() =
+  var s = ""
+  rawWriteStackTrace(s)
+  writeToStdErr(s)
+
+#proc stackTraceWrapper {.noconv.} =
+#  writeStackTrace()
+
+#addQuitProc(stackTraceWrapper)
+
+var
+  dbgAborting: bool # whether the debugger wants to abort
+
+proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
+  # print stack trace and quit
+  var s = sig
+  GC_disable()
+  setLen(buf, 0)
+  rawWriteStackTrace(buf)
+
+  if s == SIGINT: add(buf, "SIGINT: Interrupted by Ctrl-C.\n")
+  elif s == SIGSEGV: add(buf, "SIGSEGV: Illegal storage access.\n")
+  elif s == SIGABRT:
+    if dbgAborting: return # the debugger wants to abort
+    add(buf, "SIGABRT: Abnormal termination.\n")
+  elif s == SIGFPE: add(buf, "SIGFPE: Arithmetic error.\n")
+  elif s == SIGILL: add(buf, "SIGILL: Illegal operation.\n")
+  elif s == SIGBUS: add(buf, "SIGBUS: Illegal storage access.\n")
+  else: add(buf, "unknown signal\n")
+  writeToStdErr(buf)
+  dbgAborting = True # play safe here...
+  GC_enable()
+  quit(1) # always quit when SIGABRT
+
+proc registerSignalHandler() =
+  c_signal(SIGINT, signalHandler)
+  c_signal(SIGSEGV, signalHandler)
+  c_signal(SIGABRT, signalHandler)
+  c_signal(SIGFPE, signalHandler)
+  c_signal(SIGILL, signalHandler)
+  c_signal(SIGBUS, signalHandler)
+
+when not defined(noSignalHandler):
+  registerSignalHandler() # call it in initialization section
+# for easier debugging of the GC, this memory is only allocated after the
+# signal handlers have been registered
+new(gAssertionFailed)
+buf = newString(2048)
+assertBuf = newString(2048)
+setLen(buf, 0)
+setLen(assertBuf, 0)
+
+proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
+  raise newException(EOutOfRange, "value " & $val & " out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+  raise newException(EInvalidIndex, "index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+  raise newException(EInvalidField, f & " is not accessible")
+
+proc chckIndx(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseIndexError()
+
+proc chckRange(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRangeF(x, a, b: float): float =
+  if x >= a and x <= b:
+    return x
+  else:
+    raise newException(EOutOfRange, "value " & $x & " out of range")
+
+proc chckNil(p: pointer) =
+  if p == nil: c_raise(SIGSEGV)
+
+proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return # optimized fast path
+  while x != subclass:
+    if x == nil:
+      raise newException(EInvalidObjectConversion, "invalid object conversion")
+    x = x.base
+
+proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
+  if a != b:
+    raise newException(EInvalidObjectAssignment, "invalid object assignment")
+
+proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return true # optimized fast path
+  while x != subclass:
+    if x == nil: return false
+    x = x.base
+  return true
diff --git a/nimlib/system/gc.nim b/nimlib/system/gc.nim
new file mode 100755
index 000000000..da8f75768
--- /dev/null
+++ b/nimlib/system/gc.nim
@@ -0,0 +1,647 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+#            Garbage Collector
+#
+# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+# Special care has been taken to avoid recursion as far as possible to avoid
+# stack overflows when traversing deep datastructures. This is comparable to
+# an incremental and generational GC. It should be well-suited for soft real
+# time applications (like games).
+#
+# Future Improvements:
+# * Support for multi-threading. However, locks for the reference counting
+#   might turn out to be too slow.
+
+const
+  CycleIncrease = 2 # is a multiplicative increase
+  InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
+  ZctThreshold = 256  # we collect garbage if the ZCT's size
+                      # reaches this threshold
+                      # this seems to be a good value
+
+const
+  rcIncrement = 0b1000 # so that lowest 3 bits are not touched
+  # NOTE: Most colors are currently unused
+  rcBlack = 0b000  # cell is colored black; in use or free
+  rcGray = 0b001   # possible member of a cycle
+  rcWhite = 0b010  # member of a garbage cycle
+  rcPurple = 0b011 # possible root of a cycle
+  rcZct = 0b100    # in ZCT
+  rcRed = 0b101    # Candidate cycle undergoing sigma-computation
+  rcOrange = 0b110 # Candidate cycle awaiting epoch boundary
+  rcShift = 3      # shift by rcShift to get the reference counter
+  colorMask = 0b111
+type
+  TWalkOp = enum
+    waZctDecRef, waPush, waCycleDecRef
+
+  TFinalizer {.compilerproc.} = proc (self: pointer)
+    # A ref type can have a finalizer that is called before the object's
+    # storage is freed.
+
+  TGcStat {.final, pure.} = object
+    stackScans: int          # number of performed stack scans (for statistics)
+    cycleCollections: int    # number of performed full collections
+    maxThreshold: int        # max threshold that has been set
+    maxStackSize: int        # max stack size
+    maxStackCells: int       # max stack cells in ``decStack``
+    cycleTableSize: int      # max entries in cycle table  
+  
+  TGcHeap {.final, pure.} = object # this contains the zero count and
+                                   # non-zero count table
+    zct: TCellSeq            # the zero count table
+    decStack: TCellSeq       # cells in the stack that are to decref again
+    cycleRoots: TCellSet
+    tempStack: TCellSeq      # temporary stack for recursion elimination
+    stat: TGcStat
+
+var
+  stackBottom: pointer
+  gch: TGcHeap
+  cycleThreshold: int = InitialCycleThreshold
+  recGcLock: int = 0
+    # we use a lock to prevend the garbage collector to be triggered in a
+    # finalizer; the collector should not call itself this way! Thus every
+    # object allocated by a finalizer will not trigger a garbage collection.
+    # This is wasteful but safe. This is a lock against recursive garbage
+    # collection, not a lock for threads!
+
+proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.}
+  # unsureAsgnRef updates the reference counters only if dest is not on the
+  # stack. It is used by the code generator if it cannot decide wether a
+  # reference is in the stack or not (this can happen for var parameters).
+#proc growObj(old: pointer, newsize: int): pointer {.compilerproc.}
+proc newObj(typ: PNimType, size: int): pointer {.compilerproc.}
+proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.}
+
+proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
+  if (c.refcount and rcZct) == 0:
+    c.refcount = c.refcount and not colorMask or rcZct
+    add(s, c)
+
+proc cellToUsr(cell: PCell): pointer {.inline.} =
+  # convert object (=pointer to refcount) to pointer to userdata
+  result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
+
+proc usrToCell(usr: pointer): PCell {.inline.} =
+  # convert pointer to userdata to object (=pointer to refcount)
+  result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
+
+proc canbeCycleRoot(c: PCell): bool {.inline.} =
+  result = ntfAcyclic notin c.typ.flags
+
+proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
+  # used for code generation concerning debugging
+  result = usrToCell(c).typ
+
+proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
+  result = int(usrToCell(p).refcount) shr rcShift
+
+proc GC_disable() = inc(recGcLock)
+proc GC_enable() =
+  if recGcLock > 0: dec(recGcLock)
+
+proc GC_setStrategy(strategy: TGC_Strategy) =
+  case strategy
+  of gcThroughput: nil
+  of gcResponsiveness: nil
+  of gcOptimizeSpace: nil
+  of gcOptimizeTime: nil
+
+proc GC_enableMarkAndSweep() =
+  cycleThreshold = InitialCycleThreshold
+
+proc GC_disableMarkAndSweep() =
+  cycleThreshold = high(cycleThreshold)-1
+  # set to the max value to suppress the cycle detector
+
+# this that has to equals zero, otherwise we have to round up UnitsPerPage:
+when BitsPerPage mod (sizeof(int)*8) != 0:
+  {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
+
+when debugGC:
+  proc writeCell(msg: CString, c: PCell) =
+    var kind = -1
+    if c.typ != nil: kind = ord(c.typ.kind)
+    when debugGC:
+      c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld from %s(%ld)\n",
+                msg, c, kind, c.refcount shr rcShift, c.filename, c.line)
+    else:
+      c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
+                msg, c, kind, c.refcount shr rcShift)
+
+when traceGC:
+  # traceGC is a special switch to enable extensive debugging
+  type
+    TCellState = enum
+      csAllocated, csZctFreed, csCycFreed
+  var
+    states: array[TCellState, TCellSet]
+
+  proc traceCell(c: PCell, state: TCellState) =
+    case state
+    of csAllocated:
+      if c in states[csAllocated]:
+        writeCell("attempt to alloc an already allocated cell", c)
+        assert(false)
+      excl(states[csCycFreed], c)
+      excl(states[csZctFreed], c)
+    of csZctFreed:
+      if c in states[csZctFreed]:
+        writeCell("attempt to free zct cell twice", c)
+        assert(false)
+      if c in states[csCycFreed]:
+        writeCell("attempt to free with zct, but already freed with cyc", c)
+        assert(false)
+      if c notin states[csAllocated]:
+        writeCell("attempt to free not an allocated cell", c)
+        assert(false)
+      excl(states[csAllocated], c)
+    of csCycFreed:
+      if c notin states[csAllocated]:
+        writeCell("attempt to free a not allocated cell", c)
+        assert(false)
+      if c in states[csCycFreed]:
+        writeCell("attempt to free cyc cell twice", c)
+        assert(false)
+      if c in states[csZctFreed]:
+        writeCell("attempt to free with cyc, but already freed with zct", c)
+        assert(false)
+      excl(states[csAllocated], c)
+    incl(states[state], c)
+
+  proc writeLeakage() =
+    var z = 0
+    var y = 0
+    var e = 0
+    for c in elements(states[csAllocated]):
+      inc(e)
+      if c in states[csZctFreed]: inc(z)
+      elif c in states[csCycFreed]: inc(z)
+      else: writeCell("leak", c)
+    cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
+             e, z, y)
+
+template gcTrace(cell, state: expr): stmt =
+  when traceGC: traceCell(cell, state)
+
+# -----------------------------------------------------------------------------
+
+# forward declarations:
+proc collectCT(gch: var TGcHeap)
+proc IsOnStack(p: pointer): bool {.noinline.}
+proc forAllChildren(cell: PCell, op: TWalkOp)
+proc doOperation(p: pointer, op: TWalkOp)
+proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
+# we need the prototype here for debugging purposes
+
+proc prepareDealloc(cell: PCell) =
+  if cell.typ.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(recGcLock)
+    (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
+    dec(recGcLock)
+
+proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
+  stackBottom = theStackBottom
+
+proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
+  if canbeCycleRoot(c): incl(gch.cycleRoots, c)
+
+proc decRef(c: PCell) {.inline.} =
+  when stressGC:
+    if c.refcount <% rcIncrement:
+      writeCell("broken cell", c)
+  assert(c.refcount >=% rcIncrement)
+  c.refcount = c.refcount -% rcIncrement
+  if c.refcount <% rcIncrement:
+    addZCT(gch.zct, c)
+  elif canBeCycleRoot(c):
+    incl(gch.cycleRoots, c) 
+
+proc incRef(c: PCell) {.inline.} = 
+  c.refcount = c.refcount +% rcIncrement
+  if canBeCycleRoot(c):
+    incl(gch.cycleRoots, c)
+
+proc nimGCref(p: pointer) {.compilerproc, inline.} = incRef(usrToCell(p))
+proc nimGCunref(p: pointer) {.compilerproc, inline.} = decRef(usrToCell(p))
+
+proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+  # the code generator calls this proc!
+  assert(not isOnStack(dest))
+  # BUGFIX: first incRef then decRef!
+  if src != nil: incRef(usrToCell(src))
+  if dest^ != nil: decRef(usrToCell(dest^))
+  dest^ = src
+
+proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+  # the code generator calls this proc if it is known at compile time that no 
+  # cycle is possible.
+  if src != nil: 
+    var c = usrToCell(src)
+    c.refcount = c.refcount +% rcIncrement
+  if dest^ != nil: 
+    var c = usrToCell(dest^)
+    c.refcount = c.refcount -% rcIncrement
+    if c.refcount <% rcIncrement:
+      addZCT(gch.zct, c)
+  dest^ = src
+
+proc unsureAsgnRef(dest: ppointer, src: pointer) =
+  if not IsOnStack(dest):
+    if src != nil: incRef(usrToCell(src))
+    if dest^ != nil: decRef(usrToCell(dest^))
+  dest^ = src
+
+proc initGC() =
+  when traceGC:
+    for i in low(TCellState)..high(TCellState): Init(states[i])
+  gch.stat.stackScans = 0
+  gch.stat.cycleCollections = 0
+  gch.stat.maxThreshold = 0
+  gch.stat.maxStackSize = 0
+  gch.stat.maxStackCells = 0
+  gch.stat.cycleTableSize = 0
+  # init the rt
+  init(gch.zct)
+  init(gch.tempStack)
+  Init(gch.cycleRoots)
+  Init(gch.decStack)
+  new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
+
+proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
+  var d = cast[TAddress](dest)
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
+  of nkList:
+    for i in 0..n.len-1: forAllSlotsAux(dest, n.sons[i], op)
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: forAllSlotsAux(dest, m, op)
+
+proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
+  var d = cast[TAddress](dest)
+  if dest == nil: return # nothing to do
+  if ntfNoRefs notin mt.flags:
+    case mt.Kind
+    of tyArray, tyArrayConstr, tyOpenArray:
+      for i in 0..(mt.size div mt.base.size)-1:
+        forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
+    of tyRef, tyString, tySequence: # leaf:
+      doOperation(cast[ppointer](d)^, op)
+    of tyObject, tyTuple, tyPureObject:
+      forAllSlotsAux(dest, mt.node, op)
+    else: nil
+
+proc forAllChildren(cell: PCell, op: TWalkOp) =
+  assert(cell != nil)
+  assert(cell.typ != nil)
+  case cell.typ.Kind
+  of tyRef: # common case
+    forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
+  of tySequence:
+    var d = cast[TAddress](cellToUsr(cell))
+    var s = cast[PGenericSeq](d)
+    if s != nil:
+      for i in 0..s.len-1:
+        forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
+          GenericSeqSize), cell.typ.base, op)
+  of tyString: nil
+  else: assert(false)
+
+proc checkCollection {.inline.} =
+  # checks if a collection should be done
+  if recGcLock == 0:
+    collectCT(gch)
+
+proc newObj(typ: PNimType, size: int): pointer =
+  # generates a new object and sets its reference counter to 0
+  assert(typ.kind in {tyRef, tyString, tySequence})
+  checkCollection()
+  var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
+  zeroMem(res, size+sizeof(TCell))
+  assert((cast[TAddress](res) and (MemAlign-1)) == 0)
+  # now it is buffered in the ZCT
+  res.typ = typ
+  when debugGC:
+    if framePtr != nil and framePtr.prev != nil:
+      res.filename = framePtr.prev.filename
+      res.line = framePtr.prev.line
+  res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT  
+  assert(isAllocatedPtr(allocator, res))
+  # its refcount is zero, so add it to the ZCT:
+  block addToZCT: 
+    # we check the last 8 entries (cache line) for a slot
+    # that could be reused
+    var L = gch.zct.len
+    var d = gch.zct.d
+    for i in countdown(L-1, max(0, L-8)):
+      var c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.refcount = c.refcount and not colorMask
+        d[i] = res
+        break addToZCT
+    add(gch.zct, res)
+  when logGC: writeCell("new cell", res)
+  gcTrace(res, csAllocated)
+  result = cellToUsr(res)
+
+proc newSeq(typ: PNimType, len: int): pointer =
+  result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).space = len
+
+proc growObj(old: pointer, newsize: int): pointer =
+  checkCollection()
+  var ol = usrToCell(old)
+  assert(ol.typ != nil)
+  assert(ol.typ.kind in {tyString, tySequence})
+  var res = cast[PCell](rawAlloc(allocator, newsize + sizeof(TCell)))
+  var elemSize = 1
+  if ol.typ.kind != tyString:
+    elemSize = ol.typ.base.size
+  
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  copyMem(res, ol, oldsize + sizeof(TCell))
+  zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
+          newsize-oldsize)
+  assert((cast[TAddress](res) and (MemAlign-1)) == 0)
+  assert(res.refcount shr rcShift <=% 1)
+  #if res.refcount <% rcIncrement:
+  #  add(gch.zct, res)
+  #else: # XXX: what to do here?
+  #  decRef(ol)
+  if (ol.refcount and colorMask) == rcZct:
+    var j = gch.zct.len-1
+    var d = gch.zct.d
+    while j >= 0: 
+      if d[j] == ol:
+        d[j] = res
+        break
+      dec(j)
+  if canBeCycleRoot(ol): excl(gch.cycleRoots, ol)
+  when logGC:
+    writeCell("growObj old cell", ol)
+    writeCell("growObj new cell", res)
+  gcTrace(ol, csZctFreed)
+  gcTrace(res, csAllocated)
+  when reallyDealloc: rawDealloc(allocator, ol)
+  else:
+    assert(ol.typ != nil)
+    zeroMem(ol, sizeof(TCell))
+  result = cellToUsr(res)
+
+# ---------------- cycle collector -------------------------------------------
+
+proc doOperation(p: pointer, op: TWalkOp) =
+  if p == nil: return
+  var c: PCell = usrToCell(p)
+  assert(c != nil)
+  case op # faster than function pointers because of easy prediction
+  of waZctDecRef:
+    assert(c.refcount >=% rcIncrement)
+    c.refcount = c.refcount -% rcIncrement
+    when logGC: writeCell("decref (from doOperation)", c)
+    if c.refcount <% rcIncrement: addZCT(gch.zct, c)
+  of waPush:
+    add(gch.tempStack, c)
+  of waCycleDecRef:
+    assert(c.refcount >=% rcIncrement)
+    c.refcount = c.refcount -% rcIncrement
+
+# we now use a much simpler and non-recursive algorithm for cycle removal
+proc collectCycles(gch: var TGcHeap) =
+  var tabSize = 0
+  for c in elements(gch.cycleRoots):
+    inc(tabSize)
+    forallChildren(c, waCycleDecRef)
+  gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
+
+  # restore reference counts (a depth-first traversal is needed):
+  var marker: TCellSet
+  Init(marker)
+  for c in elements(gch.cycleRoots):
+    if c.refcount >=% rcIncrement:
+      if not containsOrIncl(marker, c):
+        gch.tempStack.len = 0
+        forAllChildren(c, waPush)
+        while gch.tempStack.len > 0:
+          dec(gch.tempStack.len)
+          var d = gch.tempStack.d[gch.tempStack.len]
+          d.refcount = d.refcount +% rcIncrement
+          if d in gch.cycleRoots and not containsOrIncl(marker, d):
+            forAllChildren(d, waPush)
+  # remove cycles:
+  for c in elements(gch.cycleRoots):
+    if c.refcount <% rcIncrement:
+      gch.tempStack.len = 0
+      forAllChildren(c, waPush)
+      while gch.tempStack.len > 0:
+        dec(gch.tempStack.len)
+        var d = gch.tempStack.d[gch.tempStack.len]
+        if d.refcount <% rcIncrement:
+          if d notin gch.cycleRoots: # d is leaf of c and not part of cycle
+            addZCT(gch.zct, d)
+            when logGC: writeCell("add to ZCT (from cycle collector)", d)
+      prepareDealloc(c)
+      gcTrace(c, csCycFreed)
+      when logGC: writeCell("cycle collector dealloc cell", c)
+      when reallyDealloc: rawDealloc(allocator, c)
+      else:
+        assert(c.typ != nil)
+        zeroMem(c, sizeof(TCell))
+  Deinit(gch.cycleRoots)
+  Init(gch.cycleRoots)
+
+proc gcMark(p: pointer) {.inline.} =
+  # the addresses are not as cells on the stack, so turn them to cells:
+  var cell = usrToCell(p)
+  var c = cast[TAddress](cell)
+  if c >% PageSize and (c and (MemAlign-1)) == 0:
+    # fast check: does it look like a cell?
+    if isAllocatedPtr(allocator, cell): 
+      # mark the cell:
+      cell.refcount = cell.refcount +% rcIncrement
+      add(gch.decStack, cell)
+
+# ----------------- stack management --------------------------------------
+#  inspired from Smart Eiffel
+
+proc stackSize(): int {.noinline.} =
+  var stackTop: array[0..1, pointer]
+  result = abs(cast[int](addr(stackTop[0])) - cast[int](stackBottom))
+
+when defined(sparc): # For SPARC architecture.
+  proc isOnStack(p: pointer): bool =
+    var stackTop: array [0..1, pointer]
+    var b = cast[TAddress](stackBottom)
+    var a = cast[TAddress](addr(stackTop[0]))
+    var x = cast[TAddress](p)
+    result = x >=% a and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    when defined(sparcv9):
+      asm  """"flushw \n" """
+    else:
+      asm  """"ta      0x3   ! ST_FLUSH_WINDOWS\n" """
+
+    var
+      max = stackBottom
+      sp: PPointer
+      stackTop: array[0..1, pointer]
+    sp = addr(stackTop[0])
+    # Addresses decrease as the stack grows.
+    while sp <= max:
+      gcMark(sp^)
+      sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
+
+elif defined(ELATE):
+  {.error: "stack marking code is to be written for this architecture".}
+
+elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
+     defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses increase as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop: array [0..1, pointer]
+    var a = cast[TAddress](stackBottom)
+    var b = cast[TAddress](addr(stackTop[0]))
+    var x = cast[TAddress](p)
+    result = x >=% a and x <=% b
+
+  var
+    jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
+      # a little hack to get the size of a TJmpBuf in the generated C code
+      # in a platform independant way
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[TAddress](stackBottom)
+      var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      # sp will traverse the JMP_BUF as well (jmp_buf size is added,
+      # otherwise sp would be below the registers structure).
+      while sp >=% max:
+        gcMark(cast[ppointer](sp)^)
+        sp = sp -% sizeof(pointer)
+
+else:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses decrease as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop: array [0..1, pointer]
+    var b = cast[TAddress](stackBottom)
+    var a = cast[TAddress](addr(stackTop[0]))
+    var x = cast[TAddress](p)
+    result = x >=% a and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    # We use a jmp_buf buffer that is in the C stack.
+    # Used to traverse the stack and registers assuming
+    # that 'setjmp' will save registers in the C stack.
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[TAddress](stackBottom)
+      var sp = cast[TAddress](addr(registers))
+      while sp <=% max:
+        gcMark(cast[ppointer](sp)^)
+        sp = sp +% sizeof(pointer)
+
+# ----------------------------------------------------------------------------
+# end of non-portable code
+# ----------------------------------------------------------------------------
+
+proc CollectZCT(gch: var TGcHeap) =
+  # Note: Freeing may add child objects to the ZCT! So essentially we do 
+  # deep freeing, which is bad for incremental operation. In order to 
+  # avoid a deep stack, we move objects to keep the ZCT small.
+  # This is performance critical!
+  var L = addr(gch.zct.len)
+  while L^ > 0:
+    var c = gch.zct.d[0]
+    # remove from ZCT:
+    assert((c.refcount and colorMask) == rcZct)
+    c.refcount = c.refcount and not colorMask
+    gch.zct.d[0] = gch.zct.d[L^ - 1]
+    dec(L^)
+    if c.refcount <% rcIncrement: 
+      # It may have a RC > 0, if it is in the hardware stack or
+      # it has not been removed yet from the ZCT. This is because
+      # ``incref`` does not bother to remove the cell from the ZCT 
+      # as this might be too slow.
+      # In any case, it should be removed from the ZCT. But not
+      # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
+      if canBeCycleRoot(c): excl(gch.cycleRoots, c)
+      when logGC: writeCell("zct dealloc cell", c)
+      gcTrace(c, csZctFreed)
+      # We are about to free the object, call the finalizer BEFORE its
+      # children are deleted as well, because otherwise the finalizer may
+      # access invalid memory. This is done by prepareDealloc():
+      prepareDealloc(c)
+      forAllChildren(c, waZctDecRef)
+      when reallyDealloc: rawDealloc(allocator, c)
+      else:
+        assert(c.typ != nil)
+        zeroMem(c, sizeof(TCell))
+
+proc unmarkStackAndRegisters(gch: var TGcHeap) = 
+  var d = gch.decStack.d
+  for i in 0..gch.decStack.len-1:
+    assert isAllocatedPtr(allocator, d[i])
+    decRef(d[i]) # OPT: cannot create a cycle!
+  gch.decStack.len = 0
+
+proc collectCT(gch: var TGcHeap) =
+  if gch.zct.len >= ZctThreshold or (cycleGC and
+      getOccupiedMem() >= cycleThreshold) or stressGC:
+    gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
+    assert(gch.decStack.len == 0)
+    markStackAndRegisters(gch)
+    gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+    inc(gch.stat.stackScans)
+    collectZCT(gch)
+    when cycleGC:
+      if getOccupiedMem() >= cycleThreshold or stressGC:
+        collectCycles(gch)
+        collectZCT(gch)
+        inc(gch.stat.cycleCollections)
+        cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
+                             cycleIncrease)
+        gch.stat.maxThreshold = max(gch.stat.maxThreshold, cycleThreshold)
+    unmarkStackAndRegisters(gch)
+
+proc GC_fullCollect() =
+  var oldThreshold = cycleThreshold
+  cycleThreshold = 0 # forces cycle collection
+  collectCT(gch)
+  cycleThreshold = oldThreshold
+
+proc GC_getStatistics(): string =
+  GC_disable()
+  result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
+           "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
+           "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
+           "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
+           "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
+           "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
+           "[GC] zct capacity: " & $gch.zct.cap & "\n" &
+           "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
+           "[GC] max stack size: " & $gch.stat.maxStackSize
+  when traceGC: writeLeakage()
+  GC_enable()
diff --git a/nimlib/system/hti.nim b/nimlib/system/hti.nim
new file mode 100755
index 000000000..3343000ae
--- /dev/null
+++ b/nimlib/system/hti.nim
@@ -0,0 +1,58 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type # This should be he same as ast.TTypeKind
+     # many enum fields are not used at runtime
+  TNimKind = enum
+    tyNone, tyBool, tyChar,
+    tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
+    tyGenericInvokation, # ``T[a, b]`` for types to invoke
+    tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
+    tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
+    tyGenericParam,      # ``a`` in the example
+    tyDistinct,          # distinct type
+    tyEnum,
+    tyOrdinal,
+    tyArray,
+    tyObject,
+    tyTuple,
+    tySet,
+    tyRange,
+    tyPtr, tyRef,
+    tyVar,
+    tySequence,
+    tyProc,
+    tyPointer, tyOpenArray,
+    tyString, tyCString, tyForward,
+    tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
+    tyFloat, tyFloat32, tyFloat64, tyFloat128,
+    tyPureObject # signals that object has no `n_type` field
+
+  TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
+  TNimNode {.compilerproc, final.} = object
+    kind: TNimNodeKind
+    offset: int
+    typ: ptr TNimType
+    name: Cstring
+    len: int
+    sons: ptr array [0..0x7fff, ptr TNimNode]
+
+  TNimTypeFlag = enum 
+    ntfNoRefs = 0,     # type contains no tyRef, tySequence, tyString
+    ntfAcyclic = 1     # type cannot form a cycle
+  TNimType {.compilerproc, final.} = object
+    size: int
+    kind: TNimKind
+    flags: set[TNimTypeFlag]
+    base: ptr TNimType
+    node: ptr TNimNode # valid for tyRecord, tyObject, tyTuple, tyEnum
+    finalizer: pointer # the finalizer for the type
+  PNimType = ptr TNimType
+  
+# node.len may be the ``first`` element of a set
diff --git a/nimlib/system/mm.nim b/nimlib/system/mm.nim
new file mode 100755
index 000000000..76b5d83bd
--- /dev/null
+++ b/nimlib/system/mm.nim
@@ -0,0 +1,189 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Nimrod high-level memory manager: It supports Boehm's GC, no GC and the
+# native Nimrod GC. The native Nimrod GC is the default.
+
+#{.push checks:on, assertions:on.}
+{.push checks:off.}
+
+const
+  debugGC = false # we wish to debug the GC...
+  logGC = false
+  traceGC = false # extensive debugging
+  reallyDealloc = true # for debugging purposes this can be set to false
+  cycleGC = true # (de)activate the cycle GC
+  stressGC = false
+  reallyOsDealloc = true
+  coalescRight = true
+  coalescLeft = true
+  overwriteFree = false
+
+type
+  PPointer = ptr pointer
+  TByteArray = array[0..1000_0000, byte]
+  PByte = ptr TByteArray
+  PString = ptr string
+
+# Page size of the system; in most cases 4096 bytes. For exotic OS or
+# CPU this needs to be changed:
+const
+  PageShift = 12
+  PageSize = 1 shl PageShift
+  PageMask = PageSize-1
+
+  MemAlign = 8 # also minimal allocatable memory block
+
+  BitsPerPage = PageSize div MemAlign
+  UnitsPerPage = BitsPerPage div (sizeof(int)*8)
+    # how many ints do we need to describe a page:
+    # on 32 bit systems this is only 16 (!)
+
+  TrunkShift = 9
+  BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64
+  TrunkMask = BitsPerTrunk - 1
+  IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
+  IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
+  IntMask = 1 shl IntShift - 1
+
+var
+  gOutOfMem: ref EOutOfMemory
+
+proc raiseOutOfMem() {.noreturn.} =
+  if gOutOfMem == nil: quit("out of memory; cannot even throw an exception")
+  gOutOfMem.msg = "out of memory"
+  raise gOutOfMem
+
+when defined(boehmgc):
+  when defined(windows):
+    const boehmLib = "boehmgc.dll"
+  else:
+    const boehmLib = "/usr/lib/libgc.so.1"
+
+  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} 
+  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} 
+  proc boehmGCincremental {.
+    importc: "GC_enable_incremental", dynlib: boehmLib.} 
+  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}  
+  proc boehmAlloc(size: int): pointer {.
+    importc: "GC_malloc", dynlib: boehmLib.}
+  proc boehmAllocAtomic(size: int): pointer {.
+    importc: "GC_malloc_atomic", dynlib: boehmLib.}
+  proc boehmRealloc(p: pointer, size: int): pointer {.
+    importc: "GC_realloc", dynlib: boehmLib.}
+  proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
+    
+  proc alloc(size: int): pointer =
+    result = boehmAlloc(size)
+    if result == nil: raiseOutOfMem()
+  proc alloc0(size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+  proc realloc(p: Pointer, newsize: int): pointer =
+    result = boehmRealloc(p, newsize)
+    if result == nil: raiseOutOfMem()
+  proc dealloc(p: Pointer) =
+    boehmDealloc(p)
+
+  proc initGC() = nil
+  
+  #boehmGCincremental()
+
+  proc GC_disable() = boehmGC_disable()
+  proc GC_enable() = boehmGC_enable()
+  proc GC_fullCollect() = boehmGCfullCollect()
+  proc GC_setStrategy(strategy: TGC_Strategy) = nil
+  proc GC_enableMarkAndSweep() = nil
+  proc GC_disableMarkAndSweep() = nil
+  proc GC_getStatistics(): string = return ""
+  
+  proc getOccupiedMem(): int = return -1
+  proc getFreeMem(): int = return -1
+  proc getTotalMem(): int = return -1
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).space = len
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+
+  include "system/cellsets"
+elif defined(nogc):
+  include "system/alloc"
+
+  when false:
+    proc alloc(size: int): pointer =
+      result = c_malloc(size)
+      if result == nil: raiseOutOfMem()
+    proc alloc0(size: int): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc realloc(p: Pointer, newsize: int): pointer =
+      result = c_realloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc dealloc(p: Pointer) = c_free(p)
+    proc getOccupiedMem(): int = return -1
+    proc getFreeMem(): int = return -1
+    proc getTotalMem(): int = return -1
+
+  proc initGC() = nil
+  proc GC_disable() = nil
+  proc GC_enable() = nil
+  proc GC_fullCollect() = nil
+  proc GC_setStrategy(strategy: TGC_Strategy) = nil
+  proc GC_enableMarkAndSweep() = nil
+  proc GC_disableMarkAndSweep() = nil
+  proc GC_getStatistics(): string = return ""
+  
+  
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc0(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).space = len
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+
+  include "system/cellsets"
+else:
+  include "system/alloc"
+  include "system/cellsets"
+  assert(sizeof(TCell) == sizeof(TFreeCell))
+  include "system/gc"
+  
+{.pop.}
+
+  
diff --git a/nimlib/system/profiler.nim b/nimlib/system/profiler.nim
new file mode 100755
index 000000000..b87b30d4a
--- /dev/null
+++ b/nimlib/system/profiler.nim
@@ -0,0 +1,61 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the Nimrod profiler. The profiler needs support by the
+# code generator. 
+
+type
+  TProfileData {.compilerproc, final.} = object
+    procname: cstring
+    total: float
+
+var
+  profileData {.compilerproc.}: array [0..64*1024-1, TProfileData]
+
+proc sortProfile(a: var array[0..64*1024-1, TProfileData], N: int) = 
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true: 
+    h = 3 * h + 1
+    if h > N: break 
+  while true: 
+    h = h div 3
+    for i in countup(h, N - 1): 
+      var v = a[i]
+      var j = i
+      while a[j-h].total <= v.total: 
+        a[j] = a[j-h]
+        j = j-h
+        if j < h: break 
+      a[j] = v
+    if h == 1: break
+
+proc writeProfile() {.noconv.} =
+  const filename = "profile_results"
+  var i = 0
+  var f: TFile
+  var j = 1
+  while open(f, filename & $j & ".txt"):
+    close(f)
+    inc(j)
+  if open(f, filename & $j & ".txt", fmWrite):
+    var N = 0
+    # we have to compute the actual length of the array:
+    while profileData[N].procname != nil: inc(N)
+    sortProfile(profileData, N)
+    writeln(f, "total running time of each proc" &
+               " (interpret these numbers relatively)")
+    while profileData[i].procname != nil:
+      write(f, profileData[i].procname)
+      write(f, ": ")
+      writeln(f, profileData[i].total)
+      inc(i)
+    close(f)
+
+addQuitProc(writeProfile)
diff --git a/nimlib/system/repr.nim b/nimlib/system/repr.nim
new file mode 100755
index 000000000..e340f1d7c
--- /dev/null
+++ b/nimlib/system/repr.nim
@@ -0,0 +1,249 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# The generic ``repr`` procedure. It is an invaluable debugging tool.
+
+#proc cstrToNimStrDummy(s: cstring): string {.inline.} =
+#  result = cast[string](cstrToNimStr(s))
+
+proc reprInt(x: int64): string {.compilerproc.} = return $x
+proc reprFloat(x: float): string {.compilerproc.} = return $x
+
+proc reprPointer(x: pointer): string {.compilerproc.} =
+  var buf: array [0..59, char]
+  c_sprintf(buf, "%p", x)
+  return $buf
+
+proc reprStrAux(result: var string, s: string) =
+  if cast[pointer](s) == nil:
+    add result, "nil"
+    return
+  add result, reprPointer(cast[pointer](s)) & "\""
+  for c in items(s):
+    case c
+    of '"': add result, "\\\""
+    of '\\': add result, "\\\\" # BUGFIX: forgotten
+    of '\10': add result, "\\10\"\n\"" # " \n " # better readability
+    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+      add result, "\\" & reprInt(ord(c))
+    else: result.add(c)
+  add result, "\""
+
+proc reprStr(s: string): string {.compilerproc.} =
+  result = ""
+  reprStrAux(result, s)
+
+proc reprBool(x: bool): string {.compilerproc.} =
+  if x: result = "true"
+  else: result = "false"
+
+proc reprChar(x: char): string {.compilerproc.} =
+  result = "\'"
+  case x
+  of '"': add result, "\\\""
+  of '\\': add result, "\\\\"
+  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+  else: add result, x
+  add result, "\'"
+
+proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =
+  if e <% typ.node.len: # BUGFIX
+    result = $typ.node.sons[e].name
+  else:
+    result = $e & " (invalid data!)"
+
+type
+  pbyteArray = ptr array[0.. 0xffff, byte]
+
+proc addSetElem(result: var string, elem: int, typ: PNimType) =
+  case typ.kind
+  of tyEnum: add result, reprEnum(elem, typ)
+  of tyBool: add result, reprBool(bool(elem))
+  of tyChar: add result, reprChar(chr(elem))
+  of tyRange: addSetElem(result, elem, typ.base)
+  of tyInt..tyInt64: add result, reprInt(elem)
+  else: # data corrupt --> inform the user
+    add result, " (invalid data!)"
+
+proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
+  # "typ.slots.len" field is for sets the "first" field
+  var elemCounter = 0  # we need this flag for adding the comma at
+                       # the right places
+  add result, "{"
+  var u: int64
+  case typ.size
+  of 1: u = ze64(cast[ptr int8](p)^)
+  of 2: u = ze64(cast[ptr int16](p)^)
+  of 4: u = ze64(cast[ptr int32](p)^)
+  of 8: u = cast[ptr int64](p)^
+  else:
+    var a = cast[pbyteArray](p)
+    for i in 0 .. typ.size*8-1:
+      if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  if typ.size <= 8:
+    for i in 0..sizeof(int64)*8-1:
+      if (u and (1 shl i)) != 0:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  add result, "}"
+
+proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
+  result = ""
+  reprSetAux(result, p, typ)
+
+type
+  TReprClosure {.final.} = object # we cannot use a global variable here
+                                  # as this wouldn't be thread-safe
+    marked: TCellSet
+    recdepth: int       # do not recurse endless
+    indent: int         # indentation
+
+proc initReprClosure(cl: var TReprClosure) =
+  Init(cl.marked)
+  cl.recdepth = -1      # default is to display everything!
+  cl.indent = 0
+
+proc deinitReprClosure(cl: var TReprClosure) =
+  Deinit(cl.marked)
+
+proc reprBreak(result: var string, cl: TReprClosure) =
+  add result, "\n"
+  for i in 0..cl.indent-1: add result, ' '
+
+proc reprAux(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure)
+
+proc reprArray(result: var string, p: pointer, typ: PNimType,
+               cl: var TReprClosure) =
+  add result, "["
+  var bs = typ.base.size
+  for i in 0..typ.size div bs - 1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
+  add result, "]"
+
+proc reprSequence(result: var string, p: pointer, typ: PNimType,
+                  cl: var TReprClosure) =
+  if p == nil:
+    add result, "nil"
+    return
+  result.add(reprPointer(p) & "[")
+  var bs = typ.base.size
+  for i in 0..cast[PGenericSeq](p).len-1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
+            typ.Base, cl)
+  add result, "]"
+
+proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
+                   cl: var TReprClosure) =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    add result, $n.name
+    add result, " = "
+    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+  of nkList:
+    for i in 0..n.len-1:
+      if i > 0: add result, ",\n"
+      reprRecordAux(result, p, n.sons[i], cl)
+  of nkCase:
+    var m = selectBranch(p, n)
+    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+    if m != nil: reprRecordAux(result, p, m, cl)
+
+proc reprRecord(result: var string, p: pointer, typ: PNimType,
+                cl: var TReprClosure) =
+  add result, "["
+  reprRecordAux(result, p, typ.node, cl)
+  add result, "]"
+
+proc reprRef(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure) =
+  # we know that p is not nil here:
+  when defined(boehmGC) or defined(nogc):
+    var cell = cast[PCell](p)
+  else:
+    var cell = usrToCell(p)
+  add result, "ref " & reprPointer(p)
+  if cell notin cl.marked:
+    # only the address is shown:
+    incl(cl.marked, cell)
+    add result, " --> "
+    reprAux(result, p, typ.base, cl)
+
+proc reprAux(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure) =
+  if cl.recdepth == 0:
+    add result, "..."
+    return
+  dec(cl.recdepth)
+  case typ.kind
+  of tySet: reprSetAux(result, p, typ)
+  of tyArray: reprArray(result, p, typ, cl)
+  of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
+  of tyObject: 
+    var t = cast[ptr PNimType](p)^
+    reprRecord(result, p, t, cl)
+  of tyRef, tyPtr:
+    assert(p != nil)
+    if cast[ppointer](p)^ == nil: add result, "nil"
+    else: reprRef(result, cast[ppointer](p)^, typ, cl)
+  of tySequence:
+    reprSequence(result, cast[ppointer](p)^, typ, cl)
+  of tyInt: add result, $(cast[ptr int](p)^)
+  of tyInt8: add result, $int(cast[ptr Int8](p)^)
+  of tyInt16: add result, $int(cast[ptr Int16](p)^)
+  of tyInt32: add result, $int(cast[ptr Int32](p)^)
+  of tyInt64: add result, $(cast[ptr Int64](p)^)
+  of tyFloat: add result, $(cast[ptr float](p)^)
+  of tyFloat32: add result, $(cast[ptr float32](p)^)
+  of tyFloat64: add result, $(cast[ptr float64](p)^)
+  of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
+  of tyBool: add result, reprBool(cast[ptr bool](p)^)
+  of tyChar: add result, reprChar(cast[ptr char](p)^)
+  of tyString: reprStrAux(result, cast[ptr string](p)^)
+  of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
+  of tyRange: reprAux(result, p, typ.base, cl)
+  of tyProc, tyPointer:
+    if cast[ppointer](p)^ == nil: add result, "nil"
+    else: add result, reprPointer(cast[ppointer](p)^)
+  else:
+    add result, "(invalid data!)"
+  inc(cl.recdepth)
+
+proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
+                   compilerproc.} =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  result = "["
+  var bs = elemtyp.size
+  for i in 0..length - 1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
+  add result, "]"
+  deinitReprClosure(cl)
+
+proc reprAny(p: pointer, typ: PNimType): string =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  result = ""
+  if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
+    reprAux(result, p, typ, cl)
+  else:
+    var p = p
+    reprAux(result, addr(p), typ, cl)
+  add result, "\n"
+  deinitReprClosure(cl)
diff --git a/nimlib/system/sets.nim b/nimlib/system/sets.nim
new file mode 100755
index 000000000..f9f3eb32b
--- /dev/null
+++ b/nimlib/system/sets.nim
@@ -0,0 +1,28 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# set handling
+
+type
+  TNimSet = array [0..4*2048-1, int8]
+
+proc countBits32(n: int32): int {.compilerproc.} =
+  var v = n
+  v = v -% ((v shr 1'i32) and 0x55555555'i32)
+  v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
+  result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32
+
+proc countBits64(n: int64): int {.compilerproc.} = 
+  result = countBits32(toU32(n and 0xffff'i64)) +
+           countBits32(toU32(n shr 16'i64))
+
+proc cardSet(s: TNimSet, len: int): int {.compilerproc.} =
+  result = 0
+  for i in countup(0, len-1):
+    inc(result, countBits32(int32(ze(s[i]))))
diff --git a/nimlib/system/sysio.nim b/nimlib/system/sysio.nim
new file mode 100755
index 000000000..8b6d0e285
--- /dev/null
+++ b/nimlib/system/sysio.nim
@@ -0,0 +1,184 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## Nimrod's standard IO library. It contains high-performance
+## routines for reading and writing data to (buffered) files or
+## TTYs.
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+
+proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl.}
+proc fgets(c: cstring, n: int, f: TFile): cstring {.importc: "fgets", noDecl.}
+proc fgetc(stream: TFile): cint {.importc: "fgetc", nodecl.}
+proc ungetc(c: cint, f: TFile) {.importc: "ungetc", nodecl.}
+proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl.}
+proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs.}
+proc strlen(c: cstring): int {.importc: "strlen", nodecl.}
+
+proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
+  importc, nodecl.}
+
+proc write(f: TFile, c: cstring) = fputs(c, f)
+
+var
+  IOFBF {.importc: "_IOFBF", nodecl.}: cint
+  IONBF {.importc: "_IONBF", nodecl.}: cint
+
+proc rawReadLine(f: TFile, result: var string) =
+  # of course this could be optimized a bit; but IO is slow anyway...
+  # and it was difficult to get this CORRECT with Ansi C's methods
+  setLen(result, 0) # reuse the buffer!
+  while True:
+    var c = fgetc(f)
+    if c < 0'i32: break # EOF
+    if c == 10'i32: break # LF
+    if c == 13'i32:  # CR
+      c = fgetc(f) # is the next char LF?
+      if c != 10'i32: ungetc(c, f) # no, put the character back
+      break
+    add result, chr(int(c))
+
+proc readLine(f: TFile): string =
+  result = ""
+  rawReadLine(f, result)
+
+proc write(f: TFile, s: string) = fputs(s, f)
+proc write(f: TFile, i: int) = 
+  when sizeof(int) == 8:
+    fprintf(f, "%lld", i)
+  else:
+    fprintf(f, "%ld", i)
+    
+proc write(f: TFile, b: bool) =
+  if b: write(f, "true")
+  else: write(f, "false")
+proc write(f: TFile, r: float) = fprintf(f, "%g", r)
+proc write(f: TFile, c: Char) = putc(c, f)
+proc write(f: TFile, a: openArray[string]) =
+  for x in items(a): write(f, x)
+
+#{.error: "for debugging.".}
+
+proc readFile(filename: string): string =
+  var f: TFile
+  try:
+    if open(f, filename):
+      var len = getFileSize(f)
+      if len < high(int):
+        result = newString(int(len))
+        if readBuffer(f, addr(result[0]), int(len)) != len:
+          result = nil
+      close(f)
+    else:
+      result = nil
+  except EIO:
+    result = nil
+
+proc EndOfFile(f: TFile): bool =
+  # do not blame me; blame the ANSI C standard this is so brain-damaged
+  var c = fgetc(f)
+  ungetc(c, f)
+  return c == -1'i32
+
+proc writeln[Ty](f: TFile, x: Ty) =
+  write(f, x)
+  write(f, "\n")
+
+proc writeln[Ty](f: TFile, x: openArray[Ty]) =
+  for i in items(x): write(f, i)
+  write(f, "\n")
+
+proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x)
+proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
+
+# interface to the C procs:
+proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
+
+const
+  FormatOpen: array [TFileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"]
+    #"rt", "wt", "w+t", "r+t", "at"
+    # we always use binary here as for Nimrod the OS line ending
+    # should not be translated.
+
+
+proc Open(f: var TFile, filename: string,
+          mode: TFileMode = fmRead,
+          bufSize: int = -1): Bool =
+  var
+    p: pointer
+  p = fopen(filename, FormatOpen[mode])
+  result = (p != nil)
+  f = cast[TFile](p)
+  if bufSize > 0:
+    if setvbuf(f, nil, IOFBF, bufSize) != 0'i32:
+      raise newException(EOutOfMemory, "out of memory")
+  elif bufSize == 0:
+    discard setvbuf(f, nil, IONBF, 0)
+
+proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {.
+  importc: pccHack & "fdopen", header: "<stdio.h>".}
+
+proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
+  f = fdopen(filehandle, FormatOpen[mode])
+  result = f != nil
+
+proc OpenFile(f: var TFile, filename: string,
+              mode: TFileMode = fmRead,
+              bufSize: int = -1): Bool =
+  result = open(f, filename, mode, bufSize)
+  
+proc openFile(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
+  result = open(f, filehandle, mode)
+
+# C routine that is used here:
+proc fread(buf: Pointer, size, n: int, f: TFile): int {.
+  importc: "fread", noDecl.}
+proc fseek(f: TFile, offset: clong, whence: int): int {.
+  importc: "fseek", noDecl.}
+proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
+
+proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
+  importc: "fwrite", noDecl.}
+
+proc readBuffer(f: TFile, buffer: pointer, len: int): int =
+  result = fread(buffer, 1, len, f)
+
+proc ReadBytes(f: TFile, a: var openarray[byte], start, len: int): int =
+  result = readBuffer(f, addr(a[start]), len)
+
+proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int =
+  result = readBuffer(f, addr(a[start]), len)
+
+proc writeBytes(f: TFile, a: openarray[byte], start, len: int): int =
+  var x = cast[ptr array[0..1000_000_000, byte]](a)
+  result = writeBuffer(f, addr(x[start]), len)
+proc writeChars(f: TFile, a: openarray[char], start, len: int): int =
+  var x = cast[ptr array[0..1000_000_000, byte]](a)
+  result = writeBuffer(f, addr(x[start]), len)
+proc writeBuffer(f: TFile, buffer: pointer, len: int): int =
+  result = fwrite(buffer, 1, len, f)
+
+proc setFilePos(f: TFile, pos: int64) =
+  if fseek(f, clong(pos), 0) != 0:
+    raise newException(EIO, "cannot set file position")
+
+proc getFilePos(f: TFile): int64 =
+  result = ftell(f)
+  if result < 0: raise newException(EIO, "cannot retrieve file position")
+
+proc getFileSize(f: TFile): int64 =
+  var oldPos = getFilePos(f)
+  discard fseek(f, 0, 2) # seek the end of the file
+  result = getFilePos(f)
+  setFilePos(f, oldPos)
+
+{.pop.}
diff --git a/nimlib/system/sysstr.nim b/nimlib/system/sysstr.nim
new file mode 100755
index 000000000..808941c06
--- /dev/null
+++ b/nimlib/system/sysstr.nim
@@ -0,0 +1,289 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# string & sequence handling procedures needed by the code generator
+
+# strings are dynamically resized, have a length field
+# and are zero-terminated, so they can be casted to C
+# strings easily
+# we don't use refcounts because that's a behaviour
+# the programmer may not want
+
+# implementation:
+
+proc resize(old: int): int {.inline.} =
+  if old <= 0: return 4
+  elif old < 65536: return old * 2
+  else: return old * 3 div 2 # for large arrays * 3/2 is better
+
+proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
+  if a == b: return 0
+  if a == nil: return -1
+  if b == nil: return 1
+  return c_strcmp(a.data, b.data)
+
+proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
+  if a == b: return true
+  if a == nil or b == nil: return false
+  return a.len == b.len and
+    c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
+
+proc rawNewString(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 8: s = 7
+  result = cast[NimString](newObj(addr(strDesc), sizeof(TGenericSeq) +
+                           (s+1) * sizeof(char)))
+  result.space = s
+
+proc mnewString(len: int): NimString {.exportc.} =
+  #c_fprintf(c_stdout, "[NEWSTRING] len: %ld\n", len)
+  result = rawNewString(len)
+  result.len = len
+
+proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
+  result = rawNewString(len)
+  result.len = len
+  c_memcpy(result.data, str, (len+1) * sizeof(Char))
+  result.data[len] = '\0' # readline relies on this!
+
+proc cstrToNimstr(str: CString): NimString {.compilerProc.} =
+  return toNimstr(str, c_strlen(str))
+
+proc copyString(src: NimString): NimString {.compilerProc.} =
+  if src == nil: return nil
+  result = rawNewString(src.space)
+  result.len = src.len
+  c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char))
+
+proc hashString(s: string): int {.compilerproc.} =
+  # the compiler needs exactly the same hash function!
+  # this used to be used for efficient generation of string case statements
+  var h = 0
+  for i in 0..Len(s)-1:
+    h = h +% Ord(s[i])
+    h = h +% h shl 10
+    h = h xor (h shr 6)
+  h = h +% h shl 3
+  h = h xor (h shr 11)
+  h = h +% h shl 15
+  result = h
+
+proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
+  var start = max(start, 0)
+  var len = min(last, s.len-1) - start + 1
+  if len > 0:
+    result = rawNewString(len)
+    result.len = len
+    c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
+    result.data[len] = '\0'
+  else:
+    result = mnewString(0)
+
+proc copyStr(s: NimString, start: int): NimString {.exportc.} =
+  return copyStrLast(s, start, s.len-1)
+
+proc addChar(s: NimString, c: char): NimString {.compilerProc.} =
+  result = s
+  if result.len >= result.space:
+    result.space = resize(result.space)
+    result = cast[NimString](growObj(result,
+      sizeof(TGenericSeq) + (result.space+1) * sizeof(char)))
+    #var space = resize(result.space)
+    #result = rawNewString(space)
+    #copyMem(result, s, s.len * sizeof(char) + sizeof(TGenericSeq))
+    #result.space = space
+  result.data[result.len] = c
+  result.data[result.len+1] = '\0'
+  inc(result.len)
+
+# These routines should be used like following:
+#   <Nimrod code>
+#   s &= "hallo " & name & " how do you feel?"
+#
+#   <generated C code>
+#   {
+#     s = resizeString(s, 6 + name->len + 17);
+#     appendString(s, strLit1);
+#     appendString(s, strLit2);
+#     appendString(s, strLit3);
+#   }
+#
+#   <Nimrod code>
+#   s = "hallo " & name & " how do you feel?"
+#
+#   <generated C code>
+#   {
+#     string tmp0;
+#     tmp0 = rawNewString(6 + name->len + 17);
+#     appendString(s, strLit1);
+#     appendString(s, strLit2);
+#     appendString(s, strLit3);
+#     s = tmp0;
+#   }
+#
+#   <Nimrod code>
+#   s = ""
+#
+#   <generated C code>
+#   s = rawNewString(0);
+
+proc resizeString(dest: NimString, addlen: int): NimString {.compilerproc.} =
+  if dest.len + addLen + 1 <= dest.space: # BUGFIX: this is horrible!
+    result = dest
+  else: # slow path:
+    var sp = max(resize(dest.space), dest.len + addLen + 1)
+    result = cast[NimString](growObj(dest, sizeof(TGenericSeq) +
+                           (sp+1) * sizeof(Char)))
+    result.space = sp
+    #result = rawNewString(sp)
+    #copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
+    # DO NOT UPDATE LEN YET: dest.len = newLen
+
+proc appendString(dest, src: NimString) {.compilerproc, inline.} =
+  c_memcpy(addr(dest.data[dest.len]), src.data, (src.len + 1) * sizeof(Char))
+  inc(dest.len, src.len)
+
+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 {.compilerProc.} =
+  var n = max(newLen, 0)
+  if n <= s.space:
+    result = s
+  else:
+    result = resizeString(s, n)
+  result.len = n
+  result.data[n] = '\0'
+
+# ----------------- sequences ----------------------------------------------
+
+proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
+  # increments the length by one:
+  # this is needed for supporting ``add``;
+  #
+  #  add(seq, x)  generates:
+  #  seq = incrSeq(seq, sizeof(x));
+  #  seq[seq->len-1] = x;
+  when false:
+    # broken version:
+    result = seq
+    if result.len >= result.space:
+      var s = resize(result.space)
+      result = cast[PGenericSeq](newSeq(extGetCellType(seq), s))
+      genericSeqAssign(result, seq, XXX)
+      #copyMem(result, seq, seq.len * elemSize + GenericSeqSize)
+    inc(result.len)  
+  else:  
+    result = seq
+    if result.len >= result.space:
+      result.space = resize(result.space)
+      result = cast[PGenericSeq](growObj(result, elemSize * result.space +
+                                 GenericSeqSize))
+      # set new elements to zero:
+      #var s = cast[TAddress](result)
+      #zeroMem(cast[pointer](s + GenericSeqSize + (result.len * elemSize)),
+      #  (result.space - result.len) * elemSize)
+      # for i in len .. space-1:
+      #   seq->data[i] = 0
+    inc(result.len)
+
+proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
+    compilerProc.} =
+  when false:
+    # broken version:
+    result = seq
+    if result.space < newLen:
+      var s = max(resize(result.space), newLen)
+      result = cast[PGenericSeq](newSeq(extGetCellType(seq), s))
+    result.len = newLen
+  else:
+    result = seq
+    if result.space < newLen:
+      result.space = max(resize(result.space), newLen)
+      result = cast[PGenericSeq](growObj(result, elemSize * result.space +
+                                 GenericSeqSize))
+    elif newLen < result.len:
+      # we need to decref here, otherwise the GC leaks!
+      when not defined(boehmGC) and not defined(nogc):
+        for i in newLen..result.len-1:
+          forAllChildrenAux(cast[pointer](cast[TAddress](result) +% 
+                            GenericSeqSize +% (i*%elemSize)),
+                            extGetCellType(result).base, waZctDecRef)
+      # and set the memory to nil:
+      zeroMem(cast[pointer](cast[TAddress](result) +% GenericSeqSize +%
+             (newLen*%elemSize)), (result.len-%newLen) *% elemSize)
+    result.len = newLen
+
+# --------------- other string routines ----------------------------------
+proc nimIntToStr(x: int): string {.compilerproc.} =
+  result = newString(sizeof(x)*4)
+  var i = 0
+  var y = x
+  while True:
+    var d = y div 10
+    result[i] = chr(abs(int(y - d*10)) + ord('0'))
+    inc(i)
+    y = d
+    if y == 0: break
+  if x < 0:
+    result[i] = '-'
+    inc(i)
+  setLen(result, i)
+  # mirror the string:
+  for j in 0..i div 2 - 1:
+    swap(result[j], result[i-j-1])
+
+proc nimFloatToStr(x: float): string {.compilerproc.} =
+  var buf: array [0..59, char]
+  c_sprintf(buf, "%#g", x)
+  return $buf
+
+proc nimInt64ToStr(x: int64): string {.compilerproc.} =
+  # we don't rely on C's runtime here as some C compiler's
+  # int64 support is weak
+  result = newString(sizeof(x)*4)
+  var i = 0
+  var y = x
+  while True:
+    var d = y div 10
+    result[i] = chr(abs(int(y - d*10)) + ord('0'))
+    inc(i)
+    y = d
+    if y == 0: break
+  if x < 0:
+    result[i] = '-'
+    inc(i)
+  setLen(result, i)
+  # mirror the string:
+  for j in 0..i div 2 - 1:
+    swap(result[j], result[i-j-1])
+
+proc nimBoolToStr(x: bool): string {.compilerproc.} =
+  return if x: "true" else: "false"
+
+proc nimCharToStr(x: char): string {.compilerproc.} =
+  result = newString(1)
+  result[0] = x
+
+proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} =
+  var
+    a = 0
+    b = len(x)
+  while a < b:
+     var mid = (a + b) div 2
+     if x[mid] < y:
+       a = mid + 1
+     else:
+       b = mid
+  if (a < len(x)) and (x[a] == y):
+    return a
+  else:
+    return -1