summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ccgexprs.nim4
-rwxr-xr-xcompiler/ccgstmts.nim11
-rwxr-xr-xcompiler/pragmas.nim52
-rwxr-xr-xcompiler/renderer.nim2
-rwxr-xr-xcompiler/sem.nim1
-rwxr-xr-xcompiler/semdata.nim1
-rwxr-xr-xcompiler/semstmts.nim14
-rwxr-xr-xcompiler/semtypes.nim3
-rwxr-xr-xcompiler/wordrecg.nim4
-rwxr-xr-xdoc/endb.txt35
-rwxr-xr-xlib/pure/algorithm.nim6
-rwxr-xr-xlib/system.nim42
-rwxr-xr-xlib/system/alloc.nim2
-rwxr-xr-xlib/system/cellsets.nim2
-rwxr-xr-xlib/system/debugger.nim426
-rwxr-xr-xlib/system/ecmasys.nim7
-rwxr-xr-xlib/system/excpt.nim12
-rwxr-xr-xlib/system/gc.nim17
-rwxr-xr-xlib/system/mmdisp.nim12
-rwxr-xr-xlib/system/sysio.nim2
-rwxr-xr-xtests/compile/tsortdev.nim59
-rwxr-xr-xtodo.txt2
-rwxr-xr-xweb/news.txt5
23 files changed, 518 insertions, 203 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index a7e79a8ea..ef412d753 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -662,7 +662,7 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
              [rdCharLoc(b), first, intLiteral(lastOrd(ty))])
   if d.k == locNone: d.s = a.s
   putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
-              ropef("$1[($2)-$3]", [rdLoc(a), rdCharLoc(b), first]))
+              ropef("$1[($2)- $3]", [rdLoc(a), rdCharLoc(b), first]))
 
 proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -691,7 +691,7 @@ proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) =
   var ty = skipTypes(a.t, abstractVarRange)
   if ty.kind in {tyRef, tyPtr}:
     ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check:
-  if (optBoundsCheck in p.options):
+  if optBoundsCheck in p.options:
     if ty.kind == tyString:
       appcg(p, cpsStmts,
            "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index e4cc907f8..ad1b5646f 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -615,6 +615,15 @@ proc genBreakPoint(p: BProc, t: PNode) =
         toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)), 
         makeCString(name)])
 
+proc genWatchpoint(p: BProc, n: PNode) =
+  if optEndb notin p.Options: return
+  var a: TLoc
+  initLocExpr(p, n.sons[1], a)
+  let typ = skipTypes(n.sons[1].typ, abstractVarRange)
+  appcg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
+        [a.addrLoc, makeCString(renderTree(n.sons[1])),
+        genTypeInfo(p.module, typ)])
+
 proc genPragma(p: BProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
     var it = n.sons[i]
@@ -628,6 +637,8 @@ proc genPragma(p: BProc, n: PNode) =
         # we need to keep track of ``deadCodeElim`` pragma
         if (sfDeadCodeElim in p.module.module.flags): 
           addPendingModule(p.module)
+    of wWatchpoint:
+      genWatchpoint(p, it)
     else: nil
 
 proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 4c38dcb1a..073d2b594 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -37,7 +37,7 @@ const
     wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
     wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
     wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
-    wBreakpoint, wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
+    wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
     wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
     wLinearScanEnd}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
@@ -59,17 +59,16 @@ const
   allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
 
 proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
-proc pragmaAsm*(c: PContext, n: PNode): char
 # implementation
 
 proc invalidPragma(n: PNode) = 
   LocalError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
 
-proc pragmaAsm(c: PContext, n: PNode): char = 
+proc pragmaAsm*(c: PContext, n: PNode): char = 
   result = '\0'
   if n != nil: 
     for i in countup(0, sonsLen(n) - 1): 
-      var it = n.sons[i]
+      let it = n.sons[i]
       if (it.kind == nkExprColonExpr) and (it.sons[0].kind == nkIdent): 
         case whichKeyword(it.sons[0].ident)
         of wSubsChar: 
@@ -155,13 +154,11 @@ proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
   result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
 
 proc IsTurnedOn(c: PContext, n: PNode): bool = 
-  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): 
-    case whichKeyword(n.sons[1].ident)
-    of wOn: result = true
-    of wOff: result = false
-    else: LocalError(n.info, errOnOrOffExpected)
-  else: 
-    LocalError(n.info, errOnOrOffExpected)
+  if n.kind == nkExprColonExpr:
+    let x = c.semConstBoolExpr(c, n.sons[1])
+    n.sons[1] = x
+    if x.kind == nkIntLit: return x.intVal != 0
+  LocalError(n.info, errOnOrOffExpected)
 
 proc onOff(c: PContext, n: PNode, op: TOptions) = 
   if IsTurnedOn(c, n): gOptions = gOptions + op
@@ -211,28 +208,29 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
   else: 
     incl(sym.loc.flags, lfExportLib)
   
-proc processNote(c: PContext, n: PNode) = 
+proc processNote(c: PContext, n: PNode) =
   if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
       (n.sons[0].kind == nkBracketExpr) and
       (n.sons[0].sons[1].kind == nkIdent) and
-      (n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent): 
+      (n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent):
     var nk: TNoteKind
     case whichKeyword(n.sons[0].sons[0].ident)
-    of wHint: 
+    of wHint:
       var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(hintMin))
       else: invalidPragma(n)
-    of wWarning: 
+    of wWarning:
       var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
       if x >= 0: nk = TNoteKind(x + ord(warnMin))
       else: InvalidPragma(n)
-    else: 
+    else:
       invalidPragma(n)
-      return 
-    case whichKeyword(n.sons[1].ident)
-    of wOn: incl(gNotes, nk)
-    of wOff: excl(gNotes, nk)
-    else: LocalError(n.info, errOnOrOffExpected)
+      return
+
+    let x = c.semConstBoolExpr(c, n.sons[1])
+    n.sons[1] = x
+    if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
+    else: excl(gNotes, nk)
   else: 
     invalidPragma(n)
   
@@ -335,8 +333,8 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
   if found == "": found = f # use the default
   case feature
   of linkNormal: extccomp.addFileToLink(found)
