summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--changelog.md7
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/cgen.nim10
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/sighashes.nim25
-rw-r--r--lib/genode/alloc.nim (renamed from lib/system/genodealloc.nim)43
-rw-r--r--lib/genode/env.nim29
-rw-r--r--lib/genode_cpp/threads.h1
-rw-r--r--lib/nimbase.h5
-rw-r--r--lib/pure/asynchttpserver.nim17
-rw-r--r--lib/pure/collections/critbits.nim25
-rw-r--r--lib/pure/concurrency/cpuinfo.nim8
-rw-r--r--lib/pure/net.nim2
-rw-r--r--lib/pure/os.nim2
-rw-r--r--lib/pure/strutils.nim81
-rw-r--r--lib/pure/unicode.nim114
-rw-r--r--lib/system.nim37
-rw-r--r--lib/system/osalloc.nim2
-rw-r--r--lib/system/threads.nim7
-rw-r--r--lib/wrappers/openssl.nim4
-rw-r--r--tests/cpp/tempty_generic_obj.nim16
-rw-r--r--tests/generics/t3977.nim14
-rw-r--r--tests/stdlib/tnet.nim12
24 files changed, 361 insertions, 106 deletions
diff --git a/.travis.yml b/.travis.yml
index 3bc9a9778..b7880cd36 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,6 +25,8 @@ before_install:
 
 before_script:
   - set -e
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then unset -f cd; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then shell_session_update() { :; }; fi
   - git clone --depth 1 https://github.com/nim-lang/csources.git
   - cd csources
   - sh build.sh
diff --git a/changelog.md b/changelog.md
index 5ba277898..959990900 100644
--- a/changelog.md
+++ b/changelog.md
@@ -42,6 +42,12 @@
 - ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
   (previously it used floor division like Python). Use ``math.floorMod`` for the old behavior.
 
+- For string inputs, ``unicode.isUpper`` and ``unicode.isLower`` now require a
+  second mandatory parameter ``skipNonAlpha``.
+
+- For string inputs, ``strutils.isUpperAscii`` and ``strutils.isLowerAscii`` now
+  require a second mandatory parameter ``skipNonAlpha``.
+
 #### Breaking changes in the compiler
 
 - The undocumented ``#? braces`` parsing mode was removed.
@@ -91,6 +97,7 @@
   API". Using the Nim compiler and its VM as a scripting engine has never been
   easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
   use the Nim VM in a native Nim application.
+- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc.
 - The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated.
 
 
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index d0433f9ae..82508e37e 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -731,8 +731,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
     else: addAbiCheck(m, t, result)
   of tyObject, tyTuple:
     if isImportedCppType(t) and origTyp.kind == tyGenericInst:
-      # for instantiated templates we do not go through the type cache as the
-      # the type cache is not aware of 'tyGenericInst'.
       let cppName = getTypeName(m, t, sig)
       var i = 0
       var chunkStart = 0
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index c66b25b00..ee60e62d2 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1036,14 +1036,19 @@ proc genMainProc(m: BModule) =
       "}$N$N"
 
     GenodeNimMain =
-      "Libc::Env *genodeEnv;$N" &
+      "extern Genode::Env *nim_runtime_env;$N" &
+      "extern void nim_component_construct(Genode::Env*);$N$N" &
       NimMainBody
 
     ComponentConstruct =
       "void Libc::Component::construct(Libc::Env &env) {$N" &
-      "\tgenodeEnv = &env;$N" &
+      "\t// Set Env used during runtime initialization$N" &
+      "\tnim_runtime_env = &env;$N" &
       "\tLibc::with_libc([&] () {$N\t" &
+      "\t// Initialize runtime and globals$N" &
       MainProcs &
+      "\t// Call application construct$N" &
+      "\t\tnim_component_construct(&env);$N" &
       "\t});$N" &
       "}$N$N"
 
@@ -1060,6 +1065,7 @@ proc genMainProc(m: BModule) =
   elif m.config.target.targetOS == osGenode:
     nimMain = GenodeNimMain
     otherMain = ComponentConstruct
+    m.includeHeader("<libc/component.h>")
   elif optGenDynLib in m.config.globalOptions:
     nimMain = PosixNimDllMain
     otherMain = PosixCDllMain
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 0e143e7c1..af853ec52 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -496,7 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           def = fitNode(c, typ, def, def.info)
           #changeType(def.skipConv, typ, check=true)
       else:
-        typ = skipIntLit(def.typ)
+        typ = def.typ.skipTypes({tyStatic}).skipIntLit
         if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass:
           typ = typ.lastSon
         if hasEmpty(typ):
diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim
index 46b83c386..0b95387cd 100644
--- a/compiler/sighashes.nim
+++ b/compiler/sighashes.nim
@@ -12,7 +12,7 @@
 import ast, md5, tables, ropes
 from hashes import Hash
 from astalgo import debug
-from types import typeToString, preferDesc
+import types
 from strutils import startsWith, contains
 
 when false:
@@ -148,19 +148,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
   of tyGenericInvocation:
     for i in countup(0, sonsLen(t) - 1):
       c.hashType t.sons[i], flags
-    return
   of tyDistinct:
     if CoType in flags:
       c.hashType t.lastSon, flags
     else:
       c.hashSym(t.sym)
-    return
-  of tyAlias, tySink, tyGenericInst, tyUserTypeClasses:
+  of tyGenericInst:
+    if sfInfixCall in t.base.sym.flags:
+      # This is an imported C++ generic type.
+      # We cannot trust the `lastSon` to hold a properly populated and unique
+      # value for each instantiation, so we hash the generic parameters here:
+      let normalizedType = t.skipGenericAlias
+      for i in 0 .. normalizedType.len - 2:
+        c.hashType t.sons[i], flags
+    else:
+      c.hashType t.lastSon, flags
+  of tyAlias, tySink, tyUserTypeClasses:
     c.hashType t.lastSon, flags
-    return
-  else:
-    discard
-  case t.kind
   of tyBool, tyChar, tyInt..tyUInt64:
     # no canonicalization for integral types, so that e.g. ``pid_t`` is
     # produced instead of ``NI``:
@@ -168,11 +172,12 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
     if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
       c.hashSym(t.sym)
   of tyObject, tyEnum:
-    c &= char(t.kind)
     if t.typeInst != nil:
       assert t.typeInst.kind == tyGenericInst
-      for i in countup(1, sonsLen(t.typeInst) - 2):
+      for i in countup(0, sonsLen(t.typeInst) - 2):
         c.hashType t.typeInst.sons[i], flags
+      return
+    c &= char(t.kind)
     # Every cyclic type in Nim need to be constructed via some 't.sym', so this
     # is actually safe without an infinite recursion check:
     if t.sym != nil:
diff --git a/lib/system/genodealloc.nim b/lib/genode/alloc.nim
index 3646a842d..52dc1c32c 100644
--- a/lib/system/genodealloc.nim
+++ b/lib/genode/alloc.nim
@@ -8,10 +8,15 @@
 #
 
 # Low level dataspace allocator for Genode.
+# For interacting with dataspaces outside of the
+# standard library see the Genode Nimble package.
 
 when not defined(genode):
   {.error: "Genode only module".}
 
+when not declared(GenodeEnv):
+  include genode/env
+
 type DataspaceCapability {.
   importcpp: "Genode::Dataspace_capability", pure.} = object
 
@@ -31,35 +36,35 @@ type
 
 const SlabBackendSize = 4096
 
-proc ramAvail(): int {.
-  importcpp: "genodeEnv->pd().avail_ram().value".}
+proc ramAvail(env: GenodeEnv): int {.
+  importcpp: "#->pd().avail_ram().value".}
   ## Return number of bytes available for allocation.
 
-proc capsAvail(): int {.
-  importcpp: "genodeEnv->pd().avail_caps().value".}
+proc capsAvail(env: GenodeEnv): int {.
+  importcpp: "#->pd().avail_caps().value".}
   ## Return the number of available capabilities.
   ## Each dataspace allocation consumes a capability.
 
-proc allocDataspace(size: int): DataspaceCapability {.
-  importcpp: "genodeEnv->pd().alloc(@)".}
+proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {.
+  importcpp: "#->pd().alloc(@)".}
   ## Allocate a dataspace and its capability.
 
-proc attachDataspace(ds: DataspaceCapability): pointer {.
-  importcpp: "genodeEnv->rm().attach(@)".}
+proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {.
+  importcpp: "#->rm().attach(@)".}
   ## Attach a dataspace into the component address-space.
 
-proc detachAddress(p: pointer) {.
-  importcpp: "genodeEnv->rm().detach(@)".}
+proc detachAddress(env: GenodeEnv; p: pointer) {.
+  importcpp: "#->rm().detach(@)".}
   ## Detach a dataspace from the component address-space.
 
-proc freeDataspace(ds: DataspaceCapability) {.
-  importcpp: "genodeEnv->pd().free(@)".}
+proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {.
+  importcpp: "#->pd().free(@)".}
   ## Free a dataspace.
 
 proc newMapSlab(): ptr MapSlab =
   let
-    ds = allocDataspace SlabBackendSize
-    p = attachDataspace ds
+    ds = runtimeEnv.allocDataspace SlabBackendSize
+    p = runtimeEnv.attachDataspace ds
   result = cast[ptr MapSlab](p)
   result.meta.ds = ds
 
@@ -89,13 +94,13 @@ proc osAllocPages(size: int): pointer =
           # tack a new slab on the tail
       slab = slab.meta.next
         # move to next slab in linked list
-  map.ds = allocDataspace size
+  map.ds = runtimeEnv.allocDataspace size
   map.size = size
-  map.attachment = attachDataspace map.ds
+  map.attachment = runtimeEnv.attachDataspace map.ds
   result = map.attachment
 
 proc osTryAllocPages(size: int): pointer =
-  if ramAvail() >= size and capsAvail() > 1:
+  if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
     result = osAllocPages size
 
 proc osDeallocPages(p: pointer; size: int) =
@@ -107,8 +112,8 @@ proc osDeallocPages(p: pointer; size: int) =
         if m.size != size:
           echo "cannot partially detach dataspace"
           quit -1
-        detachAddress m.attachment
-        freeDataspace m.ds
+        runtimeEnv.detachAddress m.attachment
+        runtimeEnv.freeDataspace m.ds
         m[] = Map()
         return
     slab = slab.meta.next
diff --git a/lib/genode/env.nim b/lib/genode/env.nim
new file mode 100644
index 000000000..2b180d1b3
--- /dev/null
+++ b/lib/genode/env.nim
@@ -0,0 +1,29 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Emery Hemingway
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#
+# This file contains the minimum required definitions
+# for interacting with the initial Genode environment.
+# It is reserved for use only within the standard
+# library. See ``componentConstructHook`` in the system
+# module for accessing the Genode environment after the
+# standard library has finished initializating.
+#
+
+when not defined(genode):
+  {.error: "Genode only include".}
+
+type
+  GenodeEnvObj {.importcpp: "Genode::Env", header: "<base/env.h>", pure.} = object
+  GenodeEnvPtr = ptr GenodeEnvObj
+
+const runtimeEnvSym = "nim_runtime_env"
+
+when not defined(nimscript):
+  var runtimeEnv {.importcpp: runtimeEnvSym.}: GenodeEnvPtr
diff --git a/lib/genode_cpp/threads.h b/lib/genode_cpp/threads.h
index a7cb2f17b..c901efb45 100644
--- a/lib/genode_cpp/threads.h
+++ b/lib/genode_cpp/threads.h
@@ -13,6 +13,7 @@
 #define _GENODE_CPP__THREAD_H_
 
 #include <base/thread.h>
+#include <base/env.h>
 #include <util/reconstructible.h>
 
 namespace Nim { struct SysThread; }
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 20ac9979b..6dc742910 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -502,11 +502,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz
 #  include <sys/types.h>
 #endif
 
