summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-07-13 04:48:22 +0200
committerAndreas Rumpf <rumpf_a@web.de>2017-07-13 04:48:22 +0200
commit2b862b74e0b0b7b4a18f4262356289fb921eaf0c (patch)
tree8f41b7355f6d791d6485e8225d6a5cb2f80ca7d6 /lib
parenta5695c13afabac6e67ff677d564b6d1a6aeb1af4 (diff)
parent0c271f54208c7ba0bac6ad2da87f60e7c6d8e37c (diff)
downloadNim-2b862b74e0b0b7b4a18f4262356289fb921eaf0c.tar.gz
Merge branch 'devel' into araq
Diffstat (limited to 'lib')
-rw-r--r--lib/core/macros.nim107
-rw-r--r--lib/posix/posix.nim8
-rw-r--r--lib/posix/posix_linux_amd64.nim3
-rw-r--r--lib/posix/posix_linux_amd64_consts.nim3
-rw-r--r--lib/posix/posix_other_consts.nim4
-rw-r--r--lib/pure/asyncdispatch.nim4
-rw-r--r--lib/pure/asynchttpserver.nim2
-rw-r--r--lib/pure/asyncmacro.nim41
-rw-r--r--lib/pure/asyncnet.nim6
-rw-r--r--lib/pure/collections/tables.nim7
-rw-r--r--lib/pure/concurrency/cpuinfo.nim2
-rw-r--r--lib/pure/distros.nim2
-rw-r--r--lib/pure/hashes.nim11
-rw-r--r--lib/pure/httpclient.nim3
-rw-r--r--lib/pure/includes/asynccommon.nim2
-rw-r--r--lib/pure/json.nim23
-rw-r--r--lib/pure/math.nim36
-rw-r--r--lib/pure/os.nim46
-rw-r--r--lib/pure/ospaths.nim9
-rw-r--r--lib/pure/osproc.nim5
-rw-r--r--lib/pure/parsecfg.nim4
-rw-r--r--lib/pure/parseopt.nim45
-rw-r--r--lib/pure/parseopt2.nim45
-rw-r--r--lib/pure/pegs.nim2
-rw-r--r--lib/pure/random.nim3
-rw-r--r--lib/pure/streams.nim4
-rw-r--r--lib/pure/strutils.nim4
-rw-r--r--lib/pure/times.nim100
-rw-r--r--lib/system.nim165
-rw-r--r--lib/system/alloc.nim1
-rw-r--r--lib/system/excpt.nim26
-rw-r--r--lib/system/gc_common.nim7
-rw-r--r--lib/system/gc_ms.nim55
-rw-r--r--lib/system/gc_stack.nim2
-rw-r--r--lib/system/jssys.nim2
-rw-r--r--lib/system/mmdisp.nim11
-rw-r--r--lib/system/repr.nim4
-rw-r--r--lib/system/reprjs.nim4
-rw-r--r--lib/system/syslocks.nim12
-rw-r--r--lib/system/threads.nim12
-rw-r--r--lib/windows/winlean.nim14
-rw-r--r--lib/wrappers/openssl.nim2
42 files changed, 622 insertions, 226 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 83776f16b..af1e9de28 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -225,7 +225,13 @@ proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
 proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
 
 proc newNimNode*(kind: NimNodeKind,
-                 n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.}
+                 lineInfoFrom: NimNode=nil): NimNode
+  {.magic: "NNewNimNode", noSideEffect.}
+  ## Creates a new AST node of the specified kind.
+  ##
+  ## The ``lineInfoFrom`` parameter is used for line information when the
+  ## produced code crashes. You should ensure that it is set to a node that
+  ## you are transforming.
 
 proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
 proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
@@ -249,6 +255,11 @@ proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
   result = newNimNode(nnkStrLit)
   result.strVal = s
 
+proc newCommentStmtNode*(s: string): NimNode {.compileTime, noSideEffect.} =
+  ## creates a comment statement node
+  result = newNimNode(nnkCommentStmt)
+  result.strVal = s
+
 proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
   ## creates a int literal node from `i`
   result = newNimNode(nnkIntLit)
@@ -269,6 +280,7 @@ proc newIdentNode*(i: string): NimNode {.compileTime.} =
   result = newNimNode(nnkIdent)
   result.ident = !i
 
+
 type
   BindSymRule* = enum    ## specifies how ``bindSym`` behaves
     brClosed,            ## only the symbols in current scope are bound
@@ -426,20 +438,105 @@ proc newLit*(c: char): NimNode {.compileTime.} =
   result = newNimNode(nnkCharLit)
   result.intVal = ord(c)
 
-proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
+
+proc newLit*(i: int): NimNode {.compileTime.} =
   ## produces a new integer literal node.
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
+proc newLit*(i: int8): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt8Lit)
+  result.intVal = i
+
+proc newLit*(i: int16): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt16Lit)
+  result.intVal = i
+
+proc newLit*(i: int32): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt32Lit)
+  result.intVal = i
+
+proc newLit*(i: int64): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkInt64Lit)
+  result.intVal = i
+
+proc newLit*(i: uint): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUIntLit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint8): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt8Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint16): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt16Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint32): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt32Lit)
+  result.intVal = BiggestInt(i)
+
+proc newLit*(i: uint64): NimNode {.compileTime.} =
+  ## produces a new unsigned integer literal node.
+  result = newNimNode(nnkUInt64Lit)
+  result.intVal = BiggestInt(i)
+
 proc newLit*(b: bool): NimNode {.compileTime.} =
   ## produces a new boolean literal node.
   result = if b: bindSym"true" else: bindSym"false"
 
-proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
+when false:
+  # the float type is not really a distinct type as described in https://github.com/nim-lang/Nim/issues/5875
+  proc newLit*(f: float): NimNode {.compileTime.} =
+    ## produces a new float literal node.
+    result = newNimNode(nnkFloatLit)
+    result.floatVal = f
+
+proc newLit*(f: float32): NimNode {.compileTime.} =
   ## produces a new float literal node.
-  result = newNimNode(nnkFloatLit)
+  result = newNimNode(nnkFloat32Lit)
   result.floatVal = f
 
+proc newLit*(f: float64): NimNode {.compileTime.} =
+  ## produces a new float literal node.
+  result = newNimNode(nnkFloat64Lit)
+  result.floatVal = f
+
+when compiles(float128):
+  proc newLit*(f: float128): NimNode {.compileTime.} =
+    ## produces a new float literal node.
+    result = newNimNode(nnkFloat128Lit)
+    result.floatVal = f
+
+proc newLit*(arg: object): NimNode {.compileTime.} =
+  result = nnkObjConstr.newTree(arg.type.getTypeInst[1])
+  for a, b in arg.fieldPairs:
+    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+
+proc newLit*[N,T](arg: array[N,T]): NimNode {.compileTime.} =
+  result = nnkBracket.newTree
+  for x in arg:
+    result.add newLit(x)
+
+proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} =
+  result = nnkBracket.newTree
+  for x in arg:
+    result.add newLit(x)
+  result = nnkPrefix.newTree(bindSym"@", result)
+
+proc newLit*(arg: tuple): NimNode {.compileTime.} =
+  result = nnkPar.newTree
+  for a,b in arg.fieldPairs:
+    result.add nnkExprColonExpr.newTree( newIdentNode(a), newLit(b) )
+
 proc newLit*(s: string): NimNode {.compileTime.} =
   ## produces a new string literal node.
   result = newNimNode(nnkStrLit)
@@ -744,6 +841,8 @@ proc `$`*(node: NimNode): string {.compileTime.} =
     result = $node[0]
   of nnkAccQuoted:
     result = $node[0]
+  of nnkCommentStmt:
+    result = node.strVal
   else:
     badNodeKind node.kind, "$"
 
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 02312a4d5..55d1dd2eb 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -79,6 +79,9 @@ const
   DT_SOCK* = 12   ## UNIX domain socket.
   DT_WHT* = 14
 
+# Special types
+type Sighandler = proc (a: cint) {.noconv.}
+
 # Platform specific stuff
 
 when defined(linux) and defined(amd64):
@@ -86,6 +89,9 @@ when defined(linux) and defined(amd64):
 else:
   include posix_other
 
+# There used to be this name in posix.nim a long time ago, not sure why!
+{.deprecated: [cSIG_HOLD: SIG_HOLD].}
+
 when not defined(macosx):
   proc st_atime*(s: Stat): Time {.inline.} =
     ## Second-granularity time of last access
@@ -659,7 +665,7 @@ proc sighold*(a1: cint): cint {.importc, header: "<signal.h>".}
 proc sigignore*(a1: cint): cint {.importc, header: "<signal.h>".}
 proc siginterrupt*(a1, a2: cint): cint {.importc, header: "<signal.h>".}
 proc sigismember*(a1: var Sigset, a2: cint): cint {.importc, header: "<signal.h>".}
-proc signal*(a1: cint, a2: proc (x: cint) {.noconv.}) {.
+proc signal*(a1: cint, a2: Sighandler) {.
   importc, header: "<signal.h>".}
 proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".}
 proc sigpending*(a1: var Sigset): cint {.importc, header: "<signal.h>".}
diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim
index 70f7e710f..c44128b16 100644
--- a/lib/posix/posix_linux_amd64.nim
+++ b/lib/posix/posix_linux_amd64.nim
@@ -36,6 +36,9 @@ type
 
 {.deprecated: [TSocketHandle: SocketHandle].}
 
+# not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc
+const SIG_HOLD* = cast[SigHandler](2)
+
 type
   Timespec* {.importc: "struct timespec",
                header: "<time.h>", final, pure.} = object ## struct timespec
diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim
index 9e2ed32e1..4b693960e 100644
--- a/lib/posix/posix_linux_amd64_consts.nim
+++ b/lib/posix/posix_linux_amd64_consts.nim
@@ -399,6 +399,9 @@ const SS_ONSTACK* = cint(1)
 const SS_DISABLE* = cint(2)
 const MINSIGSTKSZ* = cint(2048)
 const SIGSTKSZ* = cint(8192)
+const SIG_DFL* = cast[Sighandler](0)
+const SIG_ERR* = cast[Sighandler](-1)
+const SIG_IGN* = cast[Sighandler](1)
 
 # <sys/ipc.h>
 const IPC_CREAT* = cint(512)
diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim
index f2a71d1bd..003414a6a 100644
--- a/lib/posix/posix_other_consts.nim
+++ b/lib/posix/posix_other_consts.nim
@@ -414,6 +414,10 @@ var SS_ONSTACK* {.importc: "SS_ONSTACK", header: "<signal.h>".}: cint
 var SS_DISABLE* {.importc: "SS_DISABLE", header: "<signal.h>".}: cint
 var MINSIGSTKSZ* {.importc: "MINSIGSTKSZ", header: "<signal.h>".}: cint
 var SIGSTKSZ* {.importc: "SIGSTKSZ", header: "<signal.h>".}: cint
+var SIG_HOLD* {.importc: "SIG_HOLD", header: "<signal.h>".}: Sighandler
+var SIG_DFL* {.importc: "SIG_DFL", header: "<signal.h>".}: Sighandler
+var SIG_ERR* {.importc: "SIG_ERR", header: "<signal.h>".}: Sighandler
+var SIG_IGN* {.importc: "SIG_IGN", header: "<signal.h>".}: Sighandler
 
 # <sys/ipc.h>
 var IPC_CREAT* {.importc: "IPC_CREAT", header: "<sys/ipc.h>".}: cint
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 1697384e0..8c1cf6b18 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -163,8 +163,8 @@ include includes/asyncfutures
 
 type
   PDispatcherBase = ref object of RootRef
-    timers: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
-    callbacks: Deque[proc ()]
+    timers*: HeapQueue[tuple[finishAt: float, fut: Future[void]]]
+    callbacks*: Deque[proc ()]
 
 proc processTimers(p: PDispatcherBase) {.inline.} =
   #Process just part if timers at a step
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 8d059dbbc..a374e80e8 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   i.inc protocol.parseInt(result.minor, i)
 
 proc sendStatus(client: AsyncSocket, status: string): Future[void] =
-  client.send("HTTP/1.1 " & status & "\c\L")
+  client.send("HTTP/1.1 " & status & "\c\L\c\L") 
 
 proc processClient(client: AsyncSocket, address: string,
                    callback: proc (request: Request):
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index ce4c9a9c9..89b216b25 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -301,13 +301,13 @@ proc verifyReturnType(typeName: string) {.compileTime.} =
 proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   ## This macro transforms a single procedure into a closure iterator.
   ## The ``async`` macro supports a stmtList holding multiple async procedures.
-  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef}:
+  if prc.kind notin {nnkProcDef, nnkLambda, nnkMethodDef, nnkDo}:
       error("Cannot transform this node kind into an async proc." &
             " proc/method definition or lambda node expected.")
 
-  hint("Processing " & prc[0].getName & " as an async proc.")
+  let prcName = prc.name.getName
 
-  let returnType = prc[3][0]
+  let returnType = prc.params[0]
   var baseType: NimNode
   # Verify that the return type is a Future[T]
   if returnType.kind == nnkBracketExpr:
@@ -326,9 +326,9 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   let subtypeIsVoid = returnType.kind == nnkEmpty or
         (baseType.kind == nnkIdent and returnType[1].ident == !"void")
 
-  let futureVarIdents = getFutureVarIdents(prc[3])
+  let futureVarIdents = getFutureVarIdents(prc.params)
 
-  var outerProcBody = newNimNode(nnkStmtList, prc[6])
+  var outerProcBody = newNimNode(nnkStmtList, prc.body)
 
   # -> var retFuture = newFuture[T]()
   var retFutureSym = genSym(nskVar, "retFuture")
@@ -338,10 +338,10 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   outerProcBody.add(
     newVarStmt(retFutureSym,
       newCall(
-        newNimNode(nnkBracketExpr, prc[6]).add(
+        newNimNode(nnkBracketExpr, prc.body).add(
           newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
           subRetType),
-      newLit(prc[0].getName)))) # Get type from return type of this proc
+      newLit(prcName)))) # Get type from return type of this proc
 
   # -> iterator nameIter(): FutureBase {.closure.} =
   # ->   {.push warning[resultshadowed]: off.}
@@ -349,8 +349,8 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
   # ->   {.pop.}
   # ->   <proc_body>
   # ->   complete(retFuture, result)
-  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
-  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid,
+  var iteratorNameSym = genSym(nskIterator, $prcName & "Iter")
+  var procBody = prc.body.processBody(retFutureSym, subtypeIsVoid,
                                     futureVarIdents, nil)
   # don't do anything with forward bodies (empty)
   if procBody.kind != nnkEmpty:
@@ -362,7 +362,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
           newIdentNode("warning"), newIdentNode("resultshadowed")),
         newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
 