-  of linkSys: 
-    extccomp.addFileToLink(joinPath(libpath, completeCFilePath(found, false)))
+  of linkSys:
+    extccomp.addFileToLink(libpath / completeCFilePath(found, false))
   else: internalError(n.info, "processCommonLink")
   
 proc PragmaBreakpoint(c: PContext, n: PNode) = 
@@ -348,6 +346,12 @@ proc PragmaCheckpoint(c: PContext, n: PNode) =
   inc(info.line)              # next line is affected!
   msgs.addCheckpoint(info)
 
+proc PragmaWatchpoint(c: PContext, n: PNode) =
+  if n.kind == nkExprColonExpr:
+    n.sons[1] = c.semExpr(c, n.sons[1])
+  else:
+    invalidPragma(n)
+
 proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
   case n.sons[1].kind
   of nkStrLit, nkRStrLit, nkTripleStrLit: 
@@ -562,7 +566,7 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
           of wPassL: extccomp.addLinkOption(expectStrLit(c, it))
           of wPassC: extccomp.addCompileOption(expectStrLit(c, it))
           of wBreakpoint: PragmaBreakpoint(c, it)
-          of wCheckpoint: PragmaCheckpoint(c, it)
+          of wWatchpoint: PragmaWatchpoint(c, it)
           of wPush: 
             processPush(c, n, i + 1)
             break 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index d26896b8e..6fb5da2a9 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -322,6 +322,7 @@ proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
   
 proc lsub(n: PNode): int = 
   # computes the length of a tree
+  if isNil(n): return 0
   if n.comment != nil: return maxLineLen + 1
   case n.kind
   of nkEmpty: result = 0
@@ -663,6 +664,7 @@ proc gident(g: var TSrcGen, n: PNode) =
   if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
   
 proc gsub(g: var TSrcGen, n: PNode, c: TContext) = 
+  if isNil(n): return
   var 
     L: int
     a: TContext
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 99eca848b..58a73a3a8 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -160,6 +160,7 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   if (c.p != nil): InternalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExprNoFlags
+  c.semConstBoolExpr = semConstBoolExpr
   pushProcCon(c, module)
   pushOwner(c.module)
   openScope(c.tab)            # scope for imported symbols
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index d5f14616a..f47139e18 100755
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -67,6 +67,7 @@ type
     libs*: TLinkedList         # all libs used by this module
     semConstExpr*: proc (c: PContext, n: PNode): PNode # for the pragmas
     semExpr*: proc (c: PContext, n: PNode): PNode      # for the pragmas
+    semConstBoolExpr*: proc (c: PContext, n: PNode): PNode # XXX bite the bullet
     includedFiles*: TIntSet    # used to detect recursive include files
     filename*: string          # the module's filename
     userPragmas*: TStrTable
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 54625b46e..ce4bd3966 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -17,7 +17,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   # the correct branch. Otherwise the AST will be passed through semStmt.
   result = nil
   
-  template set_result(e: expr) =
+  template setResult(e: expr) =
     if semCheck: result = semStmt(c, e) # do not open a new scope!
     else: result = e
 
@@ -27,17 +27,17 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
     of nkElifBranch: 
       checkSonsLen(it, 2)
       var e = semAndEvalConstExpr(c, it.sons[0])
-      if (e.kind != nkIntLit): InternalError(n.info, "semWhen")
-      if (e.intVal != 0) and (result == nil):
-        set_result(it.sons[1]) 
-    of nkElse: 
+      if e.kind != nkIntLit: InternalError(n.info, "semWhen")
+      if e.intVal != 0 and result == nil:
+        setResult(it.sons[1]) 
+    of nkElse:
       checkSonsLen(it, 1)
       if result == nil: 
-        set_result(it.sons[0])
+        setResult(it.sons[0])
     else: illFormedAst(n)
   if result == nil: 
     result = newNodeI(nkNilLit, n.info) 
-  # The ``when`` statement implements the mechanism for platform dependant
+  # The ``when`` statement implements the mechanism for platform dependent
   # code. Thus we try to ensure here consistent ID allocation after the
   # ``when`` statement.
   IDsynchronizationPoint(200)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ff05586fa..5a1fc004d 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -125,8 +125,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   var a = semConstExpr(c, n[1])
   var b = semConstExpr(c, n[2])
   if not sameType(a.typ, b.typ): GlobalError(n.info, errPureTypeMismatch)
-  if not (a.typ.kind in
-      {tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}): 
+  if a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,tyFloat..tyFloat128}:
     GlobalError(n.info, errOrdinalTypeExpected)
   if enumHasHoles(a.typ): 
     GlobalError(n.info, errEnumXHasHoles, a.typ.sym.name.s)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 489850d93..398c08b8e 100755
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -53,7 +53,7 @@ type
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
     wFieldChecks, 
-    wCheckPoint, wSubsChar, 
+    wWatchPoint, wSubsChar, 
     wAcyclic, wShallow, wUnroll, wLinearScanEnd,
     wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wNoStackFrame
     
@@ -98,7 +98,7 @@ const
     "pragma",
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",
-    "checkpoint",
+    "watchpoint",
     "subschar", "acyclic", "shallow", "unroll", "linearscanend",
     "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
     "nostackframe"]
diff --git a/doc/endb.txt b/doc/endb.txt
index 853af8cad..900553f0e 100755
--- a/doc/endb.txt
+++ b/doc/endb.txt
@@ -8,10 +8,7 @@
 .. contents::

 

 

-**Note:** ENDB has not been maintained/tested since several versions. Help if

-you want this debugger to survive.

-

-Nimrod comes with a platform independant debugger -

+Nimrod comes with a platform independent debugger -

 the `Embedded Nimrod Debugger`:idx: (`ENDB`:idx:). The debugger is

 *embedded* into your executable if it has been

 compiled with the ``--debugger:on`` command line option.

@@ -102,8 +99,8 @@ and again because they are lost when you restart your program. This is not
 necessary: A special pragma has been defined for this:

 

 

-The ``{.breakpoint.}`` pragma

------------------------------

+The ``breakpoint`` pragma

+-------------------------

 

 The `breakpoint`:idx: pragma is syntactically a statement. It can be used

 to mark the *following line* as a breakpoint:

