Skip to content

Commit

Permalink
Introduced realloc0 and reallocShared0, these procs are now used by
Browse files Browse the repository at this point in the history
strs_v2 and seqs_v2. This also allowed the -d:useMalloc allocator to
drop the extra header with allocation length.
  • Loading branch information
zevv committed Jan 19, 2020
1 parent 7c22f51 commit a4e16b3
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 39 deletions.
20 changes: 19 additions & 1 deletion lib/system/alloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -1009,6 +1014,11 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
proc realloc(p: pointer, newSize: Natural): pointer =
result = realloc(allocator, p, newSize)

proc realloc0(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 =
# only used for assertions
Expand Down Expand Up @@ -1062,6 +1072,14 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
else:
result = realloc(p, newSize)

proc reallocShared0(p: pointer, oldSize, newSize: Natural): pointer =
when hasThreadSupport:
acquireSys(heapLock)
result = realloc0(sharedHeap, p, oldSize, newSize)
releaseSys(heapLock)
else:
result = realloc0(p, oldSize, newSize)

when hasThreadSupport:
template sharedMemStatsShared(v: int) =
acquireSys(heapLock)
Expand Down
2 changes: 2 additions & 0 deletions lib/system/ansi_c.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 {.
Expand Down
31 changes: 31 additions & 0 deletions lib/system/memalloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ when hasAlloc:
## The allocated memory belongs to its allocating thread!
## Use `reallocShared <#reallocShared,pointer,Natural>`_ to reallocate
## from a shared heap.
proc realloc0*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
## 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.
proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign, raises: [].} =
## Grows or shrinks a given memory block.
##
Expand Down Expand Up @@ -185,6 +201,19 @@ when hasAlloc:
## ``deallocShared(p)``.
## In other cases the block has to be freed with
## `deallocShared <#deallocShared,pointer>`_.
proc reallocShared0*(p: pointer, oldSize, newSize: Natural): pointer {.noconv, rtl, tags: [],
benign, raises: [].}
## 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>`_.
proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline, raises: [].} =
## Grows or shrinks a given memory block on the heap.
##
Expand Down Expand Up @@ -239,11 +268,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:
Expand Down
61 changes: 25 additions & 36 deletions lib/system/mmdisp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,18 @@ when defined(boehmgc):
proc realloc(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 realloc0(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 dealloc(p: pointer) = boehmDealloc(p)

proc allocShared(size: Natural): pointer = alloc(size)
proc allocShared0(size: Natural): pointer = alloc(size)
proc reallocShared(p: pointer, newSize: Natural): pointer = realloc(p, newSize)
proc reallocShared0(p: pointer, oldSize, newSize: Natural): pointer = realloc0(p, newSize, oldSize)
proc deallocShared(p: pointer) = dealloc(p)

when hasThreadSupport:
proc getFreeSharedMem(): int =
Expand Down Expand Up @@ -274,6 +275,9 @@ elif defined(gogc):
proc realloc(p: pointer, newsize: Natural): pointer =
doAssert false, "not implemented"

proc realloc0(p: pointer, oldsize, newsize: Natural): pointer =
doAssert false, "not implemented"

proc dealloc(p: pointer) =
discard

Expand All @@ -286,6 +290,9 @@ elif defined(gogc):
proc reallocShared(p: pointer, newsize: Natural): pointer =
result = realloc(p, newsize)

proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer =
result = realloc0(p, oldsize, newsize)

proc deallocShared(p: pointer) = dealloc(p)

when hasThreadSupport:
Expand Down Expand Up @@ -356,39 +363,21 @@ elif defined(gogc):

elif (defined(nogc) or defined(gcDestructors)) and defined(useMalloc):

# libc realloc() does not zero out memory, so this is handled here. Every
# allocated buffer is prepended with the size of the allocation which is used
# to deduce which part of the buffer to zero.

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 alloc(size: Natural): pointer = c_malloc(size.csize_t)
proc alloc0(size: Natural): pointer = c_calloc(size.csize_t, 1)
proc realloc(p: pointer, newsize: Natural): pointer = c_realloc(p, newSize.csize_t)
proc realloc0(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 dealloc(p: pointer) = c_free(p)

proc dealloc(p: pointer) = c_free(cast[pointer](cast[int](p) - sizeof(int)))

# Shared allocators map to the regular ones

proc allocShared(size: Natural): pointer = alloc(size.csize_t)
proc allocShared(size: Natural): pointer = alloc(size)
proc allocShared0(size: Natural): pointer = alloc0(size)
proc reallocShared(p: pointer, newsize: Natural): pointer = realloc(p, newsize.csize_t)
proc reallocShared(p: pointer, newsize: Natural): pointer = realloc(p, newsize)
proc reallocShared0(p: pointer, oldsize, newsize: Natural): pointer = realloc0(p, oldsize, newsize)
proc deallocShared(p: pointer) = dealloc(p)

proc GC_disable() = discard
Expand Down
4 changes: 3 additions & 1 deletion lib/system/seqs_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
q.cap = cap
result = q
else:
var q = cast[ptr NimSeqPayloadBase](reallocShared(p, headerSize + elemSize * cap))
let oldSize = headerSize + elemSize * p.cap
let newSize = headerSize + elemSize * cap
var q = cast[ptr NimSeqPayloadBase](reallocShared0(p, oldSize, newSize))
q.allocated = 1
q.cap = cap
result = q
Expand Down
2 changes: 1 addition & 1 deletion lib/system/strs_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
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](reallocShared(s.p, contentSize(cap)))
s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(s.p.cap), contentSize(cap)))
s.p.cap = cap

proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
Expand Down

0 comments on commit a4e16b3

Please sign in to comment.