-#if defined(__GENODE__)
-#include <libc/component.h>
-extern Libc::Env *genodeEnv;
-#endif
-
 /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
 #define NIM_CHECK_SIZE(typ, sz) \
   _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index fe5a835d7..d27c2fb9c 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -129,6 +129,20 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
 proc sendStatus(client: AsyncSocket, status: string): Future[void] =
   client.send("HTTP/1.1 " & status & "\c\L\c\L")
 
+proc parseUppercaseMethod(name: string): HttpMethod =
+  result =
+    case name
+    of "GET": HttpGet
+    of "POST": HttpPost
+    of "HEAD": HttpHead
+    of "PUT": HttpPut
+    of "DELETE": HttpDelete
+    of "PATCH": HttpPatch
+    of "OPTIONS": HttpOptions
+    of "CONNECT": HttpConnect
+    of "TRACE": HttpTrace
+    else: raise newException(ValueError, "Invalid HTTP method " & name)
+
 proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
                     client: AsyncSocket,
                     address: string, lineFut: FutureVar[string],
@@ -172,8 +186,7 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
     case i
     of 0:
       try:
-        # TODO: this is likely slow.
-        request.reqMethod = parseEnum[HttpMethod]("http" & linePart)
+        request.reqMethod = parseUppercaseMethod(linePart)
       except ValueError:
         asyncCheck request.respondError(Http400)
         return
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index eaba257ae..c94e08098 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -165,16 +165,18 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
 
 proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) =
   ## increments `c[key]` by `val`.
-  let oldCount = c.count
   var n = rawInsert(c, key)
-  if c.count >= oldCount or oldCount == 0:
-    # not a new key:
-    inc n.val, val
+  inc n.val, val
 
 proc incl*(c: var CritBitTree[void], key: string) =
   ## includes `key` in `c`.
   discard rawInsert(c, key)
 
+proc incl*[T](c: var CritBitTree[T], key: string, val: T) =
+  ## inserts `key` with value `val` into `c`.
+  var n = rawInsert(c, key)
+  n.val = val
+
 proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
   ## puts a (key, value)-pair into `t`.
   var n = rawInsert(c, key)
@@ -375,3 +377,18 @@ when isMainModule:
 
   c.inc("a", 1)
   assert c["a"] == 1
+
+  var cf = CritBitTree[float]()
+
+  cf.incl("a", 1.0)
+  assert cf["a"] == 1.0
+
+  cf.incl("b", 2.0)
+  assert cf["b"] == 2.0
+
+  cf.incl("c", 3.0)
+  assert cf["c"] == 3.0
+
+  assert cf.len == 3
+  cf.excl("c")
+  assert cf.len == 2
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index f01488811..6d41aa1b2 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -38,8 +38,10 @@ when defined(macosx) or defined(bsd):
               importc: "sysctl", nodecl.}
 
 when defined(genode):
-  proc affinitySpaceTotal(): cuint {.
-    importcpp: "genodeEnv->cpu().affinity_space().total()".}
+  include genode/env
+
+  proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
+    importcpp: "@->cpu().affinity_space().total()".}
 
 proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
   ## returns the numer of the processors/cores the machine has.
@@ -83,7 +85,7 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
     result = sysconf(SC_NPROC_ONLN)
   elif defined(genode):
-    result = affinitySpaceTotal().int
+    result = runtimeEnv.affinitySpaceTotal().int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
   if result <= 0: result = 0
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 60817484a..5d2efebee 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -447,7 +447,7 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6,
     sl: Socklen, address: var IpAddress, port: var Port) {.inline.} =
   ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises
   ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments.
-  fromSockAddrAux(unsafeAddr sa, sl, address, port)
+  fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port)
 
 when defineSsl:
   CRYPTO_malloc_init()
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 696313e4d..3bc87728b 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1440,7 +1440,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     elif defined(solaris):
       result = getApplAux("/proc/" & $getpid() & "/path/a.out")
     elif defined(genode):
-      raiseOSError("POSIX command line not supported")
+      raiseOSError(OSErrorCode(-1), "POSIX command line not supported")
     elif defined(freebsd) or defined(dragonfly):
       result = getApplFreebsd()
     # little heuristic that may work on other POSIX-like systems:
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index a4fd20fdb..bea0a0243 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -150,23 +150,52 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
   ## characters and there is at least one character in `s`.
   isImpl isSpaceAscii
 