@@ -122,6 +119,32 @@ is turned on, so you don't need to remove it from your source code after
 debugging.

 

 

+The ``watchpoint`` pragma

+-------------------------

+

+The `watchpoint`:idx: pragma is syntactically a statement. It can be used

+to mark a location as a watchpoint:

+

+.. code-block:: Nimrod

+  var a: array [0..20, int]

+  

+  {.watchpoint: a[3].}

+  for i in 0 .. 20: a[i] = i

+

+ENDB then writes a stack trace whenever the content of the location ``a[3]``

+changes. The current implementation only tracks a hash value of the location's

+contents and so locations that are not word sized may encounter false

+negatives in very rare cases.

+

+Code for the ``watchpoint`` pragma is only generated if the debugger

+is turned on, so you don't need to remove it from your source code after

+debugging.

+

+Due to the primitive implementation watchpoints are even slower than

+breakpoints: After *every* executed Nimrod code line it is checked whether the

+location changed.

+

+

 Data Display Commands

 =====================

 

diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 0244c9fce..15b0129ad 100755
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -35,12 +35,14 @@ proc reverse*[T](a: var openArray[T]) =
   reverse(a, 0, a.high)
 
 const
-  onlySafeCode = false
+  onlySafeCode = true
 
 proc merge[T](a, b: var openArray[T], lo, m, hi: int, 
               cmp: proc (x, y: T): int, order: TSortOrder) =
   template `<-` (a, b: expr) = 
-    when onlySafeCode:
+    when true:
+      a = b
+    elif onlySafeCode:
       shallowCopy(a, b)
     else:
       copyMem(addr(a), addr(b), sizeof(T))
diff --git a/lib/system.nim b/lib/system.nim
index 58f4d28f6..d9d3ebd86 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -14,8 +14,6 @@
 ## explicitly. Because of this there cannot be a user-defined module named
 ## ``system``.
 
-{.push hints: off.}
-
 type
   int* {.magic: Int.} ## default integer type; bitwidth depends on
                       ## architecture, but is always the same as a pointer
@@ -35,9 +33,15 @@ type
   string* {.magic: String.} ## built-in string type
   cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
   pointer* {.magic: Pointer.} ## built-in pointer type
-  Ordinal* {.magic: Ordinal.}[T]
+
+const
+  on* = true    ## alias for ``true``
+  off* = false  ## alias for ``false``
+
+{.push hints: off.}
 
 type
+  Ordinal* {.magic: Ordinal.}[T]
   `nil` {.magic: "Nil".}
   expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
   stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
@@ -831,10 +835,16 @@ proc quit*(errorcode: int = QuitSuccess) {.
   ## It does *not* call the garbage collector to free all the memory,
   ## unless a quit procedure calls ``GC_collect``.
 
+proc WriteStackTrace()
+
+var checkDisabled: bool
+
 template sysAssert(cond, msg: expr) =
   when defined(useSysAssert):
-    if not cond:
+    if not checkDisabled and not cond:
+      checkDisabled = true
       echo "[SYSASSERT] ", msg
+      WriteStackTrace()
       quit 1
   nil
 
@@ -1124,8 +1134,10 @@ proc `$` *[T](x: ordinal[T]): string {.magic: "EnumToStr", noSideEffect.}
 
 # undocumented:
 proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
+proc getRefcount*(x: string): int {.importc: "getRefcount", noSideEffect.}
+proc getRefcount*[T](x: seq[T]): int {.importc: "getRefcount", noSideEffect.}
   ## retrieves the reference count of an heap-allocated object. The
-  ## value is implementation-dependant.
+  ## value is implementation-dependent.
 
 # new constants:
 const
@@ -1459,7 +1471,7 @@ template accumulateResult*(iter: expr) =
 # we have to compute this here before turning it off in except.nim anyway ...
 const nimrodStackTrace = compileOption("stacktrace")
 
-{.push checks: off, debugger: off.}
+{.push checks: off.}
 # obviously we cannot generate checking operations here :-)
 # because it would yield into an endless recursion
 # however, stack-traces are available for most parts
@@ -1516,8 +1528,8 @@ type
     len: int  # length of slots (when not debugging always zero)
 
 when not defined(ECMAScript):
-  {.push stack_trace:off}
-  proc add*(x: var string, y: cstring) =
+  {.push stack_trace:off.}
+  proc add*(x: var string, y: cstring) {.noStackFrame.} =
     var i = 0
     while y[i] != '\0':
       add(x, y[i])
@@ -1600,7 +1612,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   when defined(endb):
     proc endbStep()
 
-  # ----------------- IO Part --------------------------------------------------
+  # ----------------- IO Part ------------------------------------------------
 
   type
     CFile {.importc: "FILE", nodecl, final.} = object  # empty record for
@@ -1783,6 +1795,8 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     while a[L] != nil: inc(L)
     result = cstringArrayToSeq(a, L)
 
+  # -------------------------------------------------------------------------
+
   proc allocCStringArray*(a: openArray[string]): cstringArray =
     ## creates a NULL terminated cstringArray from `a`. The result has to
     ## be freed with `deallocCStringArray` after it's not needed anymore.
@@ -1801,8 +1815,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
       inc(i)
     dealloc(a)
 
-  # ----------------------------------------------------------------------------
-
   proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.}
     ## atomic increment of `memLoc`. Returns the value after the operation.
   
@@ -1827,11 +1839,13 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     initStackBottom()
     initGC()
     
+  {.push stack_trace: off.}
   include "system/excpt"
   # we cannot compile this with stack tracing on
   # as it would recurse endlessly!
   include "system/arithm"
   {.pop.} # stack trace
+  {.pop.} # stack trace
       
   include "system/dyncalls"
   include "system/sets"
@@ -1861,8 +1875,8 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     else:
       result = n.sons[n.len]
 
-  {.push stack_trace: off.}
   include "system/mmdisp"
+  {.push stack_trace: off.}
   include "system/sysstr"
   {.pop.}
 
@@ -2127,3 +2141,7 @@ template doAssert*(cond: expr, msg = "") =
     {.line: InstantiationInfo().}:
       raiseAssert(astToStr(cond) & ' ' & msg)
 
