summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-06-26 20:17:19 +0200
committerAraq <rumpf_a@web.de>2011-06-26 20:17:19 +0200
commite25384db8907f846f3c053379cf5b431c4d28760 (patch)
tree73f9fcb73ff0b849805077e17889111314d1bf56
parentc9d21164beef5850b8c3ebb4faf70b59139644d4 (diff)
downloadNim-e25384db8907f846f3c053379cf5b431c4d28760.tar.gz
improvements to get code size down for programs that don't use GC
-rwxr-xr-xcompiler/ccgexprs.nim3
-rwxr-xr-xinstall.sh4
-rwxr-xr-xlib/system.nim59
-rwxr-xr-xlib/system/debugger.nim39
-rwxr-xr-xlib/system/excpt.nim186
-rwxr-xr-xlib/system/gc.nim1
-rwxr-xr-xlib/system/mmdisp.nim13
-rwxr-xr-xlib/system/sysstr.nim31
-rwxr-xr-xlib/system/threads.nim5
-rw-r--r--tests/accept/compile/tcodegenbug1.nim55
-rw-r--r--tests/accept/compile/tnimrodnode_for_runtime.nim13
-rw-r--r--tests/accept/run/tgenericassigntuples.nim16
-rw-r--r--tests/accept/run/tsimplesort.nim346
-rw-r--r--tests/reject/temptycaseobj.nim14
-rw-r--r--tests/reject/tprocvar.nim18
-rwxr-xr-xtests/stckovfl.nim4
-rwxr-xr-xtodo.txt16
-rwxr-xr-xweb/news.txt2
18 files changed, 643 insertions, 182 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index d054e5bac..33c654982 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1451,6 +1451,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
      mInSet:
     genSetOp(p, e, d, op)
   of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, mCreateThread: 
+    var opr = e.sons[0].sym
+    if lfNoDecl notin opr.loc.flags:
+      discard cgsym(p.module, opr.loc.r.ropeToStr)
     genCall(p, e, d)
   of mReset: genReset(p, e)
   of mEcho: genEcho(p, e)