-proc isLowerAscii*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsLowerAsciiStr".} =
-  ## Checks whether or not `s` contains all lower case characters.
+template isCaseImpl(s, charProc, skipNonAlpha) =
+  var hasAtleastOneAlphaChar = false
+  if s.len == 0: return false
+  for c in s:
+    if skipNonAlpha:
+      var charIsAlpha = c.isAlphaAscii()
+      if not hasAtleastOneAlphaChar:
+        hasAtleastOneAlphaChar = charIsAlpha
+      if charIsAlpha and (not charProc(c)):
+        return false
+    else:
+      if not charProc(c):
+        return false
+  return if skipNonAlpha: hasAtleastOneAlphaChar else: true
+
+proc isLowerAscii*(s: string, skipNonAlpha: bool): bool =
+  ## Checks whether ``s`` is lower case.
   ##
   ## This checks ASCII characters only.
-  ## Returns true if all characters in `s` are lower case
-  ## and there is at least one character  in `s`.
-  isImpl isLowerAscii
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## characters in ``s`` are lower case.  Returns false if none of the
+  ## characters in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all characters
+  ## in ``s`` are alphabetical and lower case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  isCaseImpl(s, isLowerAscii, skipNonAlpha)
 
-proc isUpperAscii*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nsuIsUpperAsciiStr".} =
-  ## Checks whether or not `s` contains all upper case characters.
+proc isUpperAscii*(s: string, skipNonAlpha: bool): bool =
+  ## Checks whether ``s`` is upper case.
   ##
   ## This checks ASCII characters only.
-  ## Returns true if all characters in `s` are upper case
-  ## and there is at least one character in `s`.
-  isImpl isUpperAscii
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## characters in ``s`` are upper case.  Returns false if none of the
+  ## characters in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all characters
+  ## in ``s`` are alphabetical and upper case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  isCaseImpl(s, isUpperAscii, skipNonAlpha)
 
 proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerAsciiChar".} =
@@ -2516,19 +2545,34 @@ when isMainModule:
     doAssert(not isLowerAscii('A'))
     doAssert(not isLowerAscii('5'))
     doAssert(not isLowerAscii('&'))
+    doAssert(not isLowerAscii(' '))
 
-    doAssert isLowerAscii("abcd")
-    doAssert(not isLowerAscii("abCD"))
-    doAssert(not isLowerAscii("33aa"))
+    doAssert isLowerAscii("abcd", false)
+    doAssert(not isLowerAscii("33aa", false))
+    doAssert(not isLowerAscii("a b", false))
+
+    doAssert(not isLowerAscii("abCD", true))
+    doAssert isLowerAscii("33aa", true)
+    doAssert isLowerAscii("a b", true)
+    doAssert isLowerAscii("1, 2, 3 go!", true)
+    doAssert(not isLowerAscii(" ", true))
+    doAssert(not isLowerAscii("(*&#@(^#$ ", true)) # None of the string chars are alphabets
 
     doAssert isUpperAscii('A')
     doAssert(not isUpperAscii('b'))
     doAssert(not isUpperAscii('5'))
     doAssert(not isUpperAscii('%'))
 
-    doAssert isUpperAscii("ABC")
-    doAssert(not isUpperAscii("AAcc"))
-    doAssert(not isUpperAscii("A#$"))
+    doAssert isUpperAscii("ABC", false)
+    doAssert(not isUpperAscii("A#$", false))
+    doAssert(not isUpperAscii("A B", false))
+
+    doAssert(not isUpperAscii("AAcc", true))
+    doAssert isUpperAscii("A#$", true)
+    doAssert isUpperAscii("A B", true)
+    doAssert isUpperAscii("1, 2, 3 GO!", true)
+    doAssert(not isUpperAscii(" ", true))
+    doAssert(not isUpperAscii("(*&#@(^#$ ", true)) # None of the string chars are alphabets
 
     doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
     doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
