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
This commit is contained in:
Ico Doornekamp 2020-01-23 14:25:22 +01:00 • committed by Andreas Rumpf
commit b68eb1cad0
21 changed files with 275 additions and 312 deletions

View file

@ -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)