summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorIco Doornekamp <ico@pruts.nl>2020-01-23 14:25:22 +0100
committerAndreas Rumpf <rumpf_a@web.de>2020-01-23 14:25:22 +0100
commitb68eb1cad0dc13d497ae0e620dd2178a6367644c (patch)
tree4456c09a2cf5a964cc1d6cb2cae16dabfa0ff2a8 /lib/system
parentf500895efe84525c131beadd2e83b30caa6674a3 (diff)
downloadNim-b68eb1cad0dc13d497ae0e620dd2178a6367644c.tar.gz
Removed lib/system/allocators.nim. seqs_v2 and strs_v2 now uses allocShared0. (#13190)
* Cleanup, remove lib/system/allocators.nim. seqs_v2 and strs_v2 now use
allocShared0 by default.

* Fixed -d:useMalloc allocShared / reallocShared / deallocShared. These now use the alloc/dealloc/realloc implementation that also takes care of zeroing memory at realloc.

* Removed debug printfs

* Removed unpairedEnvAllocs() from tests/destructor/tnewruntime_misc

* More mmdisp cleanups. The shared allocators do not need to zero memory or throw since the regular ones already do that

* Introduced realloc0 and reallocShared0, these procs are now used by
strs_v2 and seqs_v2. This also allowed the -d:useMalloc allocator to
drop the extra header with allocation length.

* Moved strs_v2/seqs_v2 'allocated' flag into 'cap' field

* Added 'getAllocStats()' to get low level alloc/dealloc counters. Enable with -d:allocStats

* *allocShared implementations for boehm and go allocators now depend on the proper *allocImpl procs
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/alloc.nim44
-rw-r--r--lib/system/allocators.nim86
-rw-r--r--lib/system/ansi_c.nim2
-rw-r--r--lib/system/gc_regions.nim26
-rw-r--r--lib/system/memalloc.nim115
-rw-r--r--lib/system/mmdisp.nim103
-rw-r--r--lib/system/seqs_v2.nim44
-rw-r--r--lib/system/strs_v2.nim52
-rw-r--r--lib/system/widestrs.nim8
9 files changed, 234 insertions, 246 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index c65abe5c2..59b7fcfd9 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -948,13 +948,18 @@ proc dealloc(allocator: var MemRegion, p: pointer) =
 
 proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
   if newsize > 0:
-    result = alloc0(allocator, newsize)
+    result = alloc(allocator, newsize)
     if p != nil:
       copyMem(result, p, min(ptrSize(p), newsize))
       dealloc(allocator, p)
   elif p != nil:
     dealloc(allocator, p)
 
+proc realloc0(allocator: var MemRegion, p: pointer, oldsize, newsize: Natural): pointer =
+  result = realloc(allocator, p, newsize)
+  if newsize > oldsize:
+    zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
+
 proc deallocOsPages(a: var MemRegion) =
   # we free every 'ordinarily' allocated page by iterating over the page bits:
   var it = addr(a.heapLinks)
@@ -997,17 +1002,22 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
 
   proc deallocOsPages = deallocOsPages(allocator)
 
-  proc alloc(size: Natural): pointer =
+  proc allocImpl(size: Natural): pointer =
     result = alloc(allocator, size)
 
-  proc alloc0(size: Natural): pointer =
+  proc alloc0Impl(size: Natural): pointer =
     result = alloc0(allocator, size)
 
-  proc dealloc(p: pointer) =
+  proc deallocImpl(p: pointer) =
     dealloc(allocator, p)
 
-  proc realloc(p: pointer, newSize: Natural): pointer =
+  proc reallocImpl(p: pointer, newSize: Natural): pointer =
+    result = realloc(allocator, p, newSize)
+
+  proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer =
     result = realloc(allocator, p, newSize)
+    if newSize > oldSize:
+      zeroMem(cast[pointer](cast[int](result) + oldSize), newSize - oldSize)
 
   when false:
     proc countFreeMem(): int =
@@ -1034,33 +1044,41 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
     var heapLock: SysLock
     initSysLock(heapLock)
 
-  proc allocShared(size: Natural): pointer =
+  proc allocSharedImpl(size: Natural): pointer =
     when hasThreadSupport:
       acquireSys(heapLock)
       result = alloc(sharedHeap, size)
       releaseSys(heapLock)
     else:
-      result = alloc(size)
+      result = allocImpl(size)
 
-  proc allocShared0(size: Natural): pointer =
-    result = allocShared(size)
+  proc allocShared0Impl(size: Natural): pointer =
+    result = allocSharedImpl(size)
     zeroMem(result, size)
 
-  proc deallocShared(p: pointer) =
+  proc deallocSharedImpl(p: pointer) =
     when hasThreadSupport:
       acquireSys(heapLock)
       dealloc(sharedHeap, p)
       releaseSys(heapLock)
     else:
-      dealloc(p)
+      deallocImpl(p)
 
-  proc reallocShared(p: pointer, newSize: Natural): pointer =
+  proc reallocSharedImpl(p: pointer, newSize: Natural): pointer =
     when hasThreadSupport:
       acquireSys(heapLock)
       result = realloc(sharedHeap, p, newSize)
       releaseSys(heapLock)
     else:
-      result = realloc(p, newSize)
+      result = reallocImpl(p, newSize)
+
+  proc reallocShared0Impl(p: pointer, oldSize, newSize: Natural): pointer =
+    when hasThreadSupport:
+      acquireSys(heapLock)
+      result = realloc0(sharedHeap, p, oldSize, newSize)
+      releaseSys(heapLock)
+    else:
+      result = realloc0Impl(p, oldSize, newSize)
 
   when hasThreadSupport:
     template sharedMemStatsShared(v: int) =
diff --git a/lib/system/allocators.nim b/lib/system/allocators.nim
deleted file mode 100644
index e642999a8..000000000
--- a/lib/system/allocators.nim
+++ /dev/null
@@ -1,86 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2017 Nim contributors
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## Unstable API.
-
-type
-  AllocatorFlag* {.pure.} = enum  ## flags describing the properties of the allocator
-    ThreadLocal ## the allocator is thread local only.
-    ZerosMem    ## the allocator always zeros the memory on an allocation
-  Allocator* = ptr AllocatorObj
-  AllocatorObj* {.inheritable, compilerproc.} = object
-    alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall, raises: [], tags: [], gcsafe.}
-    dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall, raises: [], tags: [], gcsafe.}
-    realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall, raises: [], tags: [], gcsafe.}
-    deallocAll*: proc (a: Allocator) {.nimcall, raises: [], tags: [], gcsafe.}
-    flags*: set[AllocatorFlag]
-    name*: cstring
-    allocCount: int
-    deallocCount: int
-
-var
-  localAllocator {.threadvar.}: Allocator
-  sharedAllocator: Allocator
-  allocatorStorage {.threadvar.}: AllocatorObj
-
-when defined(useMalloc) and not defined(nimscript):
-  import "system/ansi_c"
-
-import "system/memory"
-
-template `+!`(p: pointer, s: int): pointer =
-  cast[pointer](cast[int](p) +% s)
-
-proc getLocalAllocator*(): Allocator =
-  result = localAllocator
-  if result == nil:
-    result = addr allocatorStorage
-    result.alloc = proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall, raises: [].} =
-      when defined(useMalloc) and not defined(nimscript):
-        result = c_malloc(cuint size)
-        # XXX do we need this?
-        nimZeroMem(result, size)
-      elif compileOption("threads"):
-        result = system.allocShared0(size)
-      else:
-        result = system.alloc0(size)
-      inc a.allocCount
-    result.dealloc = proc (a: Allocator; p: pointer; size: int) {.nimcall, raises: [].} =
-      when defined(useMalloc) and not defined(nimscript):
-        c_free(p)
-      elif compileOption("threads"):
-        system.deallocShared(p)
-      else:
-        system.dealloc(p)
-      inc a.deallocCount
-    result.realloc = proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall, raises: [].} =
-      when defined(useMalloc) and not defined(nimscript):
-        result = c_realloc(p, cuint newSize)
-      elif compileOption("threads"):
-        result = system.reallocShared(p, newSize)
-      else:
-        result = system.realloc(p, newSize)
-      nimZeroMem(result +! oldSize, newSize - oldSize)
-    result.deallocAll = nil
-    result.flags = {ThreadLocal, ZerosMem}
-    result.name = "nim_local"
-    localAllocator = result
-
-proc setLocalAllocator*(a: Allocator) =
-  localAllocator = a
-
-proc getSharedAllocator*(): Allocator =
-  result = sharedAllocator
-
-proc setSharedAllocator*(a: Allocator) =
-  sharedAllocator = a
-
-proc allocCounters*(): (int, int) =
-  let a = getLocalAllocator()
-  result = (a.allocCount, a.deallocCount)
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 55e004f6e..6649e9517 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -140,6 +140,8 @@ proc c_sprintf*(buf, frmt: cstring): cint {.
 
 proc c_malloc*(size: csize_t): pointer {.
   importc: "malloc", header: "<stdlib.h>".}
+proc c_calloc*(nmemb, size: csize_t): pointer {.
+  importc: "calloc", header: "<stdlib.h>".}
 proc c_free*(p: pointer) {.
   importc: "free", header: "<stdlib.h>".}
 proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim
index 963fc7b78..6b1640ab1 100644
--- a/lib/system/gc_regions.nim
+++ b/lib/system/gc_regions.nim
@@ -377,16 +377,21 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
 proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
   deprecated: "old compiler compat".} = asgnRef(dest, src)
 
-proc alloc(size: Natural): pointer =
+proc allocImpl(size: Natural): pointer =
   result = c_malloc(cast[csize_t](size))
   if result == nil: raiseOutOfMem()
-proc alloc0(size: Natural): pointer =
+proc alloc0Impl(size: Natural): pointer =
   result = alloc(size)
   zeroMem(result, size)
-proc realloc(p: pointer, newsize: Natural): pointer =
+proc reallocImpl(p: pointer, newsize: Natural): pointer =
   result = c_realloc(p, cast[csize_t](newsize))
   if result == nil: raiseOutOfMem()
-proc dealloc(p: pointer) = c_free(p)
+proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
+  result = c_realloc(p, cast[csize_t](newsize))
+  if result == nil: raiseOutOfMem()
+  if newsize > oldsize:
+    zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
+proc deallocImpl(p: pointer) = c_free(p)
 
 proc alloc0(r: var MemRegion; size: Natural): pointer =
   # ignore the region. That is correct for the channels module
@@ -400,16 +405,21 @@ proc alloc(r: var MemRegion; size: Natural): pointer =
 
 proc dealloc(r: var MemRegion; p: pointer) = dealloc(p)
 
-proc allocShared(size: Natural): pointer =
+proc allocSharedImpl(size: Natural): pointer =
   result = c_malloc(cast[csize_t](size))
   if result == nil: raiseOutOfMem()
-proc allocShared0(size: Natural): pointer =
+proc allocShared0Impl(size: Natural): pointer =
   result = alloc(size)
   zeroMem(result, size)
-proc reallocShared(p: pointer, newsize: Natural): pointer =
+proc reallocSharedImpl(p: pointer, newsize: Natural): pointer =
+  result = c_realloc(p, cast[csize_t](newsize))
+  if result == nil: raiseOutOfMem()
+proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer =
   result = c_realloc(p, cast[csize_t](newsize))
   if result == nil: raiseOutOfMem()
-proc deallocShared(p: pointer) = c_free(p)
+  if newsize > oldsize:
+    zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
+proc deallocSharedImpl(p: pointer) = c_free(p)
 
 when hasThreadSupport:
   proc getFreeSharedMem(): int = 0
diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim
index b48a6d70a..201e92e98 100644
--- a/lib/system/memalloc.nim
+++ b/lib/system/memalloc.nim
@@ -33,8 +33,48 @@ when notJSnotNims:
     ## otherwise. Like any procedure dealing with raw memory this is
     ## **unsafe**.
 
-when hasAlloc:
-  proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+when hasAlloc and not defined(js):
+
+  proc allocImpl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+  proc alloc0Impl*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+  proc deallocImpl*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].}
+  proc reallocImpl*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+  proc realloc0Impl*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+
+  proc allocSharedImpl*(size: Natural): pointer {.noconv, compilerproc, rtl, benign, raises: [], tags: [].}
+  proc allocShared0Impl*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
+  proc deallocSharedImpl*(p: pointer) {.noconv, rtl, benign, raises: [], tags: [].}
+  proc reallocSharedImpl*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+  proc reallocShared0Impl*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+
+  # Allocator statistics for memory leak tests
+
+  {.push stackTrace: off.}
+
+  type AllocStats* = object
+    allocCount: int
+    deallocCount: int
+
+  proc `-`*(a, b: AllocStats): AllocStats =
+    result.allocCount = a.allocCount - b.allocCount
+    result.deallocCount = a.deallocCount - b.deallocCount
+
+  template dumpAllocstats*(code: untyped) =
+    let stats1 = getAllocStats()
+    code
+    let stats2 = getAllocStats()
+    echo $(stats2 - stats1)
+
+  when defined(allocStats):
+    var stats: AllocStats
+    template incStat(what: untyped) = inc stats.what
+    proc getAllocStats*(): AllocStats = stats
+
+  else:
+    template incStat(what: untyped) = discard
+    proc getAllocStats*(): AllocStats = discard
+
+  template alloc*(size: Natural): pointer =
     ## Allocates a new memory block with at least ``size`` bytes.
     ##
     ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
@@ -47,6 +87,9 @@ when hasAlloc:
     ##
     ## See also:
     ## * `alloc0 <#alloc0,Natural>`_
+    incStat(allocCount)
+    allocImpl(size)
+
   proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
     ## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
     ##
@@ -62,7 +105,7 @@ when hasAlloc:
     ## * `create <#create,typedesc>`_
     cast[ptr T](alloc(T.sizeof * size))
 
-  proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
+  template alloc0*(size: Natural): pointer =
     ## Allocates a new memory block with at least ``size`` bytes.
     ##
     ## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
@@ -72,6 +115,9 @@ when hasAlloc:
     ##
     ## The allocated memory belongs to its allocating thread!
     ## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap.
+    incStat(allocCount)
+    alloc0Impl(size)
+
   proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
     ## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
     ##
@@ -84,8 +130,21 @@ when hasAlloc:
     ## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap.
     cast[ptr T](alloc0(sizeof(T) * size))
 
-  proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
-                                                         benign, raises: [].}
+  template realloc*(p: pointer, newSize: Natural): pointer =
+    ## Grows or shrinks a given memory block.
+    ##
+    ## If `p` is **nil** then a new memory block is returned.
+    ## In either way the block has at least ``newSize`` bytes.
+    ## If ``newSize == 0`` and `p` is not **nil** ``realloc`` calls ``dealloc(p)``.
+    ## In other cases the block has to be freed with
+    ## `dealloc(block) <#dealloc,pointer>`_.
+    ##
+    ## The allocated memory belongs to its allocating thread!
+    ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
+    ## from a shared heap.
+    reallocImpl(p, newSize)
+
+  template realloc0*(p: pointer, oldSize, newSize: Natural): pointer =
     ## Grows or shrinks a given memory block.
     ##
     ## If `p` is **nil** then a new memory block is returned.
@@ -94,9 +153,14 @@ when hasAlloc:
     ## In other cases the block has to be freed with
     ## `dealloc(block) <#dealloc,pointer>`_.
     ##
+    ## The block is initialized with all bytes containing zero, so it is
+    ## somewhat safer then realloc
+    ##
     ## The allocated memory belongs to its allocating thread!
     ## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
     ## from a shared heap.
+    realloc0Impl(p, oldSize, newSize)
+
   proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} =
     ## Grows or shrinks a given memory block.
     ##
@@ -110,7 +174,7 @@ when hasAlloc:
     ## from a shared heap.
     cast[ptr T](realloc(p, T.sizeof * newSize))
 
-  proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign, raises: [].}
+  template dealloc*(p: pointer) =
     ## Frees the memory allocated with ``alloc``, ``alloc0`` or
     ## ``realloc``.
     ##
@@ -121,8 +185,10 @@ when hasAlloc:
     ##
     ## The freed memory must belong to its allocating thread!
     ## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap.
+    incStat(deallocCount)
+    deallocImpl(p)
 
-  proc allocShared*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
+  template allocShared*(size: Natural): pointer =
     ## Allocates a new memory block on the shared heap with at
     ## least ``size`` bytes.
     ##
@@ -135,6 +201,9 @@ when hasAlloc:
     ##
     ## See also:
     ## `allocShared0 <#allocShared0,Natural>`_.
+    incStat(allocCount)
+    allocSharedImpl(size)
+
   proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [],
                                                                benign, raises: [].} =
     ## Allocates a new memory block on the shared heap with at
@@ -151,7 +220,7 @@ when hasAlloc:
     ## * `createShared <#createShared,typedesc>`_
     cast[ptr T](allocShared(T.sizeof * size))
 
-  proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
+  template allocShared0*(size: Natural): pointer =
     ## Allocates a new memory block on the shared heap with at
     ## least ``size`` bytes.
     ##
@@ -162,6 +231,9 @@ when hasAlloc:
     ## The block is initialized with all bytes
     ## containing zero, so it is somewhat safer than
     ## `allocShared <#allocShared,Natural>`_.
+    incStat(allocCount)
+    allocShared0Impl(size)
+
   proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
     ## Allocates a new memory block on the shared heap with at
     ## least ``T.sizeof * size`` bytes.
@@ -175,8 +247,7 @@ when hasAlloc:
     ## `createSharedU <#createSharedU,typedesc>`_.
     cast[ptr T](allocShared0(T.sizeof * size))
 