diff --git a/install.sh b/install.sh
index 4ac8d5215..a7a87de14 100755
--- a/install.sh
+++ b/install.sh
@@ -203,8 +203,6 @@ if [ $# -eq 1 ] ; then
   chmod 644 $libdir/system/threads.nim
   cp lib/core/macros.nim $libdir/core/macros.nim || exit 1
   chmod 644 $libdir/core/macros.nim
-  cp lib/core/marshal.nim $libdir/core/marshal.nim || exit 1
-  chmod 644 $libdir/core/marshal.nim
   cp lib/core/typeinfo.nim $libdir/core/typeinfo.nim || exit 1
   chmod 644 $libdir/core/typeinfo.nim
   cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
@@ -241,6 +239,8 @@ if [ $# -eq 1 ] ; then
   chmod 644 $libdir/pure/lexbase.nim
   cp lib/pure/logging.nim $libdir/pure/logging.nim || exit 1
   chmod 644 $libdir/pure/logging.nim
+  cp lib/pure/marshal.nim $libdir/pure/marshal.nim || exit 1
+  chmod 644 $libdir/pure/marshal.nim
   cp lib/pure/math.nim $libdir/pure/math.nim || exit 1
   chmod 644 $libdir/pure/math.nim
   cp lib/pure/md5.nim $libdir/pure/md5.nim || exit 1
diff --git a/lib/system.nim b/lib/system.nim
index e19a9749d..5ece9375e 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1387,7 +1387,7 @@ const nimrodStackTrace = compileOption("stacktrace")
 # of the code
 
 var
-  dbgLineHook*: proc = nil
+  dbgLineHook*: proc
     ## set this variable to provide a procedure that should be called before
     ## each executed instruction. This should only be used by debuggers!
     ## Only code compiled with the ``debugger:on`` switch calls this hook.
@@ -1397,6 +1397,25 @@ var
     ## application code should never set this hook! You better know what you
     ## do when setting this. If ``raiseHook`` returns false, the exception
     ## is caught and does not propagate further through the call stack.
+    
+  outOfMemHook*: proc
+    ## set this variable to provide a procedure that should be called 
+    ## in case of an `out of memory`:idx: event. The standard handler
+    ## writes an error message and terminates the program. `outOfMemHook` can
+    ## be used to raise an exception in case of OOM like so:
+    ## 
+    ## code-block:: nimrod
+    ##   var gOutOfMem: ref EOutOfMemory
+    ##   new(gOutOfMem) # need to be allocated *before* OOM really happened!
+    ##   gOutOfMem.msg = "out of memory"
+    ## 
+    ##   proc handleOOM() =
+    ##     raise gOutOfMem
+    ##
+    ##   system.outOfMemHook = handleOOM
+    ##
+    ## If the handler does not raise an exception, ordinary control flow
+    ## continues and the program is terminated.
 
 type
   PFrame = ptr TFrame
@@ -1710,25 +1729,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   # as it would recurse endlessly!
   include "system/arithm"
   {.pop.} # stack trace
-
-  include "system/sysio"
-
-  iterator lines*(filename: string): string =
-    ## Iterate over any line in the file named `filename`.
-    ## If the file does not exist `EIO` is raised.
-    var f = open(filename)
-    var res = ""
-    while not endOfFile(f):
-      rawReadLine(f, res)
-      yield res
-    Close(f)
-
-  iterator lines*(f: TFile): string =
-    ## Iterate over any line in the file `f`.
-    var res = ""
-    while not endOfFile(f):
-      rawReadLine(f, res)
-      yield res
       
   include "system/dyncalls"
   include "system/sets"
@@ -1763,6 +1763,25 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   include "system/sysstr"
   {.pop.}
 
+  include "system/sysio"
+
+  iterator lines*(filename: string): string =
+    ## Iterate over any line in the file named `filename`.
+    ## If the file does not exist `EIO` is raised.
+    var f = open(filename)
+    var res = ""
+    while not endOfFile(f):
+      rawReadLine(f, res)
+      yield res
+    Close(f)
+
+  iterator lines*(f: TFile): string =
+    ## Iterate over any line in the file `f`.
+    var res = ""
+    while not endOfFile(f):
+      rawReadLine(f, res)
+      yield res
+
   include "system/assign"
   include "system/repr"
 
diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim
index 2dccd8579..8f381585b 100755
--- a/lib/system/debugger.nim
+++ b/lib/system/debugger.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -138,10 +138,8 @@ proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
     write(stdout, "*** endb| (procedure name not available) ***\n")
 
 proc dbgShowExecutionPoint() =
-  ThreadGlobals()
-  write(stdout, "*** endb| " & $(||framePtr).filename & 
-                "(" & $(||framePtr).line & ") " & 
-                $(||framePtr).procname & " ***\n")
+  write(stdout, "*** endb| " & $framePtr.filename & 
+                "(" & $framePtr.line & ") " & $framePtr.procname & " ***\n")
 
 when defined(windows) or defined(dos) or defined(os2):
   {.define: FileSystemCaseInsensitive.}
@@ -172,10 +170,9 @@ proc fileMatches(c, bp: cstring): bool =
   return true
 
 proc dbgBreakpointReached(line: int): int =
-  ThreadGlobals()
   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
+        fileMatches(framePtr.filename, dbgBP[i].filename): return i
   return -1
 
 proc scanAndAppendWord(src: string, a: var string, start: int): int =
@@ -257,7 +254,6 @@ proc hasExt(s: string): bool =
   return false
 
 proc setBreakPoint(s: string, start: int) =
-  ThreadGlobals()
   var dbgTemp: string
   var i = scanWord(s, dbgTemp, start)
   if i <= start:
@@ -272,7 +268,7 @@ proc setBreakPoint(s: string, start: int) =
   i = scanNumber(s, dbgBP[x].low, i)
   if dbgBP[x].low == 0:
     # set to current line:
-    dbgBP[x].low = (||framePtr).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
@@ -281,7 +277,7 @@ proc setBreakPoint(s: string, start: int) =
     if not hasExt(dbgTemp): add(dbgTemp, ".nim")
     dbgBP[x].filename = dbgTemp
   else: # use current filename
-    dbgBP[x].filename = $(||framePtr).filename
+    dbgBP[x].filename = $framePtr.filename
   # skip whitespace:
   while s[i] in {' ', '\t'}: inc(i)
   if s[i] != '\0':
@@ -350,10 +346,9 @@ proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
 
 proc CommandPrompt() =
   # if we return from this routine, user code executes again
-  ThreadGlobals()
   var
     again = True
-    dbgFramePtr = ||framePtr # for going down and up the stack
+    dbgFramePtr = framePtr # for going down and up the stack
     dbgDown = 0 # how often we did go down
 
   while again:
@@ -370,11 +365,11 @@ proc CommandPrompt() =
       again = false
     of "n", "next":
       dbgState = dbStepOver
-      dbgSkipToFrame = ||framePtr
+      dbgSkipToFrame = framePtr
       again = false
     of "f", "skipcurrent":
       dbgState = dbSkipCurrent
-      dbgSkipToFrame = (||framePtr).prev
+      dbgSkipToFrame = framePtr.prev
       again = false
     of "c", "continue":
       dbgState = dbBreakpoints
@@ -405,7 +400,7 @@ proc CommandPrompt() =
       if dbgDown <= 0:
         debugOut("[Warning] cannot go up any further ")
       else:
-        dbgFramePtr = ||framePtr
+        dbgFramePtr = framePtr
         for j in 0 .. dbgDown-2: # BUGFIX
           dbgFramePtr = dbgFramePtr.prev
         dec(dbgDown)
@@ -446,17 +441,16 @@ proc endbStep() =
   CommandPrompt()
 
 proc checkForBreakpoint() =
-  ThreadGlobals()
-  var i = dbgBreakpointReached((||framePtr).line)
+  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, framePtr.filename)
     write(stdout, "(")
-    write(stdout, (||framePtr).line)
+    write(stdout, framePtr.line)
     write(stdout, ") ")
-    write(stdout, (||framePtr).procname)
+    write(stdout, framePtr.procname)
     write(stdout, " ***\n")
     CommandPrompt()
 
@@ -487,8 +481,7 @@ proc endb(line: int) {.compilerproc.} =
   # 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"
-  ThreadGlobals()
-  (||framePtr).line = line # this is done here for smaller code size!
+  framePtr.line = line # this is done here for smaller code size!
   if dbgLineHook != nil: dbgLineHook()
   case dbgState
   of dbStepInto:
@@ -496,7 +489,7 @@ proc endb(line: int) {.compilerproc.} =
     dbgShowExecutionPoint()
     CommandPrompt()
   of dbSkipCurrent, dbStepOver: # skip current routine
-    if ||framePtr == dbgSkipToFrame:
+    if framePtr == dbgSkipToFrame:
       dbgShowExecutionPoint()
       CommandPrompt()
     else: # breakpoints are wanted though (I guess)
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index ac4ec2f0b..6ef4ca376 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -7,16 +7,15 @@
 #    distribution, for details about the copyright.
 #
 
-# Exception handling code. This is difficult because it has
-# to work if there is no more memory (but it doesn't yet!).
-
-# XXX assertions are unnecessarily complex; system should use their own
-# assertion mechanism instead!
+# Exception handling code. Carefully coded so that tiny programs which do not
+# use the heap (and nor exceptions) do not include the GC or memory allocator.
 
 var
-  stackTraceNewLine* = "\n" ## undocumented feature; it is replaced by ``<br>``
-                            ## for CGI applications
-  isMultiThreaded: bool # true when prog created at least 1 thread
+  stackTraceNewLine*: string ## undocumented feature; it is replaced by ``<br>``
+                             ## for CGI applications
+
+template stackTraceNL: expr =
+  (if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
 
 when not defined(windows) or not defined(guiapp):
   proc writeToStdErr(msg: CString) = write(stdout, msg)
@@ -42,21 +41,6 @@ var
     # a global variable for the root of all try blocks
   currException {.rtlThreadVar.}: ref E_Base
 
-  buf {.rtlThreadVar.}: string # cannot be allocated on the stack!
-  assertBuf {.rtlThreadVar.}: string 
-    # we need a different buffer for
-    # assert, as it raises an exception and
-    # exception handler needs the buffer too
-  gAssertionFailed {.rtlThreadVar.}: ref EAssertionFailed
-
-proc initGlobals() =
-  new(gAssertionFailed)
-  buf = newStringOfCap(2000)
-  assertBuf = newStringOfCap(2000)
-
-when not hasThreadSupport:
-  initGlobals()
-
 proc pushFrame(s: PFrame) {.compilerRtl, inl.} = 
   s.prev = framePtr
   framePtr = s
@@ -83,8 +67,10 @@ proc popCurrentException {.compilerRtl, inl.} =
 
 # some platforms have native support for stack traces:
 const
-   nativeStackTraceSupported = (defined(macosx) or defined(linux)) and 
-                               not nimrodStackTrace
+  nativeStackTraceSupported = (defined(macosx) or defined(linux)) and 
+                              not nimrodStackTrace
+  hasSomeStackTrace = nimrodStackTrace or 
+    defined(nativeStackTrace) and nativeStackTraceSupported
 
 when defined(nativeStacktrace) and nativeStackTraceSupported:
   type
@@ -126,7 +112,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
             add(s, tempDlInfo.dli_sname)
         else:
           add(s, '?')
-        add(s, stackTraceNewLine)
+        add(s, stackTraceNL)
       else:
         if dlresult != 0 and tempDlInfo.dli_sname != nil and
             c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
@@ -181,24 +167,24 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
         add(s, ')')
       for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
       add(s, tempFrames[j].procname)
-    add(s, stackTraceNewLine)
-
-proc rawWriteStackTrace(s: var string) =
-  when nimrodStackTrace:
-    if framePtr == nil:
-      add(s, "No stack traceback available")
-      add(s, stackTraceNewLine)
+    add(s, stackTraceNL)
+
+when hasSomeStackTrace:
+  proc rawWriteStackTrace(s: var string) =
+    when nimrodStackTrace:
+      if framePtr == nil:
+        add(s, "No stack traceback available")
+        add(s, stackTraceNL)
+      else:
+        add(s, "Traceback (most recent call last)")
+        add(s, stackTraceNL)
+        auxWriteStackTrace(framePtr, s)
+    elif defined(nativeStackTrace) and nativeStackTraceSupported:
+      add(s, "Traceback from system (most recent call last)")
+      add(s, stackTraceNL)
+      auxWriteStackTraceWithBacktrace(s)
     else:
-      add(s, "Traceback (most recent call last)")
-      add(s, stackTraceNewLine)
-      auxWriteStackTrace(framePtr, s)
-  elif defined(nativeStackTrace) and nativeStackTraceSupported:
-    add(s, "Traceback from system (most recent call last)")
-    add(s, stackTraceNewLine)
-    auxWriteStackTraceWithBacktrace(s)
-  else:
-    add(s, "No stack traceback available")
-    add(s, stackTraceNewLine)
+      add(s, "No stack traceback available\n")
 
 proc quitOrDebug() {.inline.} =
   when not defined(endb):
@@ -214,13 +200,16 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
   if excHandler != nil:
     pushCurrentException(e)
     c_longjmp(excHandler.context, 1)
+  elif e[] is EOutOfMemory:
+    writeToStdErr(ename)
+    quitOrDebug()
   else:
-    if not isNil(buf):
-      setLen(buf, 0)
+    when hasSomeStackTrace:
+      var buf = newStringOfCap(2000)
       rawWriteStackTrace(buf)
-      if e.msg != nil and e.msg[0] != '\0':
+      if not isNil(e.msg):
         add(buf, "Error: unhandled exception: ")
-        add(buf, $e.msg)
+        add(buf, e.msg)
       else:
         add(buf, "Error: unhandled exception")
       add(buf, " [")
@@ -228,7 +217,21 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
       add(buf, "]\n")
       writeToStdErr(buf)
     else:
-      writeToStdErr(ename)
+      # ugly, but avoids heap allocations :-)
+      template xadd(buf, s, slen: expr) =
+        if L + slen < high(buf):
+          copyMem(addr(buf[L]), cstring(s), slen)
+          inc L, slen
+      template add(buf, s: expr) =
+        xadd(buf, s, s.len)
+      var buf: array [0..2000, char]
+      var L = 0
+      add(buf, "Error: unhandled exception: ")
+      if not isNil(e.msg): add(buf, e.msg)
+      add(buf, " [")
+      xadd(buf, ename, c_strlen(ename))
+      add(buf, "]\n")
+      writeToStdErr(buf)
     quitOrDebug()
   GC_enable()
 
@@ -240,54 +243,57 @@ proc reraiseException() {.compilerRtl.} =
 
 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)
+    var gAssertionFailed: ref EAssertionFailed
+    new(gAssertionFailed)
+    gAssertionFailed.msg = newStringOfCap(200)
+    add(gAssertionFailed.msg, "[Assertion failure] file: ")
+    add(gAssertionFailed.msg, file)
+    add(gAssertionFailed.msg, " line: ")
+    add(gAssertionFailed.msg, $line)
+    add(gAssertionFailed.msg, "\n")
+    raise gAssertionFailed
 
 proc WriteStackTrace() =
-  var s = ""
-  rawWriteStackTrace(s)
-  writeToStdErr(s)
+  when hasSomeStackTrace:
+    var s = ""
+    rawWriteStackTrace(s)
+    writeToStdErr(s)
+  else:
+    writeToStdErr("No stack traceback available\n")
 
-var
-  dbgAborting: bool # whether the debugger wants to abort
+when defined(endb):
+  var
+    dbgAborting: bool # whether the debugger wants to abort
 
 proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
+  template processSignal(s, action: expr) =
+    if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
+    elif s == SIGSEGV: 
+      action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
+    elif s == SIGABRT:
+      when defined(endb):
+        if dbgAborting: return # the debugger wants to abort
+      action("SIGABRT: Abnormal termination.\n")
+    elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
+    elif s == SIGILL: action("SIGILL: Illegal operation.\n")
+    elif s == SIGBUS: 
+      action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
+    else: action("unknown signal\n")
+
   # 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. (Attempt to read from nil?)\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. (Attempt to read from nil?)\n")
-  else: add(buf, "unknown signal\n")
-  writeToStdErr(buf)
-  dbgAborting = True # play safe here...
-  GC_enable()
+  when hasSomeStackTrace:
+    GC_disable()
+    var buf = newStringOfCap(2000)
+    rawWriteStackTrace(buf)
+    processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
+    writeToStdErr(buf)
+    GC_enable()
+  else:
+    var msg: cstring
+    template asgn(y: expr) = msg = y
+    processSignal(sig, asgn)
+    writeToStdErr(msg)
+  when defined(endb): dbgAborting = True
   quit(1) # always quit when SIGABRT
 
 proc registerSignalHandler() =
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 619b1c9b1..29fd2eae5 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -279,7 +279,6 @@ proc initGC() =
     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)
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 272a2c626..d450c520e 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -52,15 +52,10 @@ const
   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: 