+
+when defined(initDebugger):
+  initDebugger()
+
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 95fe2542d..a5a3c0e03 100755
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -499,6 +499,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
   sysAssert(roundup(65, 8) == 72, "rawAlloc 1")
   sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2"
   var size = roundup(requestedSize, MemAlign)
+  sysAssert(size >= requestedSize, "insufficient allocated size!")
   #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
@@ -561,6 +562,7 @@ proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
   zeroMem(result, requestedSize)
 
 proc rawDealloc(a: var TMemRegion, p: pointer) =
+  #sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
   sysAssert(allocInv(a), "rawDealloc: begin")
   var c = pageAddr(p)
   if isSmallChunk(c):
diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim
index 4d997d0f9..b860ef38c 100755
--- a/lib/system/cellsets.nim
+++ b/lib/system/cellsets.nim
@@ -13,7 +13,7 @@ type
   TCell {.pure.} = object
     refcount: int  # the refcount and some flags
     typ: PNimType
-    when debugGC:
+    when leakDetector:
       filename: cstring
       line: int
 
diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim
index 3279e18f2..49a2da89f 100755
--- a/lib/system/debugger.nim
+++ b/lib/system/debugger.nim
@@ -8,15 +8,18 @@
 #
 
 # This file implements the embedded debugger that can be linked
-# with the application. We should not use dynamic memory here as that
+# with the application. Mostly we do 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...
+# I do not want to implement ``repr()`` twice.
 
 type
+  TStaticStr {.pure, final.} = object
+    len: int
+    data: array[0..100, char]
+
   TDbgState = enum
     dbOff,        # debugger is turned off
     dbStepInto,   # debugger is in tracing mode
@@ -29,8 +32,8 @@ type
     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
+    filename: cstring
+    name: TStaticStr     # name of breakpoint
 
   TVarSlot {.compilerproc, final.} = object # variable slots used for debugger:
     address: pointer
@@ -47,12 +50,10 @@ type
     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``
+  dbgUser: TStaticStr   # 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
+  dbgState: TDbgState   # state of debugger
   dbgBP: array[0..127, TDbgBreakpoint] # breakpoints
   dbgBPlen: int = 0
 
@@ -63,7 +64,36 @@ var
 
   maxDisplayRecDepth: int = 5 # do not display too much data!
 
-proc findBreakpoint(name: string): int =
+proc setLen(s: var TStaticStr, newLen=0) =
+  s.len = newLen
+  s.data[newLen] = '\0'
+
+proc add(s: var TStaticStr, c: char) =
+  if s.len < high(s.data)-1:
+    s.data[s.len] = c
+    s.data[s.len+1] = '\0'
+    inc s.len
+
+proc add(s: var TStaticStr, c: cstring) =
+  var i = 0
+  while c[i] != '\0':
+    add s, c[i]
+    inc i
+
+proc assign(s: var TStaticStr, c: cstring) =
+  setLen(s)
+  add s, c
+
+proc `==`(a, b: TStaticStr): bool =
+  if a.len == b.len:
+    for i in 0 .. a.len-1:
+      if a.data[i] != b.data[i]: return false
+    return true
+
+proc `==`(a: TStaticStr, b: cstring): bool =
+  result = c_strcmp(a.data, b) == 0
+
+proc findBreakpoint(name: TStaticStr): int =
   # returns -1 if not found
   for i in countdown(dbgBPlen-1, 0):
     if name == dbgBP[i].name: return i
@@ -72,16 +102,22 @@ proc findBreakpoint(name: string): int =
 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)
+    write(stdout, dbgBP[i].name.data)
+    write(stdout, ": ")
+    write(stdout, abs(dbgBP[i].low))
+    write(stdout, "..")
+    write(stdout, abs(dbgBP[i].high))
+    write(stdout, 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):
+proc openAppend(filename: cstring): TFile =
+  var p: pointer = fopen(filename, "ab")
+  if p != nil:
+    result = cast[TFile](p)
     write(result, "----------------------------------------\n")
 
 proc dbgRepr(p: pointer, typ: PNimType): string =
@@ -101,13 +137,17 @@ proc writeVariable(stream: TFile, slot: TVarSlot) =
   writeln(stream, dbgRepr(slot.address, slot.typ))
 
 proc ListFrame(stream: TFile, f: PExtendedFrame) =
-  write(stream, "*** endb| Frame (" & $f.f.len &  " slots):\n")
+  write(stream, "*** endb| Frame (")
+  write(stream, f.f.len)
+  write(stream, " 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")
+  write(stream, "*** endb| Frame (")
+  write(stream, f.f.len)
+  write(stream, " slots):\n")
   for i in 0 .. f.f.len-1:
     writeln(stream, f.slots[i].name)
   write(stream, "***\n")
@@ -135,14 +175,19 @@ proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
     write(stdout, dbgFramePointer.procname)
     write(stdout, " ***\n")
   else:
-    write(stdout, "*** endb| (procedure name not available) ***\n")
+    write(stdout, "*** endb| (proc name not available) ***\n")
 
 proc dbgShowExecutionPoint() =
-  write(stdout, "*** endb| " & $framePtr.filename & 
-                "(" & $framePtr.line & ") " & $framePtr.procname & " ***\n")
+  write(stdout, "*** endb| ")
+  write(stdout, framePtr.filename)
+  write(stdout, "(")
+  write(stdout, framePtr.line)
+  write(stdout, ") ")
+  write(stdout, framePtr.procname)
+  write(stdout, " ***\n")
 
-when defined(windows) or defined(dos) or defined(os2):
-  {.define: FileSystemCaseInsensitive.}
+const
+  FileSystemCaseInsensitive = defined(windows) or defined(dos) or defined(os2)
 
 proc fileMatches(c, bp: cstring): bool =
   # bp = breakpoint filename
@@ -162,7 +207,7 @@ proc fileMatches(c, bp: cstring): bool =
     var x, y: char
     x = bp[i]
     y = c[i+clen-blen]
-    when defined(FileSystemCaseInsensitive):
+    when 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
@@ -175,7 +220,7 @@ proc dbgBreakpointReached(line: int): int =
         fileMatches(framePtr.filename, dbgBP[i].filename): return i
   return -1
 