-  proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
-                                                               benign, raises: [].}
+  template reallocShared*(p: pointer, newSize: Natural): pointer =
     ## Grows or shrinks a given memory block on the heap.
     ##
     ## If `p` is **nil** then a new memory block is returned.
@@ -185,6 +256,22 @@ when hasAlloc:
     ## ``deallocShared(p)``.
     ## In other cases the block has to be freed with
     ## `deallocShared <#deallocShared,pointer>`_.
+    reallocSharedImpl(p, newSize)
+
+  template reallocShared0*(p: pointer, oldSize, newSize: Natural): pointer =
+    ## Grows or shrinks a given memory block on the heap.
+    ##
+    ## When growing, the new bytes of the block is initialized with all bytes
+    ## containing zero, so it is somewhat safer then reallocShared
+    ##
+    ## If `p` is **nil** then a new memory block is returned.
+    ## In either way the block has at least ``newSize`` bytes.
+    ## If ``newSize == 0`` and `p` is not **nil** ``reallocShared`` calls
+    ## ``deallocShared(p)``.
+    ## In other cases the block has to be freed with
+    ## `deallocShared <#deallocShared,pointer>`_.
+    reallocShared0Impl(p, oldSize, newSize)
+
   proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} =
     ## Grows or shrinks a given memory block on the heap.
     ##
@@ -196,7 +283,7 @@ when hasAlloc:
     ## `freeShared <#freeShared,ptr.T>`_.
     cast[ptr T](reallocShared(p, T.sizeof * newSize))
 
-  proc deallocShared*(p: pointer) {.noconv, rtl, benign, raises: [], tags: [].}
+  proc deallocShared*(p: pointer) {.noconv, compilerproc, rtl, benign, raises: [], tags: [].} =
     ## Frees the memory allocated with ``allocShared``, ``allocShared0`` or
     ## ``reallocShared``.
     ##
@@ -204,6 +291,9 @@ when hasAlloc:
     ## If one forgets to free the memory a leak occurs; if one tries to
     ## access freed memory (or just freeing it twice!) a core dump may happen
     ## or other memory may be corrupted.
+    incStat(deallocCount)
+    deallocSharedImpl(p)
+
   proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} =
     ## Frees the memory allocated with ``createShared``, ``createSharedU`` or
     ## ``resizeShared``.
@@ -214,6 +304,7 @@ when hasAlloc:
     ## or other memory may be corrupted.
     deallocShared(p)
 
+  {.pop.}
 
 # GC interface:
 
@@ -239,11 +330,13 @@ when defined(js):
   proc alloc(size: Natural): pointer = discard
   proc alloc0(size: Natural): pointer = discard
   proc realloc(p: pointer, newsize: Natural): pointer = discard
+  proc realloc0(p: pointer, oldsize, newsize: Natural): pointer = discard
 
   proc allocShared(size: Natural): pointer = discard
   proc allocShared0(size: Natural): pointer = discard
   proc deallocShared(p: pointer) = discard
   proc reallocShared(p: pointer, newsize: Natural): pointer = discard
+  proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = discard
 
 
 when hasAlloc and hasThreadSupport:
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index faa7813fb..1f42f1aa5 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -107,25 +107,26 @@ when defined(boehmgc):
 
   when not defined(useNimRtl):
 
-    proc alloc(size: Natural): pointer =
+    proc allocImpl(size: Natural): pointer =
       result = boehmAlloc(size)
       if result == nil: raiseOutOfMem()
-    proc alloc0(size: Natural): pointer =
+    proc alloc0Impl(size: Natural): pointer =
       result = alloc(size)
-    proc realloc(p: pointer, newSize: Natural): pointer =
+    proc reallocImpl(p: pointer, newSize: Natural): pointer =
       result = boehmRealloc(p, newSize)
       if result == nil: raiseOutOfMem()
-    proc dealloc(p: pointer) = boehmDealloc(p)
-
-    proc allocShared(size: Natural): pointer =
-      result = boehmAlloc(size)
-      if result == nil: raiseOutOfMem()
-    proc allocShared0(size: Natural): pointer =
-      result = allocShared(size)
-    proc reallocShared(p: pointer, newSize: Natural): pointer =
+    proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer =
       result = boehmRealloc(p, newSize)
       if result == nil: raiseOutOfMem()
-    proc deallocShared(p: pointer) = boehmDealloc(p)
+      if newsize > oldsize:
+        zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
+    proc deallocImpl(p: pointer) = boehmDealloc(p)
+
+    proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
+    proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
+    proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
+    proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
+    proc deallocSharedImpl(p: pointer) = deallocImpl(p)
 
     when hasThreadSupport:
       proc getFreeSharedMem(): int =
@@ -265,28 +266,26 @@ elif defined(gogc):
 
   proc nimGC_setStackBottom(theStackBottom: pointer) = discard
 
-  proc alloc(size: Natural): pointer =
+  proc allocImpl(size: Natural): pointer =
     result = goMalloc(size.uint)
 
-  proc alloc0(size: Natural): pointer =
+  proc alloc0Impl(size: Natural): pointer =
     result = goMalloc(size.uint)
 
-  proc realloc(p: pointer, newsize: Natural): pointer =
+  proc reallocImpl(p: pointer, newsize: Natural): pointer =
     doAssert false, "not implemented"
 
-  proc dealloc(p: pointer) =
-    discard
-
-  proc allocShared(size: Natural): pointer =
-    result = alloc(size)
-
-  proc allocShared0(size: Natural): pointer =
-    result = alloc0(size)
+  proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
+    doAssert false, "not implemented"
 
-  proc reallocShared(p: pointer, newsize: Natural): pointer =
-    result = realloc(p, newsize)
+  proc deallocImpl(p: pointer) =
+    discard
 
-  proc deallocShared(p: pointer) = dealloc(p)
+  proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
+  proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
+  proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
+  proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
+  proc deallocSharedImpl(p: pointer) = deallocImpl(p)
 
   when hasThreadSupport:
     proc getFreeSharedMem(): int = discard
@@ -349,7 +348,7 @@ elif defined(gogc):
   proc alloc(r: var MemRegion, size: int): pointer =
     result = alloc(size)
   proc alloc0(r: var MemRegion, size: int): pointer =
-    result = alloc0(size)
+    result = alloc0Impl(size)
   proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
   proc deallocOsPages(r: var MemRegion) {.inline.} = discard
   proc deallocOsPages() {.inline.} = discard
@@ -357,42 +356,21 @@ elif defined(gogc):
 elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
 
   when not defined(useNimRtl):
-    proc alloc(size: Natural): pointer =
-      var x = c_malloc (size + sizeof(size)).csize_t
-      if x == nil: raiseOutOfMem()
-
-      cast[ptr int](x)[] = size
-      result = cast[pointer](cast[int](x) + sizeof(size))
-
-    proc alloc0(size: Natural): pointer =
-      result = alloc(size)
-      zeroMem(result, size)
-    proc realloc(p: pointer, newsize: Natural): pointer =
-      var x = cast[pointer](cast[int](p) - sizeof(newsize))
-      let oldsize = cast[ptr int](x)[]
-
-      x = c_realloc(x, (newsize + sizeof(newsize)).csize_t)
-
-      if x == nil: raiseOutOfMem()
-
-      cast[ptr int](x)[] = newsize
-      result = cast[pointer](cast[int](x) + sizeof(newsize))
 
+    proc allocImpl(size: Natural): pointer = c_malloc(size.csize_t)
+    proc alloc0Impl(size: Natural): pointer = c_calloc(size.csize_t, 1)
+    proc reallocImpl(p: pointer, newsize: Natural): pointer = c_realloc(p, newSize.csize_t)
+    proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
+      result = realloc(p, newsize.csize_t)
       if newsize > oldsize:
         zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
+    proc deallocImpl(p: pointer) = c_free(p)
 
-    proc dealloc(p: pointer) = c_free(cast[pointer](cast[int](p) - sizeof(int)))
-
-    proc allocShared(size: Natural): pointer =
-      result = c_malloc(size.csize_t)
-      if result == nil: raiseOutOfMem()
-    proc allocShared0(size: Natural): pointer =
-      result = alloc(size)
-      zeroMem(result, size)
-    proc reallocShared(p: pointer, newsize: Natural): pointer =
-      result = c_realloc(p, newsize.csize_t)
-      if result == nil: raiseOutOfMem()
-    proc deallocShared(p: pointer) = c_free(p)
+    proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
+    proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
+    proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
+    proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
+    proc deallocSharedImpl(p: pointer) = deallocImpl(p)
 
     proc GC_disable() = discard
     proc GC_enable() = discard
@@ -400,7 +378,6 @@ elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
     proc GC_setStrategy(strategy: GC_Strategy) = discard
     proc GC_enableMarkAndSweep() = discard
     proc GC_disableMarkAndSweep() = discard
-    #proc GC_getStatistics(): string = return ""
 
     proc getOccupiedMem(): int = discard
     proc getFreeMem(): int = discard