-      procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
+      procBody.insert(1, newNimNode(nnkVarSection, prc.body).add(
         newIdentDefs(newIdentNode("result"), baseType))) # -> var result: T
 
       procBody.insert(2, newNimNode(nnkPragma).add(
@@ -377,35 +377,32 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} =
 
     var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                   procBody, nnkIteratorDef)
-    closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
+    closureIterator.pragma = newNimNode(nnkPragma, lineInfoFrom=prc.body)
+    closureIterator.addPragma(newIdentNode("closure"))
+    closureIterator.addPragma(newIdentNode("gcsafe"))
     outerProcBody.add(closureIterator)
 
     # -> createCb(retFuture)
     #var cbName = newIdentNode("cb")
     var procCb = getAst createCb(retFutureSym, iteratorNameSym,
-                         newStrLitNode(prc[0].getName),
+                         newStrLitNode(prcName),
                          createFutureVarCompletions(futureVarIdents, nil))
     outerProcBody.add procCb
 
     # -> return retFuture
-    outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
+    outerProcBody.add newNimNode(nnkReturnStmt, prc.body[^1]).add(retFutureSym)
 
   result = prc
 
-  # Remove the 'async' pragma.
-  for i in 0 .. <result[4].len:
-    if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
-      result[4].del(i)
-  result[4] = newEmptyNode()
   if subtypeIsVoid:
     # Add discardable pragma.
     if returnType.kind == nnkEmpty:
       # Add Future[void]
-      result[3][0] = parseExpr("Future[void]")
+      result.params[0] = parseExpr("Future[void]")
   if procBody.kind != nnkEmpty:
-    result[6] = outerProcBody
+    result.body = outerProcBody
   #echo(treeRepr(result))
-  #if prc[0].getName == "recvLineInto":
+  #if prcName == "recvLineInto":
   #  echo(toStrLit(result))
 
 macro async*(prc: untyped): untyped =
@@ -529,8 +526,6 @@ macro multisync*(prc: untyped): untyped =
   ##
   ## The generated async procedures use the ``async`` macro, whereas the
   ## generated synchronous procedures simply strip off the ``await`` calls.
-  hint("Processing " & prc[0].getName & " as a multisync proc.")
-
   let (sync, asyncPrc) = splitProc(prc)
   result = newStmtList()
   result.add(asyncSingleProc(asyncPrc))
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 9f73bc3cf..5de65efe0 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -533,15 +533,13 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string],
   else:
     var c = ""
     while true:
-      let recvFut = recv(socket, 1, flags)
-      c = recvFut.read()
+      c = await recv(socket, 1, flags)
       if c.len == 0:
         resString.mget.setLen(0)
         resString.complete()
         return
       if c == "\r":
-        let recvFut = recv(socket, 1, flags) # Skip \L
-        c = recvFut.read()
+        c = await recv(socket, 1, flags) # Skip \L
         assert c == "\L"
         addNLIfEmpty()
         resString.complete()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 323af5a38..5b6701a12 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -590,8 +590,11 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
   swap(t.data, n)
   while h >= 0:
     var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+    let eh = n[h].hcode
+    if isFilled(eh):
+      var j: Hash = eh and maxHash(t)
+      while isFilled(t.data[j].hcode):
+        j = nextTry(j, maxHash(t))
       rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
 
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index c3390573a..603fee080 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -69,4 +69,4 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     result = affinitySpaceTotal().int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
-  if result <= 0: result = 1
+  if result <= 0: result = 0
diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim
index 896497630..0adba5b1e 100644
--- a/lib/pure/distros.nim
+++ b/lib/pure/distros.nim
@@ -158,7 +158,7 @@ proc detectOsImpl(d: Distribution): bool =
   of Distribution.ArchLinux:
     result = "arch" in toLowerAscii(uname())
   of Distribution.OpenSUSE:
-    result = "suse" in toLowerAscii(uname())
+    result = "suse" in toLowerAscii(uname()) or "suse" in toLowerAscii(release())
   of Distribution.GoboLinux:
     result = "-Gobo " in uname()
   of Distribution.OpenMandriva:
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index e8c8776c6..b015ed311 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -139,9 +139,14 @@ proc hash*(x: cstring): Hash =
   ## efficient hashing of null-terminated strings
   var h: Hash = 0
   var i = 0
-  while x[i] != 0.char:
-    h = h !& ord(x[i])
-    inc i
+  when defined(js):
+    while i < x.len:
+      h = h !& ord(x[i])
+      inc i
+  else:
+    while x[i] != 0.char:
+      h = h !& ord(x[i])
+      inc i
   result = !$h
 
 proc hash*(sBuf: string, sPos, ePos: int): Hash =
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 4f43177a8..909a2613f 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -62,7 +62,8 @@
 ##   let body = %*{
 ##       "data": "some text"
 ##   }
-##   echo client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   let response = client.request("http://some.api", httpMethod = HttpPost, body = $body)
+##   echo response.status
 ##
 ## Progress reporting
 ## ==================
diff --git a/lib/pure/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
index a7d2f803f..8b760c66a 100644
--- a/lib/pure/includes/asynccommon.nim
+++ b/lib/pure/includes/asynccommon.nim
@@ -3,7 +3,7 @@ template newAsyncNativeSocketImpl(domain, sockType, protocol) =
   if handle == osInvalidSocket:
     raiseOSError(osLastError())
   handle.setBlocking(false)
-  when defined(macosx):
+  when defined(macosx) and not defined(nimdoc):
     handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
   result = handle.AsyncFD
   register(result)
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 564f952d3..e3d5191c6 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1001,7 +1001,7 @@ proc escapeJson*(s: string; result: var string) =
   result.add("\"")
   for x in runes(s):
     var r = int(x)
-    if r >= 32 and r <= 127:
+    if r >= 32 and r <= 126:
       var c = chr(r)
       case c
       of '"': result.add("\\\"")
@@ -1608,7 +1608,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
       result = processType(newIdentNode(typeName), obj, jsonNode, true)
     of "seq":
       let seqT = typeSym[1]
-      let forLoopI = newIdentNode("i")
+      let forLoopI = genSym(nskForVar, "i")
       let indexerNode = createJsonIndexer(jsonNode, forLoopI)
       let constructorNode = createConstructor(seqT, indexerNode)
 
@@ -1616,12 +1616,25 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
       result = quote do:
         (
           var list: `typeSym` = @[];
-          # if `jsonNode`.kind != JArray:
-          #   # TODO: Improve error message.
-          #   raise newException(ValueError, "Expected a list")
+          verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
           for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
           list
         )