@@ -2601,4 +2645,3 @@ bar
   nonStaticTests()
   staticTests()
   static: staticTests()
-
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index bfd01be55..978f569ac 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -1392,7 +1392,7 @@ proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
     (c >= 0xfe20 and c <= 0xfe2f))
 
 template runeCheck(s, runeProc) =
-  ## Common code for rune.isLower, rune.isUpper, etc
+  ## Common code for isAlpha and isSpace.
   result = if len(s) == 0: false else: true
 
   var
@@ -1403,16 +1403,6 @@ template runeCheck(s, runeProc) =
     fastRuneAt(s, i, rune, doInc=true)
     result = runeProc(rune) and result
 
-proc isUpper*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nuc$1Str".} =
-  ## Returns true iff `s` contains all upper case unicode characters.
-  runeCheck(s, isUpper)
-
-proc isLower*(s: string): bool {.noSideEffect, procvar,
-  rtl, extern: "nuc$1Str".} =
-  ## Returns true iff `s` contains all lower case unicode characters.
-  runeCheck(s, isLower)
-
 proc isAlpha*(s: string): bool {.noSideEffect, procvar,
   rtl, extern: "nuc$1Str".} =
   ## Returns true iff `s` contains all alphabetic unicode characters.
@@ -1423,6 +1413,56 @@ proc isSpace*(s: string): bool {.noSideEffect, procvar,
   ## Returns true iff `s` contains all whitespace unicode characters.
   runeCheck(s, isWhiteSpace)
 
+template runeCaseCheck(s, runeProc, skipNonAlpha) =
+  ## Common code for rune.isLower and rune.isUpper.
+  if len(s) == 0: return false
+
+  var
+    i = 0
+    rune: Rune
+    hasAtleastOneAlphaRune = false
+
+  while i < len(s):
+    fastRuneAt(s, i, rune, doInc=true)
+    if skipNonAlpha:
+      var runeIsAlpha = isAlpha(rune)
+      if not hasAtleastOneAlphaRune:
+        hasAtleastOneAlphaRune = runeIsAlpha
+      if runeIsAlpha and (not runeProc(rune)):
+        return false
+    else:
+      if not runeProc(rune):
+        return false
+  return if skipNonAlpha: hasAtleastOneAlphaRune else: true
+
+proc isLower*(s: string, skipNonAlpha: bool): bool =
+  ## Checks whether ``s`` is lower case.
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## runes in ``s`` are lower case.  Returns false if none of the
+  ## runes in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all runes in
+  ## ``s`` are alphabetical and lower case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  runeCaseCheck(s, isLower, skipNonAlpha)
+
+proc isUpper*(s: string, skipNonAlpha: bool): bool =
+  ## Checks whether ``s`` is upper case.
+  ##
+  ## If ``skipNonAlpha`` is true, returns true if all alphabetical
+  ## runes in ``s`` are upper case.  Returns false if none of the
+  ## runes in ``s`` are alphabetical.
+  ##
+  ## If ``skipNonAlpha`` is false, returns true only if all runes in
+  ## ``s`` are alphabetical and upper case.
+  ##
+  ## For either value of ``skipNonAlpha``, returns false if ``s`` is
+  ## an empty string.
+  runeCaseCheck(s, isUpper, skipNonAlpha)
+
 template convertRune(s, runeProc) =
   ## Convert runes in `s` using `runeProc` as the converter.
   result = newString(len(s))
@@ -1755,25 +1795,39 @@ when isMainModule:
   doAssert(not isSpace(""))
   doAssert(not isSpace("ΑΓc   \td"))
 
-  doAssert isLower("a")
-  doAssert isLower("γ")
-  doAssert(not isLower("Γ"))
-  doAssert(not isLower("4"))
-  doAssert(not isLower(""))
-
-  doAssert isLower("abcdγ")
-  doAssert(not isLower("abCDΓ"))
-  doAssert(not isLower("33aaΓ"))
-
-  doAssert isUpper("Γ")
-  doAssert(not isUpper("b"))
-  doAssert(not isUpper("α"))
-  doAssert(not isUpper("✓"))
-  doAssert(not isUpper(""))
-
-  doAssert isUpper("ΑΒΓ")
-  doAssert(not isUpper("AAccβ"))
-  doAssert(not isUpper("A#$β"))
+  doAssert(not isLower(' '.Rune))
+
+  doAssert isLower("a", false)
+  doAssert isLower("γ", true)
+  doAssert(not isLower("Γ", false))
+  doAssert(not isLower("4", true))
+  doAssert(not isLower("", false))
+  doAssert isLower("abcdγ", false)
+  doAssert(not isLower("33aaΓ", false))
+  doAssert(not isLower("a b", false))
+
+  doAssert(not isLower("abCDΓ", true))
+  doAssert isLower("a b", true)
+  doAssert isLower("1, 2, 3 go!", true)
+  doAssert(not isLower(" ", true))
+  doAssert(not isLower("(*&#@(^#$✓ ", true)) # None of the string runes are alphabets
+
+  doAssert(not isUpper(' '.Rune))
+
+  doAssert isUpper("Γ", false)
+  doAssert(not isUpper("α", false))
+  doAssert(not isUpper("", false))
+  doAssert isUpper("ΑΒΓ", false)
+  doAssert(not isUpper("A#$β", false))
+  doAssert(not isUpper("A B", false))
+
+  doAssert(not isUpper("b", true))
+  doAssert(not isUpper("✓", true))
+  doAssert(not isUpper("AAccβ", true))
+  doAssert isUpper("A B", true)
+  doAssert isUpper("1, 2, 3 GO!", true)
+  doAssert(not isUpper(" ", true))
+  doAssert(not isUpper("(*&#@(^#$✓ ", true)) # None of the string runes are alphabets
 
   doAssert toUpper("Γ") == "Γ"
   doAssert toUpper("b") == "B"
diff --git a/lib/system.nim b/lib/system.nim
index fee9dc314..fb02fde23 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1498,11 +1498,21 @@ when defined(nimdoc):
     ## macro, use the `error <manual.html#error-pragma>`_ or `fatal
     ## <manual.html#fatal-pragma>`_ pragmas.
 
-
 elif defined(genode):
-  proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn,
-    importcpp: "genodeEnv->parent().exit(@); Genode::sleep_forever()",
-    header: "<base/sleep.h>".}
+  include genode/env
+
+  var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr
+
+  type GenodeEnv* = GenodeEnvPtr
+    ## Opaque type representing Genode environment.
+
+  proc quit*(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn,
+    importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "<base/sleep.h>".}
+
+  proc quit*(errorcode: int = QuitSuccess) =
+    systemEnv.quit(errorCode)
+
+
 
 elif defined(nodejs):
   proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
@@ -4215,3 +4225,22 @@ when not defined(js):
 type
   ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro
                                          ## as a `for-loop macro`:idx:
+
+when defined(genode):
+  var componentConstructHook*: proc (env: GenodeEnv) {.nimcall.}
+      ## Hook into the Genode component bootstrap process.
+      ## This hook is called after all globals are initialized.
+      ## When this hook is set the component will not automatically exit,
+      ## call ``quit`` explicitly to do so. This is the only available method
+      ## of accessing the initial Genode environment.
+
+  proc nim_component_construct(env: GenodeEnv) {.exportc.} =
+    ## Procedure called during ``Component::construct`` by the loader.
+    if componentConstructHook.isNil:
+      env.quit(programResult)
+        # No native Genode application initialization,
+        # exit as would POSIX.
+    else:
+      componentConstructHook(env)
+        # Perform application initialization
+        # and return to thread entrypoint.
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index 9609b6d39..a63eadf8e 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -78,7 +78,7 @@ when defined(emscripten):
     munmap(mmapDescr.realPointer, mmapDescr.realSize)
 
 elif defined(genode):
-  include genodealloc # osAllocPages, osTryAllocPages, osDeallocPages
+  include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages
 
 elif defined(posix):
   const
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 861bde13f..c8ea03f92 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -116,6 +116,7 @@ when defined(windows):
     importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}
 
 elif defined(genode):