@@ -431,8 +408,8 @@ elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
 
   proc alloc(r: var MemRegion, size: int): pointer =
     result = alloc(size)
-  proc alloc0(r: var MemRegion, size: int): pointer =
-    result = alloc0(size)
+  proc alloc0Impl(r: var MemRegion, size: int): pointer =
+    result = alloc0Impl(size)
   proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
   proc deallocOsPages(r: var MemRegion) {.inline.} = discard
   proc deallocOsPages() {.inline.} = discard
@@ -459,7 +436,7 @@ elif defined(nogc):
   proc GC_getStatistics(): string = return ""
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
-    result = alloc0(size)
+    result = alloc0Impl(size)
 
   proc newObjNoInit(typ: PNimType, size: int): pointer =
     result = alloc(size)
diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index ed49d3abc..f28bcadca 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -9,15 +9,18 @@
 
 
 # import typetraits
-# strs already imported allocators for us.
+# strs already imported allocateds for us.
 
 proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
 
 ## Default seq implementation used by Nim's core.
 type
+
+  NimSeqPayloadBase = object
+    cap: int
+
   NimSeqPayload[T] = object
     cap: int
-    allocator: Allocator
     data: UncheckedArray[T]
 
   NimSeqV2*[T] = object
@@ -26,22 +29,13 @@ type
 
 const nimSeqVersion {.core.} = 2
 
-template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator)
-
 # XXX make code memory safe for overflows in '*'
 
-type
-  PayloadBase = object
-    cap: int
-    allocator: Allocator
-
 proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
   # we have to use type erasure here as Nim does not support generic
   # compilerProcs. Oh well, this will all be inlined anyway.
   if cap > 0:
-    let allocator = getLocalAllocator()
-    var p = cast[ptr PayloadBase](allocator.alloc(allocator, cap * elemSize + sizeof(int) + sizeof(Allocator)))
-    p.allocator = allocator
+    var p = cast[ptr NimSeqPayloadBase](allocShared0(cap * elemSize + sizeof(NimSeqPayloadBase)))
     p.cap = cap
     result = p
   else:
@@ -53,7 +47,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
     template `+!`(p: pointer, s: int): pointer =
       cast[pointer](cast[int](p) +% s)
 
-    const headerSize = sizeof(int) + sizeof(Allocator)
+    const headerSize = sizeof(NimSeqPayloadBase)
     if addlen <= 0:
       result = p
     elif p == nil:
@@ -61,23 +55,19 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
     else:
       # Note: this means we cannot support things that have internal pointers as
       # they get reallocated here. This needs to be documented clearly.
-      var p = cast[ptr PayloadBase](p)
-      let cap = max(resize(p.cap), len+addlen)
-      if p.allocator == nil:
-        let allocator = getLocalAllocator()
-        var q = cast[ptr PayloadBase](allocator.alloc(allocator,
-          headerSize + elemSize * cap))
+      var p = cast[ptr NimSeqPayloadBase](p)
+      let oldCap = p.cap and not strlitFlag
+      let newCap = max(resize(oldCap), len+addlen)
+      if (p.cap and strlitFlag) == strlitFlag:
+        var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap))
         copyMem(q +! headerSize, p +! headerSize, len * elemSize)
-        q.allocator = allocator
-        q.cap = cap
+        q.cap = newCap
         result = q
       else:
-        let allocator = p.allocator
-        var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
-          headerSize + elemSize * p.cap,
-          headerSize + elemSize * cap))
-        q.allocator = allocator
-        q.cap = cap
+        let oldSize = headerSize + elemSize * oldCap
+        let newSize = headerSize + elemSize * newCap
+        var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize))
+        q.cap = newCap
         result = q
 
 proc shrink*[T](x: var seq[T]; newLen: Natural) =
diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim
index 555028f31..b4faba749 100644
--- a/lib/system/strs_v2.nim
+++ b/lib/system/strs_v2.nim
@@ -9,12 +9,12 @@
 
 ## Default new string implementation used by Nim's core.
 
-import allocators
-
 type
+  NimStrPayloadBase = object
+    cap: int
+
   NimStrPayload {.core.} = object
     cap: int
-    allocator: Allocator
     data: UncheckedArray[char]
 
   NimStringV2 {.core.} = object
@@ -23,13 +23,13 @@ type
 
 const nimStrVersion {.core.} = 2
 
-template isLiteral(s): bool = s.p == nil or s.p.allocator == nil
+template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag
 
-template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator)
+template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase)
 
 template frees(s) =
   if not isLiteral(s):