-    echo("out of memory; cannot even throw an exception")
-    quit(1)
-  gOutOfMem.msg = "out of memory"
-  raise gOutOfMem
+proc raiseOutOfMem() {.noinline.} =
+  if outOfMemHook != nil: outOfMemHook()
+  echo("out of memory")
+  quit(1)
 
 when defined(boehmgc):
   when defined(windows):
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index e8d351899..b0843fc11 100755
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -39,11 +39,24 @@ proc rawNewString(space: int): NimString {.compilerProc.} =
                            (s+1) * sizeof(char)))
   result.space = s
 
-proc mnewString(len: int): NimString {.exportc.} =
-  #c_fprintf(c_stdout, "[NEWSTRING] len: %ld\n", len)
+proc mnewString(len: int): NimString {.compilerProc.} =
   result = rawNewString(len)
   result.len = len
 
+proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
+  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 {.compilerProc.} =
+  result = copyStrLast(s, start, s.len-1)
+
 proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
   result = rawNewString(len)
   result.len = len
@@ -72,20 +85,6 @@ proc hashString(s: string): int {.compilerproc.} =
   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.} =
-  result = copyStrLast(s, start, s.len-1)
-
 proc addChar(s: NimString, c: char): NimString =
   # is compilerproc!
   result = s
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 7478b89d0..86a6a5691 100755
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -202,7 +202,6 @@ proc ThreadVarsAlloc(size: int): pointer =
   result = c_malloc(size)
   zeroMem(result, size)
 proc ThreadVarsDealloc(p: pointer) {.importc: "free", nodecl.}
-proc initGlobals()
 
 type
   PGcThread = ptr TGcThread
@@ -239,8 +238,7 @@ when not defined(useNimRtl):
 
   initStackBottom()
   initGC()
-  initGlobals()
-
+  
   var heapLock: TSysLock
   InitSysLock(HeapLock)
 
@@ -301,7 +299,6 @@ template ThreadProcWrapperBody(closure: expr) =
     setStackBottom(addr(t))
     initGC()
   t.stackBottom = addr(t)
-  initGlobals()
   registerThread(t)
   try:
     t.fn(t.data)
diff --git a/tests/accept/compile/tcodegenbug1.nim b/tests/accept/compile/tcodegenbug1.nim
new file mode 100644
index 000000000..4ceaf6ebf
--- /dev/null
+++ b/tests/accept/compile/tcodegenbug1.nim
@@ -0,0 +1,55 @@
+import os
+# TODO: Rename this module to ``utils``
+type
+  TStatusEnum* = enum
+    sUnknown = -1, sBuildFailure, sBuildInProgress, sBuildSuccess,
+    sTestFailure, sTestInProgress, sTestSuccess, # ORDER MATTERS!
+    sDocGenFailure, sDocGenInProgress, sDocGenSuccess,
+    sCSrcGenFailure, sCSrcGenInProgress, sCSrcGenSuccess
+
+  TStatus* = object
+    status*: TStatusEnum
+    desc*: string
+    hash*: string
+    
+proc initStatus*(): TStatus =
+  result.status = sUnknown
+  result.desc = ""
+  result.hash = ""
+
+proc isInProgress*(status: TStatusEnum): bool =
+  return status in {sBuildInProgress, sTestInProgress, sDocGenInProgress,
+                    sCSrcGenInProgress}
+
+proc `$`*(status: TStatusEnum): string =
+  case status
+  of sBuildFailure:
+    return "build failure"
+  of sBuildInProgress:
+    return "build in progress"
+  of sBuildSuccess:
+    return "build finished"
+  of sTestFailure:
+    return "testing failure"
+  of sTestInProgress:
+    return "testing in progress"
+  of sTestSuccess:
+    return "testing finished"
+  of sDocGenFailure:
+    return "documentation generation failed"
+  of sDocGenInProgress:
+    return "generating documentation"
+  of sDocGenSuccess:
+    return "documentation generation succeeded"
+  of sCSrcGenFailure:
+    return "csource generation failed"
+  of sCSrcGenInProgress:
+    return "csource generation in progress"
+  of sCSrcGenSuccess:
+    return "csource generation succeeded"
+  of sUnknown:
+    return "unknown"
+    
+proc makeCommitPath*(platform, hash: string): string =
+  return platform / "nimrod_" & hash.copy(0, 11) # 11 Chars.
+
diff --git a/tests/accept/compile/tnimrodnode_for_runtime.nim b/tests/accept/compile/tnimrodnode_for_runtime.nim
new file mode 100644
index 000000000..e73c8430f
--- /dev/null
+++ b/tests/accept/compile/tnimrodnode_for_runtime.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "bla"
+  disabled: true
+"""
+
+import macros
+proc makeMacro: PNimrodNode =
+  result = nil
+
+var p = makeMacro()
+
+echo "bla"
+
diff --git a/tests/accept/run/tgenericassigntuples.nim b/tests/accept/run/tgenericassigntuples.nim
new file mode 100644
index 000000000..6dd63a984
--- /dev/null
+++ b/tests/accept/run/tgenericassigntuples.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''abc232'''
+"""
+
+var t, s: tuple[x: string, c: int]
+
+proc ugh: seq[tuple[x: string, c: int]] = 
+  result = @[("abc", 232)]
+
+t = ugh()[0]
+s = t
+s = ugh()[0]
+
+echo s[0], t[1]
+
+
diff --git a/tests/accept/run/tsimplesort.nim b/tests/accept/run/tsimplesort.nim
new file mode 100644
index 000000000..3ae2d06f8
--- /dev/null
+++ b/tests/accept/run/tsimplesort.nim
@@ -0,0 +1,346 @@
+discard """
+  output: '''true'''
+"""
+  
+import hashes, math
+
+
+when defined(shallowADT):
+  {.pragma: myShallow, shallow.}
+else:
+  {.pragma: myShallow.}
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable* {.final, myShallow.}[A, B] = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+proc len*[A, B](t: TTable[A, B]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TTable[A, B]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].key
+
+iterator values*[A, B](t: TTable[A, B]): B =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].val
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+template rawGetImpl() =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].slot != seEmpty:
+    if t.data[h].key == key and t.data[h].slot == seFilled:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+template rawInsertImpl() =
+  var h: THash = hash(key) and high(data)
+  while data[h].slot == seFilled:
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+  data[h].slot = seFilled
+
+proc RawGet[A, B](t: TTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: TTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc RawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
+                     key: A, val: B) =
+  rawInsertImpl()
+
+proc Enlarge[A, B](t: var TTable[A, B]) =
+  var n: TKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+template PutImpl() =
+  var index = RawGet(t, key)
+  if index >= 0:
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter): Enlarge(t)
+    RawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc del*[A, B](t: var TTable[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    t.data[index].slot = seDeleted
+    dec(t.counter)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toTable*[A, B](pairs: openarray[tuple[key: A, 
+                    val: B]]): TTable[A, B] =
+  ## creates a new hash table that contains the given `pairs`.
+  result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
+  for key, val in items(pairs): result[key] = val
+
+template dollarImpl(): stmt =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.add($key)
+      result.add(": ")
+      result.add($val)
+    result.add("}")
+
+proc `$`*[A, B](t: TTable[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
+# ------------------------------ count tables -------------------------------
+
+type
+  TCountTable* {.final, myShallow.}[
+      A] = object ## table that counts the number of each key
+    data: seq[tuple[key: A, val: int]]
+    counter: int
+
+proc len*[A](t: TCountTable[A]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: TCountTable[A]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: TCountTable[A]): int =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+proc RawGet[A](t: TCountTable[A], key: A): int =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].val != 0:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc `[]`*[A](t: TCountTable[A], key: A): int =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## 0 is returned. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A](t: TCountTable[A], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc RawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
+                  key: A, val: int) =
+  var h: THash = hash(key) and high(data)
+  while data[h].val != 0: h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc Enlarge[A](t: var TCountTable[A]) =
+  var n: seq[tuple[key: A, val: int]]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].val != 0: RawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
+  ## puts a (key, value)-pair into `t`. `val` has to be positive.
+  assert val > 0
+  PutImpl()
+
+proc initCountTable*[A](initialSize=64): TCountTable[A] =
+  ## creates a new count table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toCountTable*[A](keys: openArray[A]): TCountTable[A] =
+  ## creates a new count table with every key in `keys` having a count of 1.
+  result = initCountTable[A](nextPowerOfTwo(keys.len+10))
+  for key in items(keys): result[key] = 1
+
+proc `$`*[A](t: TCountTable[A]): string =
+  ## The `$` operator for count tables.
+  dollarImpl()
+
+proc inc*[A](t: var TCountTable[A], key: A, val = 1) = 
+  ## increments `t[key]` by `val`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    inc(t.data[index].val, val)
+  else:
+    if mustRehash(len(t.data), t.counter): Enlarge(t)
+    RawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the largest (key,val)-pair. Efficiency: O(n)
+  assert t.len > 0
+  var minIdx = 0
+  for h in 1..high(t.data):
+    if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h
+  result.key = t.data[minIdx].key
+  result.val = t.data[minIdx].val
+
+proc Largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
+  assert t.len > 0
+  var maxIdx = 0
+  for h in 1..high(t.data):
+    if t.data[maxIdx].val < t.data[h].val: maxIdx = h
+  result.key = t.data[maxIdx].key
+  result.val = t.data[maxIdx].val
+
+proc sort*[A](t: var TCountTable[A]) =
+  ## sorts the count table so that the entry with the highest counter comes
+  ## first. This is destructive! You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+  var w: type(t.data[0])
+  checkTypeInfo(addr(w), 10, GetTypeInfo(w))
+
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h >= high(t.data): break
+  while true:
+    h = h div 3
+    for i in countup(h, high(t.data)):
+      var j = i
+      checkTypeInfo(addr(w), 11, GetTypeInfo(w))
+      while t.data[j-h].val <= t.data[j].val:
+        checkTypeInfo(addr(w), 12, GetTypeInfo(w))
+        var xyz = t.data[j]
+        checkTypeInfo(addr(w), 13, GetTypeInfo(w))
+        t.data[j] = xyz
+        checkTypeInfo(addr(w), 14, GetTypeInfo(w))
+        t.data[j-h] = t.data[j]
+        #swap(t.data[j], t.data[j-h])
+        checkTypeInfo(addr(w), 15, GetTypeInfo(w))
+        j = j-h
+        checkTypeInfo(addr(w), 16, GetTypeInfo(w))
+        if j < h: break
+    if h == 1: break
+
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+proc fake() =
+  #var s: TTable[string, int]
+  #var otherCountTable: TCountTable[string]
+  #var w: type(otherCountTable.data[0])
+  #checkTypeInfo(addr(w), nil, GetTypeInfo(w))
+
+proc countTableTest1 =
+  #fake()
+  var s = initTable[string, int](64)
+  for key, val in items(data): s[key] = val
+  var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
+  checkTypeInfo(addr(w), 0, GetTypeInfo(w))
+  
+  #var s = data.toTable
+  #var otherCountTable: TCountTable[string]
+  #var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
+  checkTypeInfo(addr(w), 1, GetTypeInfo(w))
+  
+  var t = initCountTable[string]()
+  checkTypeInfo(addr(w), 2, GetTypeInfo(w))
+  for k, v in items(data): t.inc(k)
+  checkTypeInfo(addr(w), 3, GetTypeInfo(w))
+  for k in t.keys: assert t[k] == 1
+  checkTypeInfo(addr(w), 4, GetTypeInfo(w))
+  t.inc("90", 3)
+  checkTypeInfo(addr(w), 5, GetTypeInfo(w))
+  t.inc("12", 2)
+  checkTypeInfo(addr(w), 6, GetTypeInfo(w))
+  t.inc("34", 1)
+  checkTypeInfo(addr(w), 7, GetTypeInfo(w))
+  assert t.largest()[0] == "90"
+  checkTypeInfo(addr(w), 8, GetTypeInfo(w))
+  t.sort()
+  checkTypeInfo(addr(w), 9, GetTypeInfo(w))
+  when false:
+    for k, v in t.pairs:
+      echo k, ": ", v
+
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+countTableTest1()
+echo true
+
+
diff --git a/tests/reject/temptycaseobj.nim b/tests/reject/temptycaseobj.nim
new file mode 100644
index 000000000..5977cb92b
--- /dev/null
+++ b/tests/reject/temptycaseobj.nim
@@ -0,0 +1,14 @@
+discard """
+  line: 11
+  errormsg: "identifier expected, but found '[same indentation]'"
+"""
+
+type
+  TMyEnum = enum enA, enU, enO
+  TMyCase = object
+    case e: TMyEnum
+    of enA:
+    of enU: x, y: int
+    of enO: a, b: string
+
+
diff --git a/tests/reject/tprocvar.nim b/tests/reject/tprocvar.nim
new file mode 100644
index 000000000..56f76c613
--- /dev/null
+++ b/tests/reject/tprocvar.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "type mismatch"
+  line: 17
+  file: "tprocvar.nim"
+"""
+
+type
+  TCallback = proc (a, b: int)
+
+proc huh(x, y: var int) =
+  x = 0
+  y = x+1
+
+proc so(c: TCallback) =
+  c(2, 4)
+  
+so(huh)
+
diff --git a/tests/stckovfl.nim b/tests/stckovfl.nim
index 799fe0001..205d73edf 100755
--- a/tests/stckovfl.nim
+++ b/tests/stckovfl.nim
@@ -1,7 +1,9 @@
 # To test stack overflow message
 
 proc over(a: int): int = 
-  if a == high(int): return
+  if a >= 400:
+    assert false
+    return
   result = over(a+1)+5
   
 Echo($over(0))
diff --git a/todo.txt b/todo.txt
index 5e1788aac..3308309c7 100755
--- a/todo.txt
+++ b/todo.txt
@@ -2,7 +2,6 @@ High priority (version 0.8.12)
 ==============================
 * test threads on windows; thread analysis needs to be even more restrictive!
 * implement message passing built-ins: channels/queues
-* outOfMem hook; 0 over-head for hello world program :-)
 * bug: {:}.toTable[int, string]()
 
 
@@ -20,18 +19,6 @@ version 0.9.0
 - fix overloading resolution
 - make ^ available as operator
 - implement closures; implement proper coroutines
-- rethink comment syntax; people want::
-
-  type
-    TConfig* = object
-      limit*: int
-      outFile*: string
-      # Regex patterns to ignore. TLogEntry field -> regex pattern
-      # If this matches, the request will NOT be shown.
-      ignoreRe*: TTable[string, string] 
-
-  I think a good compromise is to define positions for the docgen in the
-  grammar and ignore other comments everywhere.
 
 Bugs
 ----
@@ -45,8 +32,7 @@ version 0.9.XX
 ==============
 
 - distinct types for array/seq indexes
-- GC: marker procs for native Nimrod GC and Boehm GC
-- code concerning 'assert' is wasteful and unnecessarily complex
+- GC: marker procs for native Nimrod GC and Boehm GC; precise stack marking
 - implicit ref/ptr->var conversion; the compiler may store an object
   implicitly on the heap for write barrier efficiency
 - resizing of strings/sequences could take into account the memory that
diff --git a/web/news.txt b/web/news.txt
index a7f6a0b78..cb41dba7c 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -95,7 +95,7 @@ Additions
 - Added a wrapper for ``sphinx``.
 - The compiler now supports array, sequence and string slicing.
 - Added ``system.newStringOfCap``.
-- Added ``system.raiseHook`` and ``system.outOfMemoryHook``.
+- Added ``system.raiseHook`` and ``system.outOfMemHook``.
 - Added ``system.writeFile``.
 - Added ``system.shallowCopy``.
 - ``system.echo`` is guaranteed to be thread-safe.