-proc scanAndAppendWord(src: string, a: var string, start: int): int =
+proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
   result = start
   # skip whitespace:
   while src[result] in {'\t', ' '}: inc(result)
@@ -187,20 +232,20 @@ proc scanAndAppendWord(src: string, a: var string, start: int): int =
     else: break
     inc(result)
 
-proc scanWord(src: string, a: var string, start: int): int =
-  a = ""
+proc scanWord(src: cstring, a: var TStaticStr, start: int): int =
+  setlen(a)
   result = scanAndAppendWord(src, a, start)
 
-proc scanFilename(src: string, a: var string, start: int): int =
+proc scanFilename(src: cstring, a: var TStaticStr, start: int): int =
   result = start
-  a = ""
+  setLen 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 =
+proc scanNumber(src: cstring, a: var int, start: int): int =
   result = start
   a = 0
   while src[result] in {'\t', ' '}: inc(result)
@@ -222,7 +267,7 @@ q, quit                 quit the debugger and the program
 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
+c, continue, r, run     continue execution until the next breakpoint
 i, ignore               continue execution, ignore all breakpoints
               BREAKPOINTS
 b, break <name> [fromline [toline]] [file]
@@ -247,14 +292,15 @@ maxdisplay <integer>    set the display's recursion maximum
 proc InvalidCommand() =
   debugOut("[Warning] invalid command ignored (type 'h' for help) ")
 
-proc hasExt(s: string): bool =
+proc hasExt(s: cstring): bool =
   # returns true if s has a filename extension
-  for i in countdown(len(s)-1, 0):
+  var i = 0
+  while s[i] != '\0':
     if s[i] == '.': return true
-  return false
+    inc i
 
-proc setBreakPoint(s: string, start: int) =
-  var dbgTemp: string
+proc setBreakPoint(s: cstring, start: int) =
+  var dbgTemp: TStaticStr
   var i = scanWord(s, dbgTemp, start)
   if i <= start:
     InvalidCommand()
@@ -273,19 +319,22 @@ proc setBreakPoint(s: string, start: int) =
   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
+  if dbgTemp.len != 0:
+    debugOut("[Warning] explicit filename for breakpoint not supported")
+    when false:
+      if not hasExt(dbgTemp.data): add(dbgTemp, ".nim")
+      dbgBP[x].filename = dbgTemp
+    dbgBP[x].filename = framePtr.filename
   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':
     dec(dbgBPLen) # remove buggy breakpoint
     InvalidCommand()
 
-proc BreakpointSetEnabled(s: string, start, enabled: int) =
-  var dbgTemp: string
+proc BreakpointSetEnabled(s: cstring, start, enabled: int) =
+  var dbgTemp: TStaticStr
   var i = scanWord(s, dbgTemp, start)
   if i <= start:
     InvalidCommand()
@@ -296,9 +345,9 @@ proc BreakpointSetEnabled(s: string, start, enabled: int) =
     dbgBP[x].low = -dbgBP[x].low
     dbgBP[x].high = -dbgBP[x].high
 