+  import genode/env
   const
     GenodeHeader = "genode_cpp/threads.h"
   type
@@ -125,11 +126,12 @@ elif defined(genode):
     ThreadVarSlot = int
 
   proc initThread(s: var SysThread,
+                  env: GenodeEnv,
                   stackSize: culonglong,
                   entry: GenodeThreadProc,
                   arg: pointer,
                   affinity: cuint) {.
-    importcpp: "#.initThread(genodeEnv, @)".}
+    importcpp: "#.initThread(@)".}
 
   proc threadVarAlloc(): ThreadVarSlot = 0
 
@@ -569,7 +571,7 @@ when hostOS == "windows":
 
 elif defined(genode):
   var affinityOffset: cuint = 1
-  # CPU affinity offset for next thread, safe to roll-over
+    ## CPU affinity offset for next thread, safe to roll-over
 
   proc createThread*[TArg](t: var Thread[TArg],
                            tp: proc (arg: TArg) {.thread, nimcall.},
@@ -580,6 +582,7 @@ elif defined(genode):
     t.dataFn = tp
     when hasSharedHeap: t.stackSize = ThreadStackSize
     t.sys.initThread(
+      runtimeEnv,
       ThreadStackSize.culonglong,
       threadProcWrapper[TArg], addr(t), affinityOffset)
     inc affinityOffset
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index a24575d11..de3bfa616 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -44,6 +44,10 @@ else:
     const
       DLLSSLName* = "libssl" & versions & ".dylib"
       DLLUtilName* = "libcrypto" & versions & ".dylib"
+  elif defined(genode):
+    const
+      DLLSSLName* = "libssl.lib.so"
+      DLLUtilName* = "libcrypto.lib.so"
   else:
     const
       DLLSSLName* = "libssl.so" & versions
diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim
index b4c746a30..b61c699f6 100644
--- a/tests/cpp/tempty_generic_obj.nim
+++ b/tests/cpp/tempty_generic_obj.nim
@@ -20,3 +20,19 @@ v.doSomething()
 
 var vf = initVector[float]()
 vf.doSomething() # Nim uses doSomething[int] here in C++
+
+# Alternative definition:
+# https://github.com/nim-lang/Nim/issues/7653
+
+type VectorAlt* {.importcpp: "std::vector", header: "<vector>", nodecl.} [T] = object
+proc mkVector*[T]: VectorAlt[T] {.importcpp: "std::vector<'*0>()", header: "<vector>", constructor, nodecl.}
+
+proc foo(): VectorAlt[cint] =
+  mkVector[cint]()
+
+proc bar(): VectorAlt[cstring] =
+  mkVector[cstring]()
+
+var x = foo()
+var y = bar()
+
diff --git a/tests/generics/t3977.nim b/tests/generics/t3977.nim
new file mode 100644
index 000000000..eed1a7d63
--- /dev/null
+++ b/tests/generics/t3977.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "42\n42"
+"""
+
+type
+  Foo[N: static[int]] = object
+
+proc foo[N](x: Foo[N]) =
+  let n = N
+  echo N
+  echo n
+
+var f1: Foo[42]
+f1.foo
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
index 64d690fc9..d364447da 100644
--- a/tests/stdlib/tnet.nim
+++ b/tests/stdlib/tnet.nim
@@ -66,6 +66,18 @@ block: # "IpAddress/Sockaddr conversion"
     doAssert(ipaddr_1 == ipaddr_2)
     doAssert($ipaddr_1 == $ipaddr_2)
 
+    if sockaddr.ss_family == AF_INET.toInt:
+      var sockaddr4: Sockaddr_in
+      copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
+      fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
+    elif sockaddr.ss_family == AF_INET6.toInt:
+      var sockaddr6: Sockaddr_in6
+      copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
+      fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)
+
+    doAssert(ipaddr_1 == ipaddr_2)
+    doAssert($ipaddr_1 == $ipaddr_2)
+
 
   # ipv6 address of example.com
   test("2606:2800:220:1:248:1893:25c8:1946")