+    of "array":
+      let arrayT = typeSym[2]
+      let forLoopI = genSym(nskForVar, "i")
+      let indexerNode = createJsonIndexer(jsonNode, forLoopI)
+      let constructorNode = createConstructor(arrayT, indexerNode)
+
+      # Create a statement expression containing a for loop.
+      result = quote do:
+        (
+          var list: `typeSym`;
+          verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
+          for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`;
+          list
+        )
+
     else:
       # Generic type.
       let obj = getType(typeSym)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index a8432b6f0..8037b31b0 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -235,7 +235,7 @@ when not defined(JS):
         x = x and (not (1'u64 shl (64'u64-12'u64-e) - 1'u64))
 
       result = cast[float64](x)
-    
+
     proc truncImpl(f: float32): float32 =
       const
         mask : uint32 = 0xFF
@@ -255,7 +255,7 @@ when not defined(JS):
         x = x and (not (1'u32 shl (32'u32-9'u32-e) - 1'u32))
 
       result = cast[float32](x)
-      
+
     proc trunc*(x: float64): float64 =
       if classify(x) in {fcZero, fcNegZero, fcNan, fcInf, fcNegInf}: return x
       result = truncImpl(x)
@@ -395,6 +395,12 @@ proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from radians to degrees
   result = T(d) / RadPerDeg
 
+proc sgn*[T: SomeNumber](x: T): int {.inline.} =
+  ## Sign function. Returns -1 for negative numbers and `NegInf`, 1 for
+  ## positive numbers and `Inf`, and 0 for positive zero, negative zero and
+  ## `NaN`.
+  ord(T(0) < x) - ord(x < T(0))
+
 proc `mod`*[T: float32|float64](x, y: T): T =
   ## Computes the modulo operation for float operators. Equivalent
   ## to ``x - y * floor(x/y)``. Note that the remainder will always
@@ -407,10 +413,13 @@ proc `mod`*[T: float32|float64](x, y: T): T =
 {.pop.}
 {.pop.}
 
-proc `^`*[T](x, y: T): T =
+proc `^`*[T](x: T, y: Natural): T =
   ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>` for negative exponents.
-  assert y >= T(0)
+  when compiles(y >= T(0)):
+    assert y >= T(0)
+  else:
+    assert T(y) >= T(0)
   var (x, y) = (x, y)
   result = 1
 
@@ -447,6 +456,7 @@ when isMainModule and not defined(JS):
   assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
   assert(erf(6.0) > erf(5.0))
   assert(erfc(6.0) < erfc(5.0))
+
 when isMainModule:
   # Function for approximate comparison of floats
   proc `==~`(x, y: float): bool = (abs(x-y) < 1e-9)
@@ -509,3 +519,21 @@ when isMainModule:
     doAssert(classify(trunc(-1e1000000'f32)) == fcNegInf)
     doAssert(classify(trunc(f_nan.float32)) == fcNan)
     doAssert(classify(trunc(0.0'f32)) == fcZero)
+
+  block: # sgn() tests
+    assert sgn(1'i8) == 1
+    assert sgn(1'i16) == 1
+    assert sgn(1'i32) == 1
+    assert sgn(1'i64) == 1
+    assert sgn(1'u8) == 1
+    assert sgn(1'u16) == 1
+    assert sgn(1'u32) == 1
+    assert sgn(1'u64) == 1
+    assert sgn(-12342.8844'f32) == -1
+    assert sgn(123.9834'f64) == 1
+    assert sgn(0'i32) == 0
+    assert sgn(0'f32) == 0
+    assert sgn(NegInf) == -1
+    assert sgn(Inf) == 1
+    assert sgn(NaN) == 0
+
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 98b6aa309..f7bcfb60e 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -666,29 +666,38 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
     else:
       raiseOSError(osLastError(), $strerror(errno))
 
-proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect, WriteIOEffect].} =
-  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+proc tryMoveFSObject(source, dest: string): bool =
+  ## Moves a file or directory from `source` to `dest`. Returns false in case
+  ## of `EXDEV` error. In case of other errors `OSError` is raised. Returns
+  ## true in case of success.
   when defined(Windows):
     when useWinUnicode:
       let s = newWideCString(source)
       let d = newWideCString(dest)
-      if moveFileW(s, d) == 0'i32: raiseOSError(osLastError())
+      if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
     else:
-      if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError())
+      if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError())
   else:
     if c_rename(source, dest) != 0'i32:
       let err = osLastError()
       if err == EXDEV.OSErrorCode:
-        # Fallback to copy & del
-        copyFile(source, dest)
-        try:
-          removeFile(source)
-        except:
-          discard tryRemoveFile(dest)
-          raise
+        return false
       else:
         raiseOSError(err, $strerror(errno))
+  return true
+
+proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+  if not tryMoveFSObject(source, dest):
+    when not defined(windows):
+      # Fallback to copy & del
+      copyFile(source, dest)
+      try:
+        removeFile(source)
+      except:
+        discard tryRemoveFile(dest)
+        raise
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   tags: [ExecIOEffect].} =
@@ -1369,6 +1378,14 @@ proc exclFilePermissions*(filename: string,
   ##   setFilePermissions(filename, getFilePermissions(filename)-permissions)
   setFilePermissions(filename, getFilePermissions(filename)-permissions)
 
+proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised.
+  if not tryMoveFSObject(source, dest):
+    when not defined(windows):
+      # Fallback to copy & del
+      copyDir(source, dest)
+      removeDir(source)
+
 include ospaths
 
 proc expandSymlink*(symlinkPath: string): string =
@@ -1412,7 +1429,7 @@ when defined(nimdoc):
   proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
     ## Returns the `i`-th `command line argument`:idx: given to the application.
     ##
-    ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex`
+    ## `i` should be in the range `1..paramCount()`, the `IndexError`
     ## exception will be raised for invalid values.  Instead of iterating over
     ## `paramCount() <#paramCount>`_ with this proc you can call the
     ## convenience `commandLineParams() <#commandLineParams>`_.
@@ -1450,7 +1467,8 @@ elif defined(windows):
     tags: [ReadIOEffect].} =
     # Docstring in nimdoc block.
     if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
-    return TaintedString(ownArgv[i])
+    if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
+    raise newException(IndexError, "invalid index")
 
 elif not defined(createNimRtl) and
   not(defined(posix) and appType == "lib") and
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 7720fb2a6..fa5342fcf 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -516,7 +516,16 @@ when declared(getEnv) or defined(nimscript):
   proc getConfigDir*(): string {.rtl, extern: "nos$1",
     tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the config directory of the current user for applications.
+    ##
+    ## On non-Windows OSs, this proc conforms to the XDG Base Directory
+    ## spec. Thus, this proc returns the value of the XDG_CONFIG_DIR environment
+    ## variable if it is set, and returns the default configuration directory,
+    ## "~/.config/", otherwise.
+    ##
+    ## An OS-dependent trailing slash is always present at the end of the
+    ## returned string; `\\` on Windows and `/` on all other OSs.
     when defined(windows): return string(getEnv("APPDATA")) & "\\"
+    elif getEnv("XDG_CONFIG_DIR"): return string(getEnv("XDG_CONFIG_DIR")) & "/"
     else: return string(getEnv("HOME")) & "/.config/"
 
   proc getTempDir*(): string {.rtl, extern: "nos$1",
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index c94a65a63..23c8546c4 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -863,18 +863,15 @@ elif not defined(useNimRtl):
       if data.workingDir.len > 0:
         setCurrentDir($data.workingDir)
       var pid: Pid
-      var err: OSErrorCode
 
       if data.optionPoUsePath:
         res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
-        if res != 0'i32: err = osLastError()
       else:
         res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
-        if res != 0'i32: err = osLastError()
 
       discard posix_spawn_file_actions_destroy(fops)
       discard posix_spawnattr_destroy(attr)
-      if res != 0'i32: raiseOSError(err)
+      if res != 0'i32: raiseOSError(OSErrorCode(res))
 
       return pid
   else:
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 28681a11f..5bdd3bc40 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -540,8 +540,8 @@ proc writeConfig*(dict: Config, filename: string) =
   ## Writes the contents of the table to the specified configuration file.
   ## Note: Comment statement will be ignored.
   let file = open(filename, fmWrite)
-  let fileStream = newFileStream(filename)
-  defer: fileStream.close()
+  defer: file.close()
+  let fileStream = newFileStream(file)
   dict.writeConfig(fileStream)
 
 proc getSectionValue*(dict: Config, section, key: string): string =
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 218f5ab81..23568edb9 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -149,26 +149,41 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
   ## retrieves the rest of the command line that has not been parsed yet.
   result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
 
+iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(initOptParser):
   iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 7fd9c60fe..2e8dbe140 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -123,26 +123,41 @@ type
 
 {.deprecated: [TGetoptResult: GetoptResult].}
 
+iterator getopt*(p: var OptParser): GetoptResult =
+  ## This is an convenience iterator for iterating over the given OptParser object.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var p = initOptParser("--left --debug:3 -l=4 -r:2")
+  ##   for kind, key, val in p.getopt():
+  ##     case kind
+  ##     of cmdArgument:
+  ##       filename = key
+  ##     of cmdLongOption, cmdShortOption:
+  ##       case key
+  ##       of "help", "h": writeHelp()
+  ##       of "version", "v": writeVersion()
+  ##     of cmdEnd: assert(false) # cannot happen
+  ##   if filename == "":
+  ##     # no filename has been given, so we show the help:
+  ##     writeHelp()
+  p.pos = 0
+  while true:
+    next(p)
+    if p.kind == cmdEnd: break
+    yield (p.kind, p.key, p.val)
+
 when declared(paramCount):
   iterator getopt*(): GetoptResult =
-    ## This is an convenience iterator for iterating over the command line.
-    ## This uses the OptParser object. Example:
+    ## This is an convenience iterator for iterating over the command line arguments.
+    ## This create a new OptParser object.
+    ## See above for a more detailed example
     ##
     ## .. code-block:: nim
-    ##   var
-    ##     filename = ""
     ##   for kind, key, val in getopt():
-    ##     case kind
-    ##     of cmdArgument:
-    ##       filename = key
-    ##     of cmdLongOption, cmdShortOption:
-    ##       case key
-    ##       of "help", "h": writeHelp()
-    ##       of "version", "v": writeVersion()
-    ##     of cmdEnd: assert(false) # cannot happen
-    ##   if filename == "":
-    ##     # no filename has been given, so we show the help:
-    ##     writeHelp()
+    ##     # this will iterate over all arguments passed to the cmdline.
+    ##     continue
+    ##
     var p = initOptParser()
     while true:
       next(p)
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 5c978a2f8..6a52e2cd5 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -371,7 +371,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   of '\a': result = "\\a"
   of '\\': result = "\\\\"
   of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
-  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c < ' ' or c >= '\127': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
 
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index 1f750edcd..8a32f7d9a 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -123,7 +123,8 @@ when not defined(nimscript):
       proc getMil(t: Time): int {.importcpp: "getTime", nodecl.}
       randomize(getMil times.getTime())
     else:
-      randomize(int times.getTime())
+      let time = int(times.epochTime() * 1_000_000_000)
+      randomize(time)
 
 {.pop.}
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index eea06f4ce..438b48beb 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -334,12 +334,16 @@ when not defined(js):
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
       inc(s.pos, result)
+    else:
+      result = 0
 
   proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
     var s = StringStream(s)
     result = min(bufLen, s.data.len - s.pos)
     if result > 0:
       copyMem(buffer, addr(s.data[s.pos]), result)
+    else:
+      result = 0
 
   proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
     var s = StringStream(s)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 458c22f3a..20b2657f6 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -1643,7 +1643,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   ## * replaces any ``\`` by ``\\``
   ## * replaces any ``'`` by ``\'``
   ## * replaces any ``"`` by ``\"``
-  ## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}``
+  ## * replaces any other character in the set ``{'\0'..'\31', '\127'..'\255'}``
   ##   by ``\xHH`` where ``HH`` is its hexadecimal value.
   ## The procedure has been designed so that its output is usable for many
   ## different common syntaxes. The resulting string is prefixed with
@@ -1653,7 +1653,7 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   result.add(prefix)
   for c in items(s):
     case c
-    of '\0'..'\31', '\128'..'\255':
+    of '\0'..'\31', '\127'..'\255':
       add(result, "\\x")
       add(result, toHex(ord(c), 2))
     of '\\': add(result, "\\\\")
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index bad003a3e..1bda94d14 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -81,7 +81,7 @@ when defined(posix) and not defined(JS):
 elif defined(windows):
   import winlean
 
-  when defined(vcc) or defined(bcc):
+  when defined(vcc) or defined(bcc) or defined(icl):
     # newest version of Visual C++ defines time_t to be of 64 bits
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
     # visual c's c runtime exposes these under a different name
@@ -98,46 +98,47 @@ elif defined(windows):
 
 elif defined(JS):
   type
-    Time* = ref TimeObj
-    TimeObj {.importc.} = object
-      getDay: proc (): int {.tags: [], raises: [], benign.}
-      getFullYear: proc (): int {.tags: [], raises: [], benign.}
-      getHours: proc (): int {.tags: [], raises: [], benign.}
-      getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
-      getMinutes: proc (): int {.tags: [], raises: [], benign.}
-      getMonth: proc (): int {.tags: [], raises: [], benign.}
-      getSeconds: proc (): int {.tags: [], raises: [], benign.}
-      getTime: proc (): int {.tags: [], raises: [], noSideEffect, benign.}
-      getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
-      getDate: proc (): int {.tags: [], raises: [], benign.}
-      getUTCDate: proc (): int {.tags: [], raises: [], benign.}
-      getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
-      getUTCHours: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
-      getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
-      getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
-      getUTCDay: proc (): int {.tags: [], raises: [], benign.}
-      getYear: proc (): int {.tags: [], raises: [], benign.}
-      parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
-      setDate: proc (x: int) {.tags: [], raises: [], benign.}
-      setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
-      setHours: proc (x: int) {.tags: [], raises: [], benign.}
-      setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
-      setMonth: proc (x: int) {.tags: [], raises: [], benign.}
-      setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setTime: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
-      setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
-      setYear: proc (x: int) {.tags: [], raises: [], benign.}
-      toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
-      toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
+    TimeBase = float
+    Time* = distinct TimeBase
+
+  proc getDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getTime(t: Time): int {.tags: [], raises: [], noSideEffect, benign, importcpp.}
+  proc getTimezoneOffset(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCDate(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCFullYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCHours(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMilliseconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMinutes(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCMonth(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCSeconds(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getUTCDay(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc getYear(t: Time): int {.tags: [], raises: [], benign, importcpp.}
+  proc parse(t: Time; s: cstring): Time {.tags: [], raises: [], benign, importcpp.}
+  proc setDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setTime(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCDate(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCFullYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCHours(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMilliseconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMinutes(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCMonth(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setUTCSeconds(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc setYear(t: Time; x: int) {.tags: [], raises: [], benign, importcpp.}
+  proc toGMTString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
+  proc toLocaleString(t: Time): cstring {.tags: [], raises: [], benign, importcpp.}
 
 type
   TimeInfo* = object of RootObj ## represents a time in different parts
@@ -225,17 +226,26 @@ proc `-`*(a, b: Time): int64 {.
 proc `<`*(a, b: Time): bool {.
   rtl, extern: "ntLtTime", tags: [], raises: [], noSideEffect.} =
   ## returns true iff ``a < b``, that is iff a happened before b.
-  result = a - b < 0
+  when defined(js):
+    result = TimeBase(a) < TimeBase(b)
+  else:
+    result = a - b < 0
 
 proc `<=` * (a, b: Time): bool {.
   rtl, extern: "ntLeTime", tags: [], raises: [], noSideEffect.}=
   ## returns true iff ``a <= b``.
-  result = a - b <= 0
+  when defined(js):
+    result = TimeBase(a) <= TimeBase(b)
+  else:
+    result = a - b <= 0
 
 proc `==`*(a, b: Time): bool {.
   rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect.} =
   ## returns true if ``a == b``, that is if both times represent the same value
-  result = a - b == 0
+  when defined(js):
+    result = TimeBase(a) == TimeBase(b)
+  else:
+    result = a - b == 0
 
 proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
@@ -479,7 +489,7 @@ proc `-=`*(t: var Time, ti: TimeInterval) =
   t = toTime(getLocalTime(t) - ti)
 
 proc `-`*(t: Time, ti: TimeInterval): Time =
-  ## adds the interval `ti` to Time `t`
+  ## subtracts the interval `ti` from Time `t`
   ##
   ## ``echo getTime() - 1.day``
   result = toTime(getLocalTime(t) - ti)
diff --git a/lib/system.nim b/lib/system.nim
index 9b41253cc..8f653c1e0 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -49,6 +49,9 @@ type
   cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
   pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
                               ## operator to get a pointer to a variable
+
+  typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
+
 const
   on* = true    ## alias for ``true``
   off* = false  ## alias for ``false``
@@ -56,6 +59,15 @@ const
 {.push warning[GcMem]: off, warning[Uninit]: off.}
 {.push hints: off.}
 
+proc `or` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
+  ## Constructs an `or` meta class
+
+proc `and` *(a, b: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
+  ## Constructs an `and` meta class
+
+proc `not` *(a: typedesc): typedesc {.magic: "TypeTrait", noSideEffect.}
+  ## Constructs an `not` meta class
+
 type
   Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer,
                                  ## bool, character, and enumeration types
@@ -66,11 +78,11 @@ type
   `ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
 
   `nil` {.magic: "Nil".}
+
   expr* {.magic: Expr, deprecated.} ## meta type to denote an expression (for templates)
-                        ## **Deprecated** since version 0.15. Use ``untyped`` instead.
+    ## **Deprecated** since version 0.15. Use ``untyped`` instead.
   stmt* {.magic: Stmt, deprecated.} ## meta type to denote a statement (for templates)
     ## **Deprecated** since version 0.15. Use ``typed`` instead.
-  typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
   void* {.magic: "VoidType".}   ## meta type to denote the absence of any type
   auto* {.magic: Expr.} ## meta type for automatic type determination
   any* = distinct auto ## meta type for any supported type
@@ -430,6 +442,7 @@ type
                                         ## providing an exception message
                                         ## is bad style.
     trace: string
+    up: ref Exception # used for stacking exceptions. Not exported!
 
   SystemError* = object of Exception ## \
     ## Abstract class for exceptions that the runtime system raises.
@@ -1056,7 +1069,7 @@ proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
   ## ``floor(x/y)``.
   ##
   ## .. code-block:: Nim
-  ##  (7 div 5) == 2
+  ##  (7 div 5) == 1
 
 proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
   ## computes the integer modulo operation (remainder).
@@ -1332,6 +1345,7 @@ const
   hasThreadSupport = compileOption("threads") and not defined(nimscript)
   hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
   taintMode = compileOption("taintmode")
+  nimEnableCovariance* = defined(nimEnableCovariance) # or true
 
 when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
   # tcc doesn't support TLS
@@ -1879,7 +1893,7 @@ const
   NimMajor*: int = 0
     ## is the major number of Nim's version.
 
-  NimMinor*: int = 16
+  NimMinor*: int = 17
     ## is the minor number of Nim's version.
 
   NimPatch*: int = 1
@@ -2034,6 +2048,14 @@ proc clamp*[T](x, a, b: T): T =
   if x > b: return b
   return x
 
+proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} =
+  ## length of ordinal slice, when x.b < x.a returns zero length
+  ##
+  ## .. code-block:: Nim
+  ##   assert((0..5).len == 6)
+  ##   assert((5..2).len == 0)
+  result = max(0, ord(x.b) - ord(x.a) + 1)
+
 iterator items*[T](a: openArray[T]): T {.inline.} =
   ## iterates over each item of `a`.
   var i = 0
@@ -2428,18 +2450,6 @@ when false:
 # ----------------- GC interface ---------------------------------------------
 
 when not defined(nimscript) and hasAlloc:
-  proc GC_disable*() {.rtl, inl, benign.}
-    ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
-    ## reactivate the GC. Note that in most circumstances one should only disable
-    ## the mark and sweep phase with `GC_disableMarkAndSweep`.
-
-  proc GC_enable*() {.rtl, inl, benign.}
-    ## enables the GC again.
-
-  proc GC_fullCollect*() {.rtl, benign.}
-    ## forces a full garbage collection pass.
-    ## Ordinary code does not need to call this (and should not).
-
   type
     GC_Strategy* = enum ## the strategy the GC should use for the application
       gcThroughput,      ## optimize for throughput
@@ -2449,33 +2459,87 @@ when not defined(nimscript) and hasAlloc:
 
   {.deprecated: [TGC_Strategy: GC_Strategy].}
 
-  proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
-    ## tells the GC the desired strategy for the application.
-    ## **Deprecated** since version 0.8.14. This has always been a nop.
-
-  proc GC_enableMarkAndSweep*() {.rtl, benign.}
-  proc GC_disableMarkAndSweep*() {.rtl, benign.}
-    ## the current implementation uses a reference counting garbage collector
-    ## with a seldomly run mark and sweep phase to free cycles. The mark and
-    ## sweep phase may take a long time and is not needed if the application
-    ## does not create cycles. Thus the mark and sweep phase can be deactivated
-    ## and activated separately from the rest of the GC.
-
-  proc GC_getStatistics*(): string {.rtl, benign.}
-    ## returns an informative string about the GC's activity. This may be useful
-    ## for tweaking.
-
-  proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
-  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
-  proc GC_ref*(x: string) {.magic: "GCref", benign.}
-    ## marks the object `x` as referenced, so that it will not be freed until
-    ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
-    ## n calls to `GC_unref` are needed to unmark `x`.
-
-  proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
-  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
-  proc GC_unref*(x: string) {.magic: "GCunref", benign.}
-    ## see the documentation of `GC_ref`.
+  when not defined(JS):
+    proc GC_disable*() {.rtl, inl, benign.}
+      ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
+      ## reactivate the GC. Note that in most circumstances one should only disable
+      ## the mark and sweep phase with `GC_disableMarkAndSweep`.
+
+    proc GC_enable*() {.rtl, inl, benign.}
+      ## enables the GC again.
+
+    proc GC_fullCollect*() {.rtl, benign.}
+      ## forces a full garbage collection pass.
+      ## Ordinary code does not need to call this (and should not).
+
+    proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
+      ## tells the GC the desired strategy for the application.
+      ## **Deprecated** since version 0.8.14. This has always been a nop.
+
+    proc GC_enableMarkAndSweep*() {.rtl, benign.}
+    proc GC_disableMarkAndSweep*() {.rtl, benign.}
+      ## the current implementation uses a reference counting garbage collector
+      ## with a seldomly run mark and sweep phase to free cycles. The mark and
+      ## sweep phase may take a long time and is not needed if the application
+      ## does not create cycles. Thus the mark and sweep phase can be deactivated
+      ## and activated separately from the rest of the GC.
+
+    proc GC_getStatistics*(): string {.rtl, benign.}
+      ## returns an informative string about the GC's activity. This may be useful
+      ## for tweaking.
+
+    proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
+    proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
+    proc GC_ref*(x: string) {.magic: "GCref", benign.}
+      ## marks the object `x` as referenced, so that it will not be freed until
+      ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
+      ## n calls to `GC_unref` are needed to unmark `x`.
+
+    proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
+    proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
+    proc GC_unref*(x: string) {.magic: "GCunref", benign.}
+      ## see the documentation of `GC_ref`.
+
+  else:
+    template GC_disable* =
+      {.warning: "GC_disable is a no-op in JavaScript".}
+
+    template GC_enable* =
+      {.warning: "GC_enable is a no-op in JavaScript".}
+
+    template GC_fullCollect* =
+      {.warning: "GC_fullCollect is a no-op in JavaScript".}
+
+    template GC_setStrategy* =
+      {.warning: "GC_setStrategy is a no-op in JavaScript".}
+
+    template GC_enableMarkAndSweep* =
+      {.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".}
+
+    template GC_disableMarkAndSweep* =
+      {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
+
+    template GC_ref*[T](x: ref T) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_ref*[T](x: seq[T]) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_ref*(x: string) =
+      {.warning: "GC_ref is a no-op in JavaScript".}
+
+    template GC_unref*[T](x: ref T) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_unref*[T](x: seq[T]) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_unref*(x: string) =
+      {.warning: "GC_unref is a no-op in JavaScript".}
+
+    template GC_getStatistics*(): string =
+      {.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
+      ""
 
 template accumulateResult*(iter: untyped) =
   ## helps to convert an iterator to a proc.
@@ -3210,16 +3274,6 @@ when not defined(JS): #and not defined(nimscript):
 
 elif defined(JS):
   # Stubs:
-  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
-
-  proc GC_disable() = discard
-  proc GC_enable() = discard
-  proc GC_fullCollect() = discard
-  proc GC_setStrategy(strategy: GC_Strategy) = discard
-  proc GC_enableMarkAndSweep() = discard
-  proc GC_disableMarkAndSweep() = discard
-  proc GC_getStatistics(): string = return ""
-
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
@@ -3458,7 +3512,7 @@ proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.
 
 proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.
   inline, noSideEffect.} =
-  ## Increments in placee a floating point number
+  ## Increments in place a floating point number
   x = x + y
 
 proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.
@@ -3721,7 +3775,8 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
 
 when hasAlloc and not defined(nimscript) and not defined(JS):
   proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
-    ## performs a deep copy of `x`. This is also used by the code generator
+    ## performs a deep copy of `y` and copies it into `x`.
+    ## This is also used by the code generator
     ## for the implementation of ``spawn``.
     discard
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index bcbc5d92f..78db96e77 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -9,7 +9,6 @@
 
 # Low level allocator for Nim. Has been designed to support the GC.
 # TODO:
-# - eliminate "used" field
 # - make searching for block O(1)
 {.push profiler:off.}
 
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 55f283d2d..6c163f711 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -90,12 +90,11 @@ proc popSafePoint {.compilerRtl, inl.} =
   excHandler = excHandler.prev
 
 proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
-  #if e.parent.isNil:
-  #  e.parent = currException
+  e.up = currException
   currException = e
 
 proc popCurrentException {.compilerRtl, inl.} =
-  currException = nil # currException.parent
+  currException = currException.up
 
 # some platforms have native support for stack traces:
 const
@@ -247,6 +246,18 @@ when false:
     pushCurrentException(e)
     c_longjmp(excHandler.context, 1)
 
+var onUnhandledException*: (proc (errorMsg: string) {.
+  nimcall.}) ## set this error \
+  ## handler to override the existing behaviour on an unhandled exception.
+  ## The default is to write a stacktrace to ``stderr`` and then call ``quit(1)``.
+  ## Unstable API.
+
+template unhandled(buf, body) =
+  if onUnhandledException != nil:
+    onUnhandledException($buf)
+  else:
+    body
+
 proc raiseExceptionAux(e: ref Exception) =
   if localRaiseHook != nil:
     if not localRaiseHook(e): return
@@ -277,7 +288,9 @@ proc raiseExceptionAux(e: ref Exception) =
         add(buf, " [")
         add(buf, $e.name)
         add(buf, "]\n")
-        showErrorMessage(buf)
+        unhandled(buf):
+          showErrorMessage(buf)
+          quitOrDebug()
       else:
         # ugly, but avoids heap allocations :-)
         template xadd(buf, s, slen: expr) =
@@ -293,8 +306,9 @@ proc raiseExceptionAux(e: ref Exception) =
         add(buf, " [")
         xadd(buf, e.name, e.name.len)
         add(buf, "]\n")
-        showErrorMessage(buf)
-      quitOrDebug()
+        unhandled(buf):
+          showErrorMessage(buf)
+          quitOrDebug()
 
 proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
   if e.name.isNil: e.name = ename
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index b0eb25616..cd03d2a54 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -25,6 +25,13 @@ when defined(nimTypeNames):
         c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
       it = it.nextType
 
+  when defined(nimGcRefLeak):
+    proc oomhandler() =
+      c_fprintf(stdout, "[Heap] ROOTS: #%ld\n", gch.additionalRoots.len)
+      writeLeaks()
+
+    outOfMemHook = oomhandler
+
 template decTypeSize(cell, t) =
   # XXX this needs to use atomics for multithreaded apps!
   when defined(nimTypeNames):
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 5896af88e..a97e974a1 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -142,11 +142,54 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
 proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
 # we need the prototype here for debugging purposes
 
+when defined(nimGcRefLeak):
+  const
+    MaxTraceLen = 20 # tracking the last 20 calls is enough
+
+  type
+    GcStackTrace = object
+      lines: array[0..MaxTraceLen-1, cstring]
+      files: array[0..MaxTraceLen-1, cstring]
+
+  proc captureStackTrace(f: PFrame, st: var GcStackTrace) =
+    const
+      firstCalls = 5
+    var
+      it = f
+      i = 0
+      total = 0
+    while it != nil and i <= high(st.lines)-(firstCalls-1):
+      # the (-1) is for the "..." entry
+      st.lines[i] = it.procname
+      st.files[i] = it.filename
+      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:
+      st.lines[i] = "..."
+      st.files[i] = "..."
+      inc(i)
+    while b != nil and i <= high(st.lines):
+      st.lines[i] = b.procname
+      st.files[i] = b.filename
+      inc(i)
+      b = b.prev
+
+  var ax: array[10_000, GcStackTrace]
+
 proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
   when false:
     when withBitvectors: excl(gch.allocated, usrToCell(p))
     else: usrToCell(p).refcount = rcBlack
+  when defined(nimGcRefLeak):
+    captureStackTrace(framePtr, ax[gch.additionalRoots.len])
   add(gch.additionalRoots, usrToCell(p))
 
 proc nimGCunref(p: pointer) {.compilerProc.} =
@@ -157,6 +200,8 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
   while i >= 0:
     if d[i] == cell:
       d[i] = d[L]
+      when defined(nimGcRefLeak):
+        ax[i] = ax[L]
       dec gch.additionalRoots.len
       break
     dec(i)
@@ -164,6 +209,16 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
     when withBitvectors: incl(gch.allocated, usrToCell(p))
     else: usrToCell(p).refcount = rcWhite
 
+when defined(nimGcRefLeak):
+  proc writeLeaks() =
+    for i in 0..gch.additionalRoots.len-1:
+      c_fprintf(stdout, "[Heap] NEW STACK TRACE\n")
+      for ii in 0..MaxTraceLen-1:
+        let line = ax[i].lines[ii]
+        let file = ax[i].files[ii]
+        if isNil(line): break
+        c_fprintf(stdout, "[Heap] %s(%s)\n", file, line)
+
 include gc_common
 
 proc prepareDealloc(cell: PCell) =
diff --git a/lib/system/gc_stack.nim b/lib/system/gc_stack.nim
index 3eda08df9..e7b9f65a7 100644
--- a/lib/system/gc_stack.nim
+++ b/lib/system/gc_stack.nim
@@ -79,7 +79,7 @@ template withRegion*(r: MemRegion; body: untyped) =
   try:
     body
   finally:
-    r = tlRegion
+    #r = tlRegion
     tlRegion = oldRegion
 
 template inc(p: pointer, s: int) =
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 8a81a550a..768f9bc17 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -446,7 +446,7 @@ when defined(kwin):
       print(buf);
     """
 
-elif defined(nodejs):
+elif not defined(nimOldEcho):
   proc ewriteln(x: cstring) = log(x)
 
   proc rawEcho {.compilerproc, asmNoStackFrame.} =
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 431f84bfd..5b5ba9490 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -255,12 +255,21 @@ elif defined(gogc):
         next_gc: uint64          # next GC (in heap_alloc time)
         last_gc: uint64          # last GC (in absolute time)
         pause_total_ns: uint64
-        pause_ns: array[256, uint64]
+        pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths
+        pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970)
         numgc: uint32
+        numforcedgc: uint32      # number of user-forced GCs
+        gc_cpu_fraction: float64 # fraction of CPU time used by GC
         enablegc: cbool
         debuggc: cbool
         # Statistics about allocation size classes.
         by_size: array[goNumSizeClasses, goMStats_inner_struct]
+        # Statistics below here are not exported to MemStats directly.
+        tinyallocs: uint64       # number of tiny allocations that didn't cause actual allocation; not exported to go directly
+        gc_trigger: uint64
+        heap_live: uint64
+        heap_scan: uint64
+        heap_marked: uint64
 
   proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl,
     importc: "runtime_ReadMemStats",
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index d9aa03b53..ab02c58a2 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -49,7 +49,7 @@ proc reprStrAux(result: var string, s: cstring; len: int) =
     of '"': add result, "\\\""
     of '\\': add result, "\\\\" # BUGFIX: forgotten
     of '\10': add result, "\\10\"\n\"" # " \n " # better readability
-    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+    of '\127' .. '\255', '\0'..'\9', '\11'..'\31':
       add result, "\\" & reprInt(ord(c))
     else:
       result.add(c)
@@ -68,7 +68,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
   case x
   of '"': add result, "\\\""
   of '\\': add result, "\\\\"
-  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+  of '\127' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
   else: add result, x
   add result, "\'"
 
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
index 6b0e32191..5c265a891 100644
--- a/lib/system/reprjs.nim
+++ b/lib/system/reprjs.nim
@@ -44,7 +44,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
   case x
   of '"': add(result, "\\\"")
   of '\\': add(result, "\\\\")
-  of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
+  of '\127'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
   else: add(result, x)
   add(result, "\'")
 
@@ -56,7 +56,7 @@ proc reprStrAux(result: var string, s: cstring, len: int) =
     of '"': add(result, "\\\"")
     of '\\': add(result, "\\\\")
     of '\10': add(result, "\\10\"\n\"")
-    of '\128'..'\255', '\0'..'\9', '\11'..'\31':
+    of '\127'..'\255', '\0'..'\9', '\11'..'\31':
       add( result, "\\" & reprInt(ord(c)) )
     else:
       add( result, reprInt(ord(c)) ) # Not sure about this.
diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim
index f61b887ad..6569f4f9f 100644
--- a/lib/system/syslocks.nim
+++ b/lib/system/syslocks.nim
@@ -117,6 +117,12 @@ else:
       when defined(linux) and defined(amd64):
         abi: array[48 div sizeof(clonglong), clonglong]
 
+    SysCondAttr {.importc: "pthread_condattr_t", pure, final
+               header: """#include <sys/types.h>
+                          #include <pthread.h>""".} = object
+      when defined(linux) and defined(amd64):
+        abi: array[4 div sizeof(cint), cint]  # actually a cint
+
     SysLockType = distinct cint
 
   proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
@@ -185,7 +191,7 @@ else:
       importc: "pthread_mutexattr_settype", header: "<pthread.h>", noSideEffect.}
 
   else:
-    proc initSysCondAux(cond: var SysCondObj, cond_attr: pointer) {.
+    proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {.
       importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
     proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
       importc: "pthread_cond_destroy", header: "<pthread.h>".}
@@ -196,7 +202,7 @@ else:
       importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
 
     when defined(ios):
-      proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
+      proc initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
         cond = cast[SysCond](c_malloc(sizeof(SysCondObj)))
         initSysCondAux(cond[], cond_attr)
 
@@ -209,7 +215,7 @@ else:
       template signalSysCond(cond: var SysCond) =
         signalSysCondAux(cond[])
     else:
-      template initSysCond(cond: var SysCond, cond_attr: pointer = nil) =
+      template initSysCond(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
         initSysCondAux(cond, cond_attr)
       template deinitSysCond(cond: var SysCond) =
         deinitSysCondAux(cond)
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index d1012e9c5..49b13576c 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -264,7 +264,17 @@ else:
 
     proc getThreadId*(): int =
       result = int(lwp_gettid())
-  elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  elif defined(openbsd):
+    proc getthrid(): int32 {.importc: "getthrid", header: "<unistd.h>".}
+
+    proc getThreadId*(): int =
+      result = int(getthrid())
+  elif defined(netbsd):
+    proc lwp_self(): int32 {.importc: "_lwp_self", header: "<lwp.h>".}
+
+    proc getThreadId*(): int =
+      result = int(lwp_self())
+  elif defined(macosx) or defined(freebsd):
     proc pthread_threadid_np(y: pointer; x: var uint64): cint {.importc, header: "pthread.h".}
 
     proc getThreadId*(): int =
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 164499543..7a221ceb1 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -291,6 +291,14 @@ const
   FILE_ATTRIBUTE_TEMPORARY* = 256'i32
 
   MAX_PATH* = 260
+
+  MOVEFILE_COPY_ALLOWED* = 0x2'i32
+  MOVEFILE_CREATE_HARDLINK* = 0x10'i32
+  MOVEFILE_DELAY_UNTIL_REBOOT* = 0x4'i32
+  MOVEFILE_FAIL_IF_NOT_TRACKABLE* = 0x20'i32
+  MOVEFILE_REPLACE_EXISTING* = 0x1'i32
+  MOVEFILE_WRITE_THROUGH* = 0x8'i32
+
 type
   WIN32_FIND_DATA* {.pure.} = object
     dwFileAttributes*: int32
@@ -342,6 +350,9 @@ when useWinUnicode:
 
   proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {.
     importc: "MoveFileW", stdcall, dynlib: "kernel32".}
+  proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString,
+                    flags: DWORD): WINBOOL {.
+    importc: "MoveFileExW", stdcall, dynlib: "kernel32".}
 
   proc getEnvironmentStringsW*(): WideCString {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
@@ -369,6 +380,9 @@ else:
 
   proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {.
     importc: "MoveFileA", stdcall, dynlib: "kernel32".}
+  proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString,
+                    flags: DWORD): WINBOOL {.
+    importc: "MoveFileExA", stdcall, dynlib: "kernel32".}
 
   proc getEnvironmentStringsA*(): cstring {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 5521476d9..ff18fc2c2 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -26,7 +26,7 @@ when useWinVersion:
   from winlean import SocketHandle
 else:
   const
-    versions = "(|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
+    versions = "(|.38|.39|.41|.43|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
   when defined(macosx):
     const
       DLLSSLName = "libssl" & versions & ".dylib"