-proc dbgEvaluate(stream: TFile, s: string, start: int,
+proc dbgEvaluate(stream: TFile, s: cstring, start: int,
                  currFrame: PExtendedFrame) =
-  var dbgTemp: string
+  var dbgTemp: tstaticstr
   var i = scanWord(s, dbgTemp, start)
   while s[i] in {' ', '\t'}: inc(i)
   var f = currFrame
@@ -311,92 +360,108 @@ proc dbgEvaluate(stream: TFile, s: string, start: int,
   if s[i] != '\0':
     debugOut("[Warning] could not parse expr ")
     return
-  var j = findVariable(f, dbgTemp)
+  var j = findVariable(f, dbgTemp.data)
   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
+proc dbgOut(s: cstring, start: int, currFrame: PExtendedFrame) =
+  var dbgTemp: tstaticstr
   var i = scanFilename(s, dbgTemp, start)
   if dbgTemp.len == 0:
     InvalidCommand()
     return
-  var stream = openAppend(dbgTemp)
+  var stream = openAppend(dbgTemp.data)
   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
+proc dbgStackFrame(s: cstring, start: int, currFrame: PExtendedFrame) =
+  var dbgTemp: TStaticStr
   var i = scanFilename(s, dbgTemp, start)
   if dbgTemp.len == 0:
     # just write it to stdout:
     ListFrame(stdout, currFrame)
   else:
-    var stream = openAppend(dbgTemp)
+    var stream = openAppend(dbgTemp.data)
     if stream == nil:
       debugOut("[Warning] could not open or create file ")
       return
     ListFrame(stream, currFrame)
     close(stream)
 
+proc readLine(f: TFile, line: var TStaticStr): bool =
+  while True:
+    var c = fgetc(f)
+    if c < 0'i32:
+      if line.len > 0: break
+      else: return false
+    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 line, chr(int(c))
+  result = true
+
+proc dbgWriteStackTrace(f: PFrame)
 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
+    dbgTemp: TStaticStr
 
   while again:
     write(stdout, "*** endb| >>")
-    var tmp = readLine(stdin)
-    if tmp.len > 0: dbgUser = tmp
+    let oldLen = dbgUser.len
+    dbgUser.len = 0
+    if not readLine(stdin, dbgUser): break
+    if dbgUser.len == 0: dbgUser.len = oldLen
     # now look what we have to do:
-    var dbgTemp: string
-    var i = scanWord(dbgUser, dbgTemp, 0)
-    case dbgTemp
-    of "": InvalidCommand()
-    of "s", "step":
+    var i = scanWord(dbgUser.data, dbgTemp, 0)
+    template `?`(x: expr): expr = dbgTemp == cstring(x)
+    if ?"s" or ?"step":
       dbgState = dbStepInto
       again = false
-    of "n", "next":
+    elif ?"n" or ?"next":
       dbgState = dbStepOver
       dbgSkipToFrame = framePtr
       again = false
-    of "f", "skipcurrent":
+    elif ?"f" or ?"skipcurrent":
       dbgState = dbSkipCurrent
       dbgSkipToFrame = framePtr.prev
       again = false
-    of "c", "continue":
+    elif ?"c" or ?"continue" or ?"r" or ?"run":
       dbgState = dbBreakpoints
       again = false
-    of "i", "ignore":
+    elif ?"i" or ?"ignore":
       dbgState = dbOff
       again = false
-    of "h", "help":
+    elif ?"h" or ?"help":
       dbgHelp()
-    of "q", "quit":
+    elif ?"q" or ?"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":
+    elif ?"e" or ?"eval":
+      dbgEvaluate(stdout, dbgUser.data, i, cast[PExtendedFrame](dbgFramePtr))
+    elif ?"o" or ?"out":
+      dbgOut(dbgUser.data, i, cast[PExtendedFrame](dbgFramePtr))
+    elif ?"stackframe":
+      dbgStackFrame(dbgUser.data, i, cast[PExtendedFrame](dbgFramePtr))
+    elif ?"w" or ?"where":
       dbgShowExecutionPoint()
-    of "l", "locals":
+    elif ?"l" or ?"locals":
       ListVariables(stdout, cast[PExtendedFrame](dbgFramePtr))
-    of "g", "globals":
+    elif ?"g" or ?"globals":
       ListVariables(stdout, addr(dbgGlobalData))
-    of "u", "up":
+    elif ?"u" or ?"up":
       if dbgDown <= 0:
         debugOut("[Warning] cannot go up any further ")
       else:
@@ -405,33 +470,32 @@ proc CommandPrompt() =
           dbgFramePtr = dbgFramePtr.prev
         dec(dbgDown)
       dbgShowCurrentProc(dbgFramePtr)
-    of "d", "down":
+    elif ?"d" or ?"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":
+    elif ?"bt" or ?"backtrace":
+      dbgWriteStackTrace(framePtr)
+    elif ?"b" or ?"break":
+      setBreakPoint(dbgUser.data, i)
+    elif ?"breakpoints":
       ListBreakPoints()
-    of "disable":
-      BreakpointSetEnabled(dbgUser, i, -1)
-    of "enable":
-      BreakpointSetEnabled(dbgUser, i, +1)
-    of "maxdisplay":
+    elif ?"disable":
+      BreakpointSetEnabled(dbgUser.data, i, -1)
+    elif ?"enable":
+      BreakpointSetEnabled(dbgUser.data, i, +1)
+    elif ?"maxdisplay":
       var parsed: int
-      i = scanNumber(dbgUser, parsed, i)
-      if dbgUser[i-1] in {'0'..'9'}:
+      i = scanNumber(dbgUser.data, parsed, i)
+      if dbgUser.data[i-1] in {'0'..'9'}:
         if parsed == 0: maxDisplayRecDepth = -1
         else: maxDisplayRecDepth = parsed
       else:
         InvalidCommand()
-    else:
-      InvalidCommand()
+    else: InvalidCommand()
 
 proc endbStep() =
   # we get into here if an unhandled exception has been raised
@@ -441,10 +505,10 @@ proc endbStep() =
   CommandPrompt()
 
 proc checkForBreakpoint() =
-  var i = dbgBreakpointReached(framePtr.line)
+  let i = dbgBreakpointReached(framePtr.line)
   if i >= 0:
     write(stdout, "*** endb| reached ")
-    write(stdout, dbgBP[i].name)
+    write(stdout, dbgBP[i].name.data)
     write(stdout, " in ")
     write(stdout, framePtr.filename)
     write(stdout, "(")
@@ -458,16 +522,19 @@ proc checkForBreakpoint() =
 
 proc dbgRegisterBreakpoint(line: int,
                            filename, name: cstring) {.compilerproc.} =
-  var x = dbgBPlen
+  let x = dbgBPlen
+  if x >= high(dbgBP):
+    debugOut("[Warning] cannot register breakpoint")
+    return
   inc(dbgBPlen)
-  dbgBP[x].name = $name
-  dbgBP[x].filename = $filename
+  dbgBP[x].name.assign(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
+  let i = dbgGlobalData.f.len
   if i >= high(dbgGlobalData.slots):
     debugOut("[Warning] cannot register global ")
     return
@@ -476,14 +543,179 @@ proc dbgRegisterGlobal(name: cstring, address: pointer,
   dbgGlobalData.slots[i].address = address
   inc(dbgGlobalData.f.len)
 
+type
+  THash = int
+  TWatchpoint {.pure, final.} = object
+    name: cstring
+    address: pointer
+    typ: PNimType
+    oldValue: THash
+
+var
+  Watchpoints: array [0..99, TWatchpoint]
+  WatchpointsLen: int
+
+proc `!&`(h: THash, val: int): THash {.inline.} =
+  result = h +% val
+  result = result +% result shl 10
+  result = result xor (result shr 6)
+
+proc `!$`(h: THash): THash {.inline.} =
+  result = h +% h shl 3
+  result = result xor (result shr 11)
+  result = result +% result shl 15
+
+proc hash(Data: Pointer, Size: int): THash =
+  var h: THash = 0
+  var p = cast[cstring](Data)
+  var i = 0
+  var s = size
+  while s > 0:
+    h = h !& ord(p[i])
+    Inc(i)
+    Dec(s)
+  result = !$h
+
+proc genericHashAux(dest: Pointer, mt: PNimType, shallow: bool,
+                    h: THash): THash
+proc genericHashAux(dest: Pointer, n: ptr TNimNode, shallow: bool,
+                    h: THash): THash =
+  var d = cast[TAddress](dest)
+  case n.kind
+  of nkSlot:
+    result = genericHashAux(cast[pointer](d +% n.offset), n.typ, shallow, h)
+  of nkList:
+    result = h
+    for i in 0..n.len-1: 
+      result = result !& genericHashAux(dest, n.sons[i], shallow, result)
+  of nkCase:
+    result = h !& hash(cast[pointer](d +% n.offset), n.typ.size)
+    var m = selectBranch(dest, n)
+    if m != nil: result = genericHashAux(dest, m, shallow, result)
+  of nkNone: sysAssert(false, "genericHashAux")
+
+proc genericHashAux(dest: Pointer, mt: PNimType, shallow: bool, 
+                    h: THash): THash =
+  sysAssert(mt != nil, "genericHashAux 2")
+  case mt.Kind
+  of tyString:
+    var x = cast[ppointer](dest)[]
+    result = h
+    if x != nil:
+      let s = cast[NimString](x)
+      let y = cast[pointer](cast[int](x) -% 2*sizeof(int))
+      result = result !& hash(x, s.len + 2*sizeof(int))
+  of tySequence:
+    var x = cast[ppointer](dest)
+    var dst = cast[taddress](cast[ppointer](dest)[])
+    result = h
+    if dst != 0:
+      for i in 0..cast[pgenericseq](dst).len-1:
+        result = result !& genericHashAux(
+          cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+          mt.Base, shallow, result)
+  of tyObject, tyTuple:
+    # we don't need to copy m_type field for tyObject, as they are equal anyway
+    result = genericHashAux(dest, mt.node, shallow, h)
+  of tyArray, tyArrayConstr:
+    let d = cast[TAddress](dest)
+    result = h
+    for i in 0..(mt.size div mt.base.size)-1:
+      result = result !& genericHashAux(cast[pointer](d +% i*% mt.base.size),
+                                        mt.base, shallow, result)
+  of tyRef:
+    if shallow:
+      result = h !& hash(dest, mt.size)
+    else:
+      var s = cast[ppointer](dest)[]
+      if s != nil: result = genericHashAux(s, mt.base, shallow, h)
+  else:
+    result = h !& hash(dest, mt.size) # hash raw bits
+
+proc genericHash(dest: Pointer, mt: PNimType): int =
+  result = genericHashAux(dest, mt, false, 0)
+  
+proc dbgRegisterWatchpoint(address: pointer, name: cstring,
+                           typ: PNimType) {.compilerproc.} =
+  let L = WatchpointsLen
+  for i in 0.. <L:
+    if Watchpoints[i].name == name:
+      # address may have changed:
+      Watchpoints[i].address = address
+      return
+  if L >= watchPoints.high:
+    debugOut("[Warning] cannot register watchpoint")
+    return
+  Watchpoints[L].name = name
+  Watchpoints[L].address = address
+  Watchpoints[L].typ = typ
+  Watchpoints[L].oldValue = genericHash(address, typ)
+  inc WatchpointsLen
+
+proc dbgWriteStackTrace(f: PFrame) =
+  const
+    firstCalls = 32
+  var
+    it = f
+    i = 0
+    total = 0
+    tempFrames: array [0..127, PFrame]
+  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: 
+      write(stdout, "(")
+      write(stdout, (total-i-1))
+      write(stdout, " calls omitted) ...")
+    else:
+      write(stdout, tempFrames[j].filename)
+      if tempFrames[j].line > 0:
+        write(stdout, '(')
+        write(stdout, tempFrames[j].line)
+        write(stdout, ')')
+      write(stdout, ' ')
+      write(stdout, tempFrames[j].procname)
+    write(stdout, "\n")
+  
+proc checkWatchpoints =
+  let L = WatchpointsLen
+  for i in 0.. <L:
+    let newHash = genericHash(Watchpoints[i].address, Watchpoints[i].typ)
+    if newHash != Watchpoints[i].oldValue:
+      dbgWriteStackTrace(framePtr)
+      debugOut(Watchpoints[i].name)
+      Watchpoints[i].oldValue = newHash
+      
 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"
+  if framePtr == nil: return
+  let oldState = dbgState
+  #dbgState = dbOff
+  #if oldState != dbOff: 
+  checkWatchpoints()
   framePtr.line = line # this is done here for smaller code size!
   if dbgLineHook != nil: dbgLineHook()
-  case dbgState
+  case oldState
   of dbStepInto:
     # we really want the command prompt here:
     dbgShowExecutionPoint()
@@ -497,3 +729,9 @@ proc endb(line: int) {.compilerproc.} =
   of dbBreakpoints: # debugger is only interested in breakpoints
     checkForBreakpoint()
   else: nil
+
+proc initDebugger {.inline.} =
+  dbgState = dbStepInto
+  dbgUser.len = 1
+  dbgUser.data[0] = 's'
+
diff --git a/lib/system/ecmasys.nim b/lib/system/ecmasys.nim
index 7bec2b5bf..c8fedc85d 100755
--- a/lib/system/ecmasys.nim
+++ b/lib/system/ecmasys.nim
@@ -391,13 +391,6 @@ proc modInt64(a, b: int): int {.noStackFrame, compilerproc.} =
 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) {.noStackFrame, compilerproc.} =
-  var
-    e: ref EAssertionFailed
-  new(e)
-  asm """`e`.message = "[Assertion failure] file: "+`file`+", line: "+`line`"""
-  raise e
-
 include "system/hti"
 
 proc isFatPointer(ti: PNimType): bool =
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 4f7584d30..e7dc88af2 100755
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -238,18 +238,6 @@ proc reraiseException() {.compilerRtl.} =
   else:
     raiseException(currException, currException.name)
 
-proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
-  if not cond:
-    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() =
   when hasSomeStackTrace:
     var s = ""
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 1aae16f1a..57ee11f8b 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -111,7 +111,7 @@ when debugGC:
   proc writeCell(msg: CString, c: PCell) =
     var kind = -1
     if c.typ != nil: kind = ord(c.typ.kind)
-    when debugGC:
+    when leakDetector:
       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:
@@ -277,6 +277,10 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
     # the test for '!= nil' is correct, but I got tired of the segfaults
     # resulting from the crappy stack checking:
     if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
+  else:
+    # can't be an interior pointer if it's a stack location!
+    sysAssert(interiorAllocatedPtr(gch.region, dest)==nil, 
+              "stack loc AND interior pointer")
   dest[] = src
 
 proc initGC() =
@@ -400,7 +404,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
   sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   # now it is buffered in the ZCT
   res.typ = typ
-  when debugGC and not hasThreadSupport:
+  when leakDetector and not hasThreadSupport:
     if framePtr != nil and framePtr.prev != nil:
       res.filename = framePtr.prev.filename
       res.line = framePtr.prev.line
@@ -437,7 +441,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   # now it is buffered in the ZCT
   res.typ = typ
-  when debugGC and not hasThreadSupport:
+  when leakDetector and not hasThreadSupport:
     if framePtr != nil and framePtr.prev != nil:
       res.filename = framePtr.prev.filename
       res.line = framePtr.prev.line
@@ -510,6 +514,9 @@ proc doOperation(p: pointer, op: TWalkOp) =
   sysAssert(c != nil, "doOperation: 1")
   case op # faster than function pointers because of easy prediction
   of waZctDecRef:
+    #if not isAllocatedPtr(gch.region, c):
+    #  return
+    #  c_fprintf(c_stdout, "[GC] decref bug: %p", c) 
     sysAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef")
     sysAssert(c.refcount >=% rcIncrement, "doOperation 2")
     c.refcount = c.refcount -% rcIncrement
@@ -776,7 +783,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
 
 proc collectCT(gch: var TGcHeap) =
   if (gch.zct.len >= ZctThreshold or (cycleGC and
-      getOccupiedMem(gch.region) >= gch.cycleThreshold) or stressGC) and 
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and 
       gch.recGcLock == 0:
     sysAssert(allocInv(gch.region), "collectCT: begin")
     
@@ -789,7 +796,7 @@ proc collectCT(gch: var TGcHeap) =
     inc(gch.stat.stackScans)
     collectZCT(gch)
     when cycleGC:
-      if getOccupiedMem(gch.region) >= gch.cycleThreshold or stressGC:
+      if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
         collectCycles(gch)
         collectZCT(gch)
         inc(gch.stat.cycleCollections)
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index dc4caee48..1561e1b27 100755
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -17,13 +17,16 @@ 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
+  alwaysCycleGC = false
+  alwaysGC = false # collect after every memory allocation (for debugging)
+  leakDetector = false
+  overwriteFree = false
+  
   cycleGC = true # (de)activate the cycle GC
-  stressGC = false
+  reallyDealloc = true # for debugging purposes this can be set to false
   reallyOsDealloc = true
   coalescRight = true
   coalescLeft = true
-  overwriteFree = false
 
 type
   PPointer = ptr pointer
@@ -229,7 +232,8 @@ else:
   include "system/alloc"
 
   include "system/cellsets"
-  sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
+  when not leakDetector:
+    sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
   include "system/gc"
   
 {.pop.}
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 33f16b834..33d7dc5f2 100755
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -125,7 +125,7 @@ proc readAll(file: TFile): TaintedString =
   # don't know the overall length of the TFile.
   var len = rawFileSize(file)
   if len >= 0:
-    result = readAllFile(file, len).TaintedSTring
+    result = readAllFile(file, len).TaintedString
   else:
     result = readAllBuffer(file).TaintedString
   
diff --git a/tests/compile/tsortdev.nim b/tests/compile/tsortdev.nim
index ecfab260d..0af0fe0f4 100755
--- a/tests/compile/tsortdev.nim
+++ b/tests/compile/tsortdev.nim
@@ -25,40 +25,55 @@ proc bubbleSort[T](a: var openArray[T],
 when isMainModule:
   proc main() =
     const order = Ascending
-    var data: seq[string]
-
-    for i in 0..10_000: 
-      var L = random(59)
-      newSeq(data, L)
+    var data: seq[string] = @[]
+    
+    var L = random(59)
+    for i in 0..1: 
+      echo "loop: ", i
+      #newSeq(data, L)
+      setLen(data, L)
       for j in 0 .. L-1:
         data[j] = $(math.random(90) - 10)
+        assert getRefcount(data[j]) == 1
+        {.watchpoint: data.}
       var copy = data
+      for j in 0 .. L-1:
+        assert getRefcount(copy[j]) == 1
+        assert(cast[pointer](copy[j]) != cast[pointer](data[i]))
+      
       bubblesort(data, system.cmp, order)
       if not sorted(data, order):
         quit "bubblesort failed"
-      sort(copy, cmp, order)
-      if copy.len != data.len: 
-        quit "lengths differ!"
-      for i in 0 .. copy.high:
-        if copy[i] != data[i]:
-          quit "algorithms differ!"
 
-    for i in 0..10_000:
-      var data: seq[int]
-      var L = random(59)
-      newSeq(data, L)
-      for j in 0 .. L-1: 
-        data[j] = (math.random(90) - 10)
-      var copy = data
-      sort(data, cmp[int], order)
-      if not sorted(data, order):
-        quit "sort for seq[int] failed"
-      bubblesort(copy, system.cmp[int], order)
+      sort(copy, cmp, order)
+      for j in 0 .. L-1:
+        let rc = getRefcount(data[j])
+        if rc != 1:
+          echo "RC IST ", rc, " j: ", j
+          assert getRefcount(data[j]) == 1
+    when false:
       if copy.len != data.len: 
         quit "lengths differ!"
       for i in 0 .. copy.high:
         if copy[i] != data[i]:
           quit "algorithms differ!"
+    when false:
+      for i in 0..10_000:
+        var data: seq[int]
+        var L = random(59)
+        newSeq(data, L)
+        for j in 0 .. L-1: 
+          data[j] = (math.random(90) - 10)
+        var copy = data
+        sort(data, cmp[int], order)
+        if not sorted(data, order):
+          quit "sort for seq[int] failed"
+        bubblesort(copy, system.cmp[int], order)
+        if copy.len != data.len: 
+          quit "lengths differ!"
+        for i in 0 .. copy.high:
+          if copy[i] != data[i]:
+            quit "algorithms differ!"
 
   main()
 
diff --git a/todo.txt b/todo.txt
index 61d5b5c0c..dc9f9c159 100755
--- a/todo.txt
+++ b/todo.txt
@@ -2,6 +2,8 @@ version 0.8.14
 ==============
 
 - bug: tsortdev does not run with native GC
+- object {.pure, final.} does not work again!
+
 
 version 0.9.0
 =============
diff --git a/web/news.txt b/web/news.txt
index 3ab7ac751..5181baadf 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -119,6 +119,11 @@ Compiler Additions
   for specifying modules that will be automatically imported/incluced.
 - ``nimrod i`` can now optionally be given a module to execute.
 - The compiler now performs a simple alias analysis to generate better code.
+- The compiler and ENDB now support *watchpoints*.
+- The compiler now supports proper compile time expressions of type ``bool``
+  for ``on|off`` switches in pragmas. In order to not break existing code,
+  ``on`` and ``off`` are now aliases for ``true`` and ``false`` and declared
+  in the system module.
 
 
 Library Additions