-    s.p.allocator.dealloc(s.p.allocator, s.p, contentSize(s.p.cap))
+    deallocShared(s.p)
 
 proc resize(old: int): int {.inline.} =
   if old <= 0: result = 4
@@ -41,19 +41,17 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
     if addlen > 0:
       let oldP = s.p
       # can't mutate a literal, so we need a fresh copy here:
-      let allocator = getLocalAllocator()
-      s.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(s.len + addlen)))
-      s.p.allocator = allocator
+      s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen)))
       s.p.cap = s.len + addlen
       if s.len > 0:
         # we are about to append, so there is no need to copy the \0 terminator:
         copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len)
-  elif s.len + addlen > s.p.cap:
-    let cap = max(s.len + addlen, resize(s.p.cap))
-    s.p = cast[ptr NimStrPayload](s.p.allocator.realloc(s.p.allocator, s.p,
-      oldSize = contentSize(s.p.cap),
-      newSize = contentSize(cap)))
-    s.p.cap = cap
+  else:
+    let oldCap = s.p.cap and not strlitFlag
+    if s.len + addlen > oldCap:
+      let newCap = max(s.len + addlen, resize(oldCap))
+      s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap)))
+      s.p.cap = newCap
 
 proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
   prepareAdd(s, 1)
@@ -65,9 +63,7 @@ proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} =
   if len <= 0:
     result = NimStringV2(len: 0, p: nil)
   else:
-    let allocator = getLocalAllocator()
-    var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(len)))
-    p.allocator = allocator
+    var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
     p.cap = len
     if len > 0:
       # we are about to append, so there is no need to copy the \0 terminator:
@@ -98,9 +94,7 @@ proc rawNewString(space: int): NimStringV2 {.compilerproc.} =
   if space <= 0:
     result = NimStringV2(len: 0, p: nil)
   else:
-    let allocator = getLocalAllocator()
-    var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(space)))
-    p.allocator = allocator
+    var p = cast[ptr NimStrPayload](allocShared0(contentSize(space)))
     p.cap = space
     result = NimStringV2(len: 0, p: p)
 
@@ -108,9 +102,7 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} =
   if len <= 0:
     result = NimStringV2(len: 0, p: nil)
   else:
-    let allocator = getLocalAllocator()
-    var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(len)))
-    p.allocator = allocator
+    var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
     p.cap = len
     result = NimStringV2(len: len, p: p)
 
@@ -130,24 +122,20 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
     a.len = b.len
     a.p = b.p
   else:
-    if isLiteral(a) or a.p.cap < b.len:
-      let allocator = if a.p != nil and a.p.allocator != nil: a.p.allocator else: getLocalAllocator()
+    if isLiteral(a) or  (a.p.cap and not strlitFlag) < b.len:
       # we have to allocate the 'cap' here, consider
       # 'let y = newStringOfCap(); var x = y'
       # on the other hand... These get turned into moves now.
       frees(a)
-      a.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(b.len)))
-      a.p.allocator = allocator
+      a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len)))
       a.p.cap = b.len
     a.len = b.len
     copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
 
 proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl.} =
-  if s.p != nil and s.p.allocator == nil:
+  if s.p != nil and (s.p.cap and strlitFlag) == strlitFlag:
     let oldP = s.p
     # can't mutate a literal, so we need a fresh copy here:
-    let allocator = getLocalAllocator()
-    s.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(s.len)))
-    s.p.allocator = allocator
+    s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
     s.p.cap = s.len
     copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim
index f3a6f9d77..59e507a4d 100644
--- a/lib/system/widestrs.nim
+++ b/lib/system/widestrs.nim
@@ -18,8 +18,6 @@ type
 
 when defined(nimv2):
 
-  import system / allocators
-
   type
     WideCString* = ptr UncheckedArray[Utf16Char]
 
@@ -29,8 +27,7 @@ when defined(nimv2):
 
   proc `=destroy`(a: var WideCStringObj) =
     if a.data != nil:
-      let alor = getLocalAllocator()
-      alor.dealloc(alor, a.data, a.bytes)
+      deallocShared(a.data)
       a.data = nil
 
   proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.}
@@ -41,8 +38,7 @@ when defined(nimv2):
 
   proc createWide(a: var WideCStringObj; bytes: int) =
     a.bytes = bytes
-    let alor = getLocalAllocator()
-    a.data = cast[typeof(a.data)](alor.alloc(alor, bytes))
+    a.data = cast[typeof(a.data)](allocShared0(bytes))
 
   template `[]`(a: WideCStringObj; idx: int): Utf16Char = a.data[idx]
   template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val