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:
parent
f500895efe
commit
b68eb1cad0
21 changed files with 275 additions and 312 deletions
|
|
@ -2037,15 +2037,15 @@ proc genDestroy(p: BProc; n: PNode) =
|
||||||
of tyString:
|
of tyString:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, arg, a)
|
initLocExpr(p, arg, a)
|
||||||
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
|
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
|
||||||
" $1.p->allocator->dealloc($1.p->allocator, $1.p, $1.p->cap + 1 + sizeof(NI) + sizeof(void*));$n" &
|
" #deallocShared($1.p);$n" &
|
||||||
" $1.p = NIM_NIL; }$n",
|
" $1.p = NIM_NIL; }$n",
|
||||||
[rdLoc(a)])
|
[rdLoc(a)])
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, arg, a)
|
initLocExpr(p, arg, a)
|
||||||
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
|
linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" &
|
||||||
" $1.p->allocator->dealloc($1.p->allocator, $1.p, ($1.p->cap * sizeof($2)) + sizeof(NI) + sizeof(void*));$n" &
|
" #deallocShared($1.p);$n" &
|
||||||
" $1.p = NIM_NIL; }$n",
|
" $1.p = NIM_NIL; }$n",
|
||||||
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
|
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
|
||||||
else: discard "nothing to do"
|
else: discard "nothing to do"
|
||||||
|
|
@ -2917,8 +2917,8 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =
|
||||||
|
|
||||||
appcg(p.module, cfsData,
|
appcg(p.module, cfsData,
|
||||||
"static $5 struct {$n" &
|
"static $5 struct {$n" &
|
||||||
" NI cap; void* allocator; $1 data[$2];$n" &
|
" NI cap; $1 data[$2];$n" &
|
||||||
"} $3 = {$2, NIM_NIL, $4};$n", [
|
"} $3 = {$2 | NIM_STRLIT_FLAG, $4};$n", [
|
||||||
getTypeDesc(p.module, base), n.len, payload, data,
|
getTypeDesc(p.module, base), n.len, payload, data,
|
||||||
if isConst: "const" else: ""])
|
if isConst: "const" else: ""])
|
||||||
result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
|
result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
|
||||||
|
|
||||||
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
|
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
|
||||||
m.s[cfsData].addf("static $4 struct {$n" &
|
m.s[cfsData].addf("static $4 struct {$n" &
|
||||||
" NI cap; void* allocator; NIM_CHAR data[$2+1];$n" &
|
" NI cap; NIM_CHAR data[$2+1];$n" &
|
||||||
"} $1 = { $2, NIM_NIL, $3 };$n",
|
"} $1 = { $2 | NIM_STRLIT_FLAG, $3 };$n",
|
||||||
[result, rope(s.len), makeCString(s),
|
[result, rope(s.len), makeCString(s),
|
||||||
rope(if isConst: "const" else: "")])
|
rope(if isConst: "const" else: "")])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -432,7 +432,7 @@ proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
|
||||||
appcg(m, m.s[cfsTypes], """$N
|
appcg(m, m.s[cfsTypes], """$N
|
||||||
$3ifndef $2_Content_PP
|
$3ifndef $2_Content_PP
|
||||||
$3define $2_Content_PP
|
$3define $2_Content_PP
|
||||||
struct $2_Content { NI cap;#AllocatorObj* allocator;$1 data[SEQ_DECL_SIZE];};
|
struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];};
|
||||||
$3endif$N
|
$3endif$N
|
||||||
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])
|
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -948,13 +948,18 @@ proc dealloc(allocator: var MemRegion, p: pointer) =
|
||||||
|
|
||||||
proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
|
proc realloc(allocator: var MemRegion, p: pointer, newsize: Natural): pointer =
|
||||||
if newsize > 0:
|
if newsize > 0:
|
||||||
result = alloc0(allocator, newsize)
|
result = alloc(allocator, newsize)
|
||||||
if p != nil:
|
if p != nil:
|
||||||
copyMem(result, p, min(ptrSize(p), newsize))
|
copyMem(result, p, min(ptrSize(p), newsize))
|
||||||
dealloc(allocator, p)
|
dealloc(allocator, p)
|
||||||
elif p != nil:
|
elif p != nil:
|
||||||
dealloc(allocator, p)
|
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) =
|
proc deallocOsPages(a: var MemRegion) =
|
||||||
# we free every 'ordinarily' allocated page by iterating over the page bits:
|
# we free every 'ordinarily' allocated page by iterating over the page bits:
|
||||||
var it = addr(a.heapLinks)
|
var it = addr(a.heapLinks)
|
||||||
|
|
@ -997,18 +1002,23 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||||
|
|
||||||
proc deallocOsPages = deallocOsPages(allocator)
|
proc deallocOsPages = deallocOsPages(allocator)
|
||||||
|
|
||||||
proc alloc(size: Natural): pointer =
|
proc allocImpl(size: Natural): pointer =
|
||||||
result = alloc(allocator, size)
|
result = alloc(allocator, size)
|
||||||
|
|
||||||
proc alloc0(size: Natural): pointer =
|
proc alloc0Impl(size: Natural): pointer =
|
||||||
result = alloc0(allocator, size)
|
result = alloc0(allocator, size)
|
||||||
|
|
||||||
proc dealloc(p: pointer) =
|
proc deallocImpl(p: pointer) =
|
||||||
dealloc(allocator, p)
|
dealloc(allocator, p)
|
||||||
|
|
||||||
proc realloc(p: pointer, newSize: Natural): pointer =
|
proc reallocImpl(p: pointer, newSize: Natural): pointer =
|
||||||
result = realloc(allocator, p, newSize)
|
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:
|
when false:
|
||||||
proc countFreeMem(): int =
|
proc countFreeMem(): int =
|
||||||
# only used for assertions
|
# only used for assertions
|
||||||
|
|
@ -1034,33 +1044,41 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||||
var heapLock: SysLock
|
var heapLock: SysLock
|
||||||
initSysLock(heapLock)
|
initSysLock(heapLock)
|
||||||
|
|
||||||
proc allocShared(size: Natural): pointer =
|
proc allocSharedImpl(size: Natural): pointer =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
acquireSys(heapLock)
|
acquireSys(heapLock)
|
||||||
result = alloc(sharedHeap, size)
|
result = alloc(sharedHeap, size)
|
||||||
releaseSys(heapLock)
|
releaseSys(heapLock)
|
||||||
else:
|
else:
|
||||||
result = alloc(size)
|
result = allocImpl(size)
|
||||||
|
|
||||||
proc allocShared0(size: Natural): pointer =
|
proc allocShared0Impl(size: Natural): pointer =
|
||||||
result = allocShared(size)
|
result = allocSharedImpl(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
|
|
||||||
proc deallocShared(p: pointer) =
|
proc deallocSharedImpl(p: pointer) =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
acquireSys(heapLock)
|
acquireSys(heapLock)
|
||||||
dealloc(sharedHeap, p)
|
dealloc(sharedHeap, p)
|
||||||
releaseSys(heapLock)
|
releaseSys(heapLock)
|
||||||
else:
|
else:
|
||||||
dealloc(p)
|
deallocImpl(p)
|
||||||
|
|
||||||
proc reallocShared(p: pointer, newSize: Natural): pointer =
|
proc reallocSharedImpl(p: pointer, newSize: Natural): pointer =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
acquireSys(heapLock)
|
acquireSys(heapLock)
|
||||||
result = realloc(sharedHeap, p, newSize)
|
result = realloc(sharedHeap, p, newSize)
|
||||||
releaseSys(heapLock)
|
releaseSys(heapLock)
|
||||||
else:
|
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:
|
when hasThreadSupport:
|
||||||
template sharedMemStatsShared(v: int) =
|
template sharedMemStatsShared(v: int) =
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -140,6 +140,8 @@ proc c_sprintf*(buf, frmt: cstring): cint {.
|
||||||
|
|
||||||
proc c_malloc*(size: csize_t): pointer {.
|
proc c_malloc*(size: csize_t): pointer {.
|
||||||
importc: "malloc", header: "<stdlib.h>".}
|
importc: "malloc", header: "<stdlib.h>".}
|
||||||
|
proc c_calloc*(nmemb, size: csize_t): pointer {.
|
||||||
|
importc: "calloc", header: "<stdlib.h>".}
|
||||||
proc c_free*(p: pointer) {.
|
proc c_free*(p: pointer) {.
|
||||||
importc: "free", header: "<stdlib.h>".}
|
importc: "free", header: "<stdlib.h>".}
|
||||||
proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
|
proc c_realloc*(p: pointer, newsize: csize_t): pointer {.
|
||||||
|
|
|
||||||
|
|
@ -377,16 +377,21 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
|
||||||
deprecated: "old compiler compat".} = asgnRef(dest, src)
|
deprecated: "old compiler compat".} = asgnRef(dest, src)
|
||||||
|
|
||||||
proc alloc(size: Natural): pointer =
|
proc allocImpl(size: Natural): pointer =
|
||||||
result = c_malloc(cast[csize_t](size))
|
result = c_malloc(cast[csize_t](size))
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc alloc0(size: Natural): pointer =
|
proc alloc0Impl(size: Natural): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, 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))
|
result = c_realloc(p, cast[csize_t](newsize))
|
||||||
if result == nil: raiseOutOfMem()
|
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 =
|
proc alloc0(r: var MemRegion; size: Natural): pointer =
|
||||||
# ignore the region. That is correct for the channels module
|
# 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 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))
|
result = c_malloc(cast[csize_t](size))
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc allocShared0(size: Natural): pointer =
|
proc allocShared0Impl(size: Natural): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, 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))
|
result = c_realloc(p, cast[csize_t](newsize))
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc deallocShared(p: pointer) = c_free(p)
|
proc reallocShared0Impl(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 deallocSharedImpl(p: pointer) = c_free(p)
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
proc getFreeSharedMem(): int = 0
|
proc getFreeSharedMem(): int = 0
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,48 @@ when notJSnotNims:
|
||||||
## otherwise. Like any procedure dealing with raw memory this is
|
## otherwise. Like any procedure dealing with raw memory this is
|
||||||
## **unsafe**.
|
## **unsafe**.
|
||||||
|
|
||||||
when hasAlloc:
|
when hasAlloc and not defined(js):
|
||||||
proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign, raises: [].}
|
|
||||||
|
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.
|
## Allocates a new memory block with at least ``size`` bytes.
|
||||||
##
|
##
|
||||||
## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
|
## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
|
||||||
|
|
@ -47,6 +87,9 @@ when hasAlloc:
|
||||||
##
|
##
|
||||||
## See also:
|
## See also:
|
||||||
## * `alloc0 <#alloc0,Natural>`_
|
## * `alloc0 <#alloc0,Natural>`_
|
||||||
|
incStat(allocCount)
|
||||||
|
allocImpl(size)
|
||||||
|
|
||||||
proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
|
proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
|
||||||
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
|
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
|
||||||
##
|
##
|
||||||
|
|
@ -62,7 +105,7 @@ when hasAlloc:
|
||||||
## * `create <#create,typedesc>`_
|
## * `create <#create,typedesc>`_
|
||||||
cast[ptr T](alloc(T.sizeof * size))
|
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.
|
## Allocates a new memory block with at least ``size`` bytes.
|
||||||
##
|
##
|
||||||
## The block has to be freed with `realloc(block, 0) <#realloc,pointer,Natural>`_
|
## 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!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `allocShared0 <#allocShared0,Natural>`_ to allocate from a shared heap.
|
## 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: [].} =
|
proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign, raises: [].} =
|
||||||
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
|
## Allocates a new memory block with at least ``T.sizeof * size`` bytes.
|
||||||
##
|
##
|
||||||
|
|
@ -84,8 +130,7 @@ when hasAlloc:
|
||||||
## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap.
|
## Use `createShared <#createShared,typedesc>`_ to allocate from a shared heap.
|
||||||
cast[ptr T](alloc0(sizeof(T) * size))
|
cast[ptr T](alloc0(sizeof(T) * size))
|
||||||
|
|
||||||
proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
|
template realloc*(p: pointer, newSize: Natural): pointer =
|
||||||
benign, raises: [].}
|
|
||||||
## Grows or shrinks a given memory block.
|
## Grows or shrinks a given memory block.
|
||||||
##
|
##
|
||||||
## If `p` is **nil** then a new memory block is returned.
|
## If `p` is **nil** then a new memory block is returned.
|
||||||
|
|
@ -97,6 +142,25 @@ when hasAlloc:
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
|
## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
|
||||||
## from a shared heap.
|
## 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.
|
||||||
|
## 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 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: [].} =
|
proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} =
|
||||||
## Grows or shrinks a given memory block.
|
## Grows or shrinks a given memory block.
|
||||||
##
|
##
|
||||||
|
|
@ -110,7 +174,7 @@ when hasAlloc:
|
||||||
## from a shared heap.
|
## from a shared heap.
|
||||||
cast[ptr T](realloc(p, T.sizeof * newSize))
|
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
|
## Frees the memory allocated with ``alloc``, ``alloc0`` or
|
||||||
## ``realloc``.
|
## ``realloc``.
|
||||||
##
|
##
|
||||||
|
|
@ -121,8 +185,10 @@ when hasAlloc:
|
||||||
##
|
##
|
||||||
## The freed memory must belong to its allocating thread!
|
## The freed memory must belong to its allocating thread!
|
||||||
## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap.
|
## 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
|
## Allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes.
|
## least ``size`` bytes.
|
||||||
##
|
##
|
||||||
|
|
@ -135,6 +201,9 @@ when hasAlloc:
|
||||||
##
|
##
|
||||||
## See also:
|
## See also:
|
||||||
## `allocShared0 <#allocShared0,Natural>`_.
|
## `allocShared0 <#allocShared0,Natural>`_.
|
||||||
|
incStat(allocCount)
|
||||||
|
allocSharedImpl(size)
|
||||||
|
|
||||||
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [],
|
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, tags: [],
|
||||||
benign, raises: [].} =
|
benign, raises: [].} =
|
||||||
## Allocates a new memory block on the shared heap with at
|
## Allocates a new memory block on the shared heap with at
|
||||||
|
|
@ -151,7 +220,7 @@ when hasAlloc:
|
||||||
## * `createShared <#createShared,typedesc>`_
|
## * `createShared <#createShared,typedesc>`_
|
||||||
cast[ptr T](allocShared(T.sizeof * size))
|
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
|
## Allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes.
|
## least ``size`` bytes.
|
||||||
##
|
##
|
||||||
|
|
@ -162,6 +231,9 @@ when hasAlloc:
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than
|
## containing zero, so it is somewhat safer than
|
||||||
## `allocShared <#allocShared,Natural>`_.
|
## `allocShared <#allocShared,Natural>`_.
|
||||||
|
incStat(allocCount)
|
||||||
|
allocShared0Impl(size)
|
||||||
|
|
||||||
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
||||||
## Allocates a new memory block on the shared heap with at
|
## Allocates a new memory block on the shared heap with at
|
||||||
## least ``T.sizeof * size`` bytes.
|
## least ``T.sizeof * size`` bytes.
|
||||||
|
|
@ -175,8 +247,7 @@ when hasAlloc:
|
||||||
## `createSharedU <#createSharedU,typedesc>`_.
|
## `createSharedU <#createSharedU,typedesc>`_.
|
||||||
cast[ptr T](allocShared0(T.sizeof * size))
|
cast[ptr T](allocShared0(T.sizeof * size))
|
||||||
|
|
||||||
proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
|
template reallocShared*(p: pointer, newSize: Natural): pointer =
|
||||||
benign, raises: [].}
|
|
||||||
## Grows or shrinks a given memory block on the heap.
|
## Grows or shrinks a given memory block on the heap.
|
||||||
##
|
##
|
||||||
## If `p` is **nil** then a new memory block is returned.
|
## If `p` is **nil** then a new memory block is returned.
|
||||||
|
|
@ -185,6 +256,22 @@ when hasAlloc:
|
||||||
## ``deallocShared(p)``.
|
## ``deallocShared(p)``.
|
||||||
## In other cases the block has to be freed with
|
## In other cases the block has to be freed with
|
||||||
## `deallocShared <#deallocShared,pointer>`_.
|
## `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: [].} =
|
proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} =
|
||||||
## Grows or shrinks a given memory block on the heap.
|
## Grows or shrinks a given memory block on the heap.
|
||||||
##
|
##
|
||||||
|
|
@ -196,7 +283,7 @@ when hasAlloc:
|
||||||
## `freeShared <#freeShared,ptr.T>`_.
|
## `freeShared <#freeShared,ptr.T>`_.
|
||||||
cast[ptr T](reallocShared(p, T.sizeof * newSize))
|
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
|
## Frees the memory allocated with ``allocShared``, ``allocShared0`` or
|
||||||
## ``reallocShared``.
|
## ``reallocShared``.
|
||||||
##
|
##
|
||||||
|
|
@ -204,6 +291,9 @@ when hasAlloc:
|
||||||
## If one forgets to free the memory a leak occurs; if one tries to
|
## 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
|
## access freed memory (or just freeing it twice!) a core dump may happen
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
|
incStat(deallocCount)
|
||||||
|
deallocSharedImpl(p)
|
||||||
|
|
||||||
proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} =
|
proc freeShared*[T](p: ptr T) {.inline, benign, raises: [].} =
|
||||||
## Frees the memory allocated with ``createShared``, ``createSharedU`` or
|
## Frees the memory allocated with ``createShared``, ``createSharedU`` or
|
||||||
## ``resizeShared``.
|
## ``resizeShared``.
|
||||||
|
|
@ -214,6 +304,7 @@ when hasAlloc:
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
deallocShared(p)
|
deallocShared(p)
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
# GC interface:
|
# GC interface:
|
||||||
|
|
||||||
|
|
@ -239,11 +330,13 @@ when defined(js):
|
||||||
proc alloc(size: Natural): pointer = discard
|
proc alloc(size: Natural): pointer = discard
|
||||||
proc alloc0(size: Natural): pointer = discard
|
proc alloc0(size: Natural): pointer = discard
|
||||||
proc realloc(p: pointer, newsize: 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 allocShared(size: Natural): pointer = discard
|
||||||
proc allocShared0(size: Natural): pointer = discard
|
proc allocShared0(size: Natural): pointer = discard
|
||||||
proc deallocShared(p: pointer) = discard
|
proc deallocShared(p: pointer) = discard
|
||||||
proc reallocShared(p: pointer, newsize: Natural): pointer = discard
|
proc reallocShared(p: pointer, newsize: Natural): pointer = discard
|
||||||
|
proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = discard
|
||||||
|
|
||||||
|
|
||||||
when hasAlloc and hasThreadSupport:
|
when hasAlloc and hasThreadSupport:
|
||||||
|
|
|
||||||
|
|
@ -107,25 +107,26 @@ when defined(boehmgc):
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
|
|
||||||
proc alloc(size: Natural): pointer =
|
proc allocImpl(size: Natural): pointer =
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc alloc0(size: Natural): pointer =
|
proc alloc0Impl(size: Natural): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
proc realloc(p: pointer, newSize: Natural): pointer =
|
proc reallocImpl(p: pointer, newSize: Natural): pointer =
|
||||||
result = boehmRealloc(p, newSize)
|
result = boehmRealloc(p, newSize)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc dealloc(p: pointer) = boehmDealloc(p)
|
proc realloc0Impl(p: pointer, oldSize, newSize: Natural): pointer =
|
||||||
|
result = boehmRealloc(p, newSize)
|
||||||
|
if result == nil: raiseOutOfMem()
|
||||||
|
if newsize > oldsize:
|
||||||
|
zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
|
||||||
|
proc deallocImpl(p: pointer) = boehmDealloc(p)
|
||||||
|
|
||||||
proc allocShared(size: Natural): pointer =
|
proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
|
||||||
result = boehmAlloc(size)
|
proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
|
||||||
if result == nil: raiseOutOfMem()
|
proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
|
||||||
proc allocShared0(size: Natural): pointer =
|
proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
|
||||||
result = allocShared(size)
|
proc deallocSharedImpl(p: pointer) = deallocImpl(p)
|
||||||
proc reallocShared(p: pointer, newSize: Natural): pointer =
|
|
||||||
result = boehmRealloc(p, newSize)
|
|
||||||
if result == nil: raiseOutOfMem()
|
|
||||||
proc deallocShared(p: pointer) = boehmDealloc(p)
|
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
proc getFreeSharedMem(): int =
|
proc getFreeSharedMem(): int =
|
||||||
|
|
@ -265,28 +266,26 @@ elif defined(gogc):
|
||||||
|
|
||||||
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
proc nimGC_setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc alloc(size: Natural): pointer =
|
proc allocImpl(size: Natural): pointer =
|
||||||
result = goMalloc(size.uint)
|
result = goMalloc(size.uint)
|
||||||
|
|
||||||
proc alloc0(size: Natural): pointer =
|
proc alloc0Impl(size: Natural): pointer =
|
||||||
result = goMalloc(size.uint)
|
result = goMalloc(size.uint)
|
||||||
|
|
||||||
proc realloc(p: pointer, newsize: Natural): pointer =
|
proc reallocImpl(p: pointer, newsize: Natural): pointer =
|
||||||
doAssert false, "not implemented"
|
doAssert false, "not implemented"
|
||||||
|
|
||||||
proc dealloc(p: pointer) =
|
proc realloc0Impl(p: pointer, oldsize, newsize: Natural): pointer =
|
||||||
|
doAssert false, "not implemented"
|
||||||
|
|
||||||
|
proc deallocImpl(p: pointer) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc allocShared(size: Natural): pointer =
|
proc allocSharedImpl(size: Natural): pointer = allocImpl(size)
|
||||||
result = alloc(size)
|
proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
|
||||||
|
proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
|
||||||
proc allocShared0(size: Natural): pointer =
|
proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
|
||||||
result = alloc0(size)
|
proc deallocSharedImpl(p: pointer) = deallocImpl(p)
|
||||||
|
|
||||||
proc reallocShared(p: pointer, newsize: Natural): pointer =
|
|
||||||
result = realloc(p, newsize)
|
|
||||||
|
|
||||||
proc deallocShared(p: pointer) = dealloc(p)
|
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
proc getFreeSharedMem(): int = discard
|
proc getFreeSharedMem(): int = discard
|
||||||
|
|
@ -349,7 +348,7 @@ elif defined(gogc):
|
||||||
proc alloc(r: var MemRegion, size: int): pointer =
|
proc alloc(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
proc alloc0(r: var MemRegion, size: int): pointer =
|
proc alloc0(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc0(size)
|
result = alloc0Impl(size)
|
||||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||||
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
@ -357,42 +356,21 @@ elif defined(gogc):
|
||||||
elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
|
elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
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:
|
if newsize > oldsize:
|
||||||
zeroMem(cast[pointer](cast[int](result) + oldsize), 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 allocSharedImpl(size: Natural): pointer = allocImpl(size)
|
||||||
|
proc allocShared0Impl(size: Natural): pointer = alloc0Impl(size)
|
||||||
proc allocShared(size: Natural): pointer =
|
proc reallocSharedImpl(p: pointer, newsize: Natural): pointer = reallocImpl(p, newsize)
|
||||||
result = c_malloc(size.csize_t)
|
proc reallocShared0Impl(p: pointer, oldsize, newsize: Natural): pointer = realloc0Impl(p, oldsize, newsize)
|
||||||
if result == nil: raiseOutOfMem()
|
proc deallocSharedImpl(p: pointer) = deallocImpl(p)
|
||||||
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 GC_disable() = discard
|
proc GC_disable() = discard
|
||||||
proc GC_enable() = 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_setStrategy(strategy: GC_Strategy) = discard
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
#proc GC_getStatistics(): string = return ""
|
|
||||||
|
|
||||||
proc getOccupiedMem(): int = discard
|
proc getOccupiedMem(): int = discard
|
||||||
proc getFreeMem(): 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 =
|
proc alloc(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
proc alloc0(r: var MemRegion, size: int): pointer =
|
proc alloc0Impl(r: var MemRegion, size: int): pointer =
|
||||||
result = alloc0(size)
|
result = alloc0Impl(size)
|
||||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||||
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var MemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
@ -459,7 +436,7 @@ elif defined(nogc):
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||||
result = alloc0(size)
|
result = alloc0Impl(size)
|
||||||
|
|
||||||
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,18 @@
|
||||||
|
|
||||||
|
|
||||||
# import typetraits
|
# import typetraits
|
||||||
# strs already imported allocators for us.
|
# strs already imported allocateds for us.
|
||||||
|
|
||||||
proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
|
proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
|
||||||
|
|
||||||
## Default seq implementation used by Nim's core.
|
## Default seq implementation used by Nim's core.
|
||||||
type
|
type
|
||||||
|
|
||||||
|
NimSeqPayloadBase = object
|
||||||
|
cap: int
|
||||||
|
|
||||||
NimSeqPayload[T] = object
|
NimSeqPayload[T] = object
|
||||||
cap: int
|
cap: int
|
||||||
allocator: Allocator
|
|
||||||
data: UncheckedArray[T]
|
data: UncheckedArray[T]
|
||||||
|
|
||||||
NimSeqV2*[T] = object
|
NimSeqV2*[T] = object
|
||||||
|
|
@ -26,22 +29,13 @@ type
|
||||||
|
|
||||||
const nimSeqVersion {.core.} = 2
|
const nimSeqVersion {.core.} = 2
|
||||||
|
|
||||||
template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator)
|
|
||||||
|
|
||||||
# XXX make code memory safe for overflows in '*'
|
# XXX make code memory safe for overflows in '*'
|
||||||
|
|
||||||
type
|
|
||||||
PayloadBase = object
|
|
||||||
cap: int
|
|
||||||
allocator: Allocator
|
|
||||||
|
|
||||||
proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
|
proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
|
||||||
# we have to use type erasure here as Nim does not support generic
|
# we have to use type erasure here as Nim does not support generic
|
||||||
# compilerProcs. Oh well, this will all be inlined anyway.
|
# compilerProcs. Oh well, this will all be inlined anyway.
|
||||||
if cap > 0:
|
if cap > 0:
|
||||||
let allocator = getLocalAllocator()
|
var p = cast[ptr NimSeqPayloadBase](allocShared0(cap * elemSize + sizeof(NimSeqPayloadBase)))
|
||||||
var p = cast[ptr PayloadBase](allocator.alloc(allocator, cap * elemSize + sizeof(int) + sizeof(Allocator)))
|
|
||||||
p.allocator = allocator
|
|
||||||
p.cap = cap
|
p.cap = cap
|
||||||
result = p
|
result = p
|
||||||
else:
|
else:
|
||||||
|
|
@ -53,7 +47,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
|
||||||
template `+!`(p: pointer, s: int): pointer =
|
template `+!`(p: pointer, s: int): pointer =
|
||||||
cast[pointer](cast[int](p) +% s)
|
cast[pointer](cast[int](p) +% s)
|
||||||
|
|
||||||
const headerSize = sizeof(int) + sizeof(Allocator)
|
const headerSize = sizeof(NimSeqPayloadBase)
|
||||||
if addlen <= 0:
|
if addlen <= 0:
|
||||||
result = p
|
result = p
|
||||||
elif p == nil:
|
elif p == nil:
|
||||||
|
|
@ -61,23 +55,19 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
|
||||||
else:
|
else:
|
||||||
# Note: this means we cannot support things that have internal pointers as
|
# Note: this means we cannot support things that have internal pointers as
|
||||||
# they get reallocated here. This needs to be documented clearly.
|
# they get reallocated here. This needs to be documented clearly.
|
||||||
var p = cast[ptr PayloadBase](p)
|
var p = cast[ptr NimSeqPayloadBase](p)
|
||||||
let cap = max(resize(p.cap), len+addlen)
|
let oldCap = p.cap and not strlitFlag
|
||||||
if p.allocator == nil:
|
let newCap = max(resize(oldCap), len+addlen)
|
||||||
let allocator = getLocalAllocator()
|
if (p.cap and strlitFlag) == strlitFlag:
|
||||||
var q = cast[ptr PayloadBase](allocator.alloc(allocator,
|
var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * newCap))
|
||||||
headerSize + elemSize * cap))
|
|
||||||
copyMem(q +! headerSize, p +! headerSize, len * elemSize)
|
copyMem(q +! headerSize, p +! headerSize, len * elemSize)
|
||||||
q.allocator = allocator
|
q.cap = newCap
|
||||||
q.cap = cap
|
|
||||||
result = q
|
result = q
|
||||||
else:
|
else:
|
||||||
let allocator = p.allocator
|
let oldSize = headerSize + elemSize * oldCap
|
||||||
var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
|
let newSize = headerSize + elemSize * newCap
|
||||||
headerSize + elemSize * p.cap,
|
var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize))
|
||||||
headerSize + elemSize * cap))
|
q.cap = newCap
|
||||||
q.allocator = allocator
|
|
||||||
q.cap = cap
|
|
||||||
result = q
|
result = q
|
||||||
|
|
||||||
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
proc shrink*[T](x: var seq[T]; newLen: Natural) =
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
## Default new string implementation used by Nim's core.
|
## Default new string implementation used by Nim's core.
|
||||||
|
|
||||||
import allocators
|
|
||||||
|
|
||||||
type
|
type
|
||||||
|
NimStrPayloadBase = object
|
||||||
|
cap: int
|
||||||
|
|
||||||
NimStrPayload {.core.} = object
|
NimStrPayload {.core.} = object
|
||||||
cap: int
|
cap: int
|
||||||
allocator: Allocator
|
|
||||||
data: UncheckedArray[char]
|
data: UncheckedArray[char]
|
||||||
|
|
||||||
NimStringV2 {.core.} = object
|
NimStringV2 {.core.} = object
|
||||||
|
|
@ -23,13 +23,13 @@ type
|
||||||
|
|
||||||
const nimStrVersion {.core.} = 2
|
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) =
|
template frees(s) =
|
||||||
if not isLiteral(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.} =
|
proc resize(old: int): int {.inline.} =
|
||||||
if old <= 0: result = 4
|
if old <= 0: result = 4
|
||||||
|
|
@ -41,19 +41,17 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
|
||||||
if addlen > 0:
|
if addlen > 0:
|
||||||
let oldP = s.p
|
let oldP = s.p
|
||||||
# can't mutate a literal, so we need a fresh copy here:
|
# can't mutate a literal, so we need a fresh copy here:
|
||||||
let allocator = getLocalAllocator()
|
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len + addlen)))
|
||||||
s.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(s.len + addlen)))
|
|
||||||
s.p.allocator = allocator
|
|
||||||
s.p.cap = s.len + addlen
|
s.p.cap = s.len + addlen
|
||||||
if s.len > 0:
|
if s.len > 0:
|
||||||
# we are about to append, so there is no need to copy the \0 terminator:
|
# 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)
|
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len)
|
||||||
elif s.len + addlen > s.p.cap:
|
else:
|
||||||
let cap = max(s.len + addlen, resize(s.p.cap))
|
let oldCap = s.p.cap and not strlitFlag
|
||||||
s.p = cast[ptr NimStrPayload](s.p.allocator.realloc(s.p.allocator, s.p,
|
if s.len + addlen > oldCap:
|
||||||
oldSize = contentSize(s.p.cap),
|
let newCap = max(s.len + addlen, resize(oldCap))
|
||||||
newSize = contentSize(cap)))
|
s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||||
s.p.cap = cap
|
s.p.cap = newCap
|
||||||
|
|
||||||
proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
|
proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
|
||||||
prepareAdd(s, 1)
|
prepareAdd(s, 1)
|
||||||
|
|
@ -65,9 +63,7 @@ proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} =
|
||||||
if len <= 0:
|
if len <= 0:
|
||||||
result = NimStringV2(len: 0, p: nil)
|
result = NimStringV2(len: 0, p: nil)
|
||||||
else:
|
else:
|
||||||
let allocator = getLocalAllocator()
|
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||||
var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(len)))
|
|
||||||
p.allocator = allocator
|
|
||||||
p.cap = len
|
p.cap = len
|
||||||
if len > 0:
|
if len > 0:
|
||||||
# we are about to append, so there is no need to copy the \0 terminator:
|
# 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:
|
if space <= 0:
|
||||||
result = NimStringV2(len: 0, p: nil)
|
result = NimStringV2(len: 0, p: nil)
|
||||||
else:
|
else:
|
||||||
let allocator = getLocalAllocator()
|
var p = cast[ptr NimStrPayload](allocShared0(contentSize(space)))
|
||||||
var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(space)))
|
|
||||||
p.allocator = allocator
|
|
||||||
p.cap = space
|
p.cap = space
|
||||||
result = NimStringV2(len: 0, p: p)
|
result = NimStringV2(len: 0, p: p)
|
||||||
|
|
||||||
|
|
@ -108,9 +102,7 @@ proc mnewString(len: int): NimStringV2 {.compilerproc.} =
|
||||||
if len <= 0:
|
if len <= 0:
|
||||||
result = NimStringV2(len: 0, p: nil)
|
result = NimStringV2(len: 0, p: nil)
|
||||||
else:
|
else:
|
||||||
let allocator = getLocalAllocator()
|
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||||
var p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(len)))
|
|
||||||
p.allocator = allocator
|
|
||||||
p.cap = len
|
p.cap = len
|
||||||
result = NimStringV2(len: len, p: p)
|
result = NimStringV2(len: len, p: p)
|
||||||
|
|
||||||
|
|
@ -130,24 +122,20 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||||
a.len = b.len
|
a.len = b.len
|
||||||
a.p = b.p
|
a.p = b.p
|
||||||
else:
|
else:
|
||||||
if isLiteral(a) or a.p.cap < b.len:
|
if isLiteral(a) or (a.p.cap and not strlitFlag) < b.len:
|
||||||
let allocator = if a.p != nil and a.p.allocator != nil: a.p.allocator else: getLocalAllocator()
|
|
||||||
# we have to allocate the 'cap' here, consider
|
# we have to allocate the 'cap' here, consider
|
||||||
# 'let y = newStringOfCap(); var x = y'
|
# 'let y = newStringOfCap(); var x = y'
|
||||||
# on the other hand... These get turned into moves now.
|
# on the other hand... These get turned into moves now.
|
||||||
frees(a)
|
frees(a)
|
||||||
a.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(b.len)))
|
a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len)))
|
||||||
a.p.allocator = allocator
|
|
||||||
a.p.cap = b.len
|
a.p.cap = b.len
|
||||||
a.len = b.len
|
a.len = b.len
|
||||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
||||||
|
|
||||||
proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl.} =
|
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
|
let oldP = s.p
|
||||||
# can't mutate a literal, so we need a fresh copy here:
|
# can't mutate a literal, so we need a fresh copy here:
|
||||||
let allocator = getLocalAllocator()
|
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
|
||||||
s.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(s.len)))
|
|
||||||
s.p.allocator = allocator
|
|
||||||
s.p.cap = s.len
|
s.p.cap = s.len
|
||||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
|
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@ type
|
||||||
|
|
||||||
when defined(nimv2):
|
when defined(nimv2):
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
|
|
||||||
type
|
type
|
||||||
WideCString* = ptr UncheckedArray[Utf16Char]
|
WideCString* = ptr UncheckedArray[Utf16Char]
|
||||||
|
|
||||||
|
|
@ -29,8 +27,7 @@ when defined(nimv2):
|
||||||
|
|
||||||
proc `=destroy`(a: var WideCStringObj) =
|
proc `=destroy`(a: var WideCStringObj) =
|
||||||
if a.data != nil:
|
if a.data != nil:
|
||||||
let alor = getLocalAllocator()
|
deallocShared(a.data)
|
||||||
alor.dealloc(alor, a.data, a.bytes)
|
|
||||||
a.data = nil
|
a.data = nil
|
||||||
|
|
||||||
proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.}
|
proc `=`(a: var WideCStringObj; b: WideCStringObj) {.error.}
|
||||||
|
|
@ -41,8 +38,7 @@ when defined(nimv2):
|
||||||
|
|
||||||
proc createWide(a: var WideCStringObj; bytes: int) =
|
proc createWide(a: var WideCStringObj; bytes: int) =
|
||||||
a.bytes = bytes
|
a.bytes = bytes
|
||||||
let alor = getLocalAllocator()
|
a.data = cast[typeof(a.data)](allocShared0(bytes))
|
||||||
a.data = cast[typeof(a.data)](alor.alloc(alor, bytes))
|
|
||||||
|
|
||||||
template `[]`(a: WideCStringObj; idx: int): Utf16Char = a.data[idx]
|
template `[]`(a: WideCStringObj; idx: int): Utf16Char = a.data[idx]
|
||||||
template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val
|
template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char) = a.data[idx] = val
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c -d:allocStats --newruntime $file'''
|
||||||
output: '''0
|
output: '''0
|
||||||
3 3 alloc/dealloc pairs: 0'''
|
(allocCount: 6, deallocCount: 6)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
@ -97,7 +96,6 @@ proc main() =
|
||||||
discard
|
discard
|
||||||
echo res
|
echo res
|
||||||
|
|
||||||
main()
|
dumpAllocStats:
|
||||||
|
main()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld alloc/dealloc pairs: %ld\n", a, d, system.allocs)
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c -d:allocStats --newruntime $file'''
|
||||||
output: '''hi
|
output: '''hi
|
||||||
ho
|
ho
|
||||||
ha
|
ha
|
||||||
|
|
@ -10,10 +10,9 @@ a: @[4, 2, 3]
|
||||||
0
|
0
|
||||||
30
|
30
|
||||||
true
|
true
|
||||||
41 41'''
|
(allocCount: 41, deallocCount: 41)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
include system / ansi_c
|
include system / ansi_c
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
|
|
@ -201,7 +200,4 @@ proc takeAinArray =
|
||||||
takeAinArray()
|
takeAinArray()
|
||||||
echo ga == "foo"
|
echo ga == "foo"
|
||||||
|
|
||||||
|
echo getAllocStats()
|
||||||
#echo s
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld\n", a, d)
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim cpp --newruntime --threads:on $file'''
|
cmd: '''nim cpp -d:allocStats --newruntime --threads:on $file'''
|
||||||
output: '''(field: "value")
|
output: '''(field: "value")
|
||||||
Indeed
|
Indeed
|
||||||
axc
|
axc
|
||||||
(v: 10)
|
(v: 10)
|
||||||
0 new: 0
|
|
||||||
...
|
...
|
||||||
destroying GenericObj[T] GenericObj[system.int]
|
destroying GenericObj[T] GenericObj[system.int]
|
||||||
test
|
test
|
||||||
'''
|
(allocCount: 17, deallocCount: 15)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
import tables
|
import tables
|
||||||
|
|
@ -24,6 +22,8 @@ type
|
||||||
import os
|
import os
|
||||||
putEnv("HEAPTRASHING", "Indeed")
|
putEnv("HEAPTRASHING", "Indeed")
|
||||||
|
|
||||||
|
let s1 = getAllocStats()
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
var w = newTable[string, owned Node]()
|
var w = newTable[string, owned Node]()
|
||||||
w["key"] = Node(field: "value")
|
w["key"] = Node(field: "value")
|
||||||
|
|
@ -87,9 +87,6 @@ proc testWrongAt() =
|
||||||
|
|
||||||
testWrongAt()
|
testWrongAt()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld new: %ld\n", a - unpairedEnvAllocs() - d, allocs)
|
|
||||||
|
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
type
|
type
|
||||||
Table[A, B] = object
|
Table[A, B] = object
|
||||||
|
|
@ -134,3 +131,4 @@ proc xx(xml: string): MyObject =
|
||||||
|
|
||||||
|
|
||||||
discard xx("test")
|
discard xx("test")
|
||||||
|
echo getAllocStats() - s1
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
discard """
|
discard """
|
||||||
valgrind: true
|
valgrind: true
|
||||||
cmd: '''nim c --newruntime -d:useMalloc $file'''
|
cmd: '''nim c -d:allocStats --newruntime -d:useMalloc $file'''
|
||||||
output: '''
|
output: '''
|
||||||
@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]
|
@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]'''
|
||||||
461 461'''
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import strutils, os, std / wordwrap
|
import strutils, os, std / wordwrap
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
# bug #11004
|
# bug #11004
|
||||||
|
|
@ -213,6 +211,3 @@ staticTests()
|
||||||
# bug #12965
|
# bug #12965
|
||||||
let xaa = @[""].join()
|
let xaa = @[""].join()
|
||||||
let xbb = @["", ""].join()
|
let xbb = @["", ""].join()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld\n", a, d)
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c -d:allocStats --newruntime $file'''
|
||||||
output: '''a b
|
output: '''a b
|
||||||
70
|
70
|
||||||
hello
|
hello
|
||||||
hello
|
hello
|
||||||
hello
|
hello
|
||||||
2 2 alloc/dealloc pairs: 0'''
|
(allocCount: 4, deallocCount: 4)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
proc main(): owned(proc()) =
|
proc main(): owned(proc()) =
|
||||||
|
|
@ -60,5 +59,4 @@ when false:
|
||||||
|
|
||||||
stringIter()
|
stringIter()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
echo getAllocStats()
|
||||||
discard cprintf("%ld %ld alloc/dealloc pairs: %ld\n", a, d, system.allocs)
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c --newruntime $file'''
|
||||||
errormsg: "'=' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(53, 4)"
|
errormsg: "'=' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)"
|
||||||
line: 49
|
line: 48
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -56,5 +55,3 @@ proc main =
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld new: %ld\n", a, d, allocs)
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
valgrind: true
|
||||||
|
cmd: '''nim c -d:allocStats --newruntime $file'''
|
||||||
output: '''OK 3
|
output: '''OK 3
|
||||||
5 2'''
|
(allocCount: 8, deallocCount: 3)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import strutils, math
|
import strutils, math
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
import system / allocators
|
|
||||||
|
|
||||||
proc mainA =
|
proc mainA =
|
||||||
try:
|
try:
|
||||||
|
|
@ -50,6 +50,4 @@ except:
|
||||||
inc ok
|
inc ok
|
||||||
|
|
||||||
echo "OK ", ok
|
echo "OK ", ok
|
||||||
|
echo getAllocStats()
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld\n", a, d)
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c -d:allocstats --newruntime $file'''
|
||||||
output: '''button
|
output: '''button
|
||||||
clicked!
|
clicked!
|
||||||
1 1 alloc/dealloc pairs: 0'''
|
(allocCount: 4, deallocCount: 4)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -72,7 +71,6 @@ proc main =
|
||||||
|
|
||||||
w.draw()
|
w.draw()
|
||||||
|
|
||||||
main()
|
dumpAllocstats:
|
||||||
|
main()
|
||||||
|
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld alloc/dealloc pairs: %ld\n", a, d, allocs)
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c -d:allocStats --newruntime $file'''
|
||||||
output: '''button
|
output: '''button
|
||||||
clicked!
|
clicked!
|
||||||
6 6 alloc/dealloc pairs: 0'''
|
(allocCount: 9, deallocCount: 9)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import system / allocators
|
|
||||||
import system / ansi_c
|
import system / ansi_c
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -69,7 +68,5 @@ proc main =
|
||||||
if a != nil:
|
if a != nil:
|
||||||
a()
|
a()
|
||||||
|
|
||||||
main()
|
dumpAllocStats:
|
||||||
|
main()
|
||||||
let (a, d) = allocCounters()
|
|
||||||
discard cprintf("%ld %ld alloc/dealloc pairs: %ld\n", a, d, allocs)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue