Skip to content

Commit

Permalink
Cleanup, remove lib/system/allocators.nim. seqs_v2 and strs_v2 now use
Browse files Browse the repository at this point in the history
allocShared0 by default.
  • Loading branch information
zevv committed Jan 18, 2020
1 parent 107352f commit 6751721
Show file tree
Hide file tree
Showing 18 changed files with 72 additions and 202 deletions.
12 changes: 6 additions & 6 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2037,15 +2037,15 @@ proc genDestroy(p: BProc; n: PNode) =
of tyString:
var a: TLoc
initLocExpr(p, arg, a)
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
" $1.p->allocator->dealloc($1.p->allocator, $1.p, $1.p->cap + 1 + sizeof(NI) + sizeof(void*));$n" &
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocated) {$n" &
" #deallocShared($1.p);$n" &
" $1.p = NIM_NIL; }$n",
[rdLoc(a)])
of tySequence:
var a: TLoc
initLocExpr(p, arg, a)
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocator) {$n" &
" $1.p->allocator->dealloc($1.p->allocator, $1.p, ($1.p->cap * sizeof($2)) + sizeof(NI) + sizeof(void*));$n" &
linefmt(p, cpsStmts, "if ($1.p && $1.p->allocated) {$n" &
" #deallocShared($1.p);$n" &
" $1.p = NIM_NIL; }$n",
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
else: discard "nothing to do"
Expand Down Expand Up @@ -2884,8 +2884,8 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool): Rope =

appcg(p.module, cfsData,
"static $5 struct {$n" &
" NI cap; void* allocator; $1 data[$2];$n" &
"} $3 = {$2, NIM_NIL, $4};$n", [
" NI cap; NI allocated; $1 data[$2];$n" &
"} $3 = {$2, 0, $4};$n", [
getTypeDesc(p.module, base), n.len, payload, data,
if isConst: "const" else: ""])
result = "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload]
Expand Down
4 changes: 2 additions & 2 deletions compiler/ccgliterals.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =

proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
m.s[cfsData].addf("static $4 struct {$n" &
" NI cap; void* allocator; NIM_CHAR data[$2+1];$n" &
"} $1 = { $2, NIM_NIL, $3 };$n",
" NI cap; NI allocated; NIM_CHAR data[$2+1];$n" &
"} $1 = { $2, 0, $3 };$n",
[result, rope(s.len), makeCString(s),
rope(if isConst: "const" else: "")])

Expand Down
2 changes: 1 addition & 1 deletion compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) =
appcg(m, m.s[cfsTypes], """$N
$3ifndef $2_Content_PP
$3define $2_Content_PP
struct $2_Content { NI cap;#AllocatorObj* allocator;$1 data[SEQ_DECL_SIZE];};
struct $2_Content { NI cap;NI allocated;$1 data[SEQ_DECL_SIZE];};
$3endif$N
""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check), result, rope"#"])

Expand Down
8 changes: 8 additions & 0 deletions lib/system/alloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -997,13 +997,21 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =

proc deallocOsPages = deallocOsPages(allocator)

proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}

proc alloc(size: Natural): pointer =
result = alloc(allocator, size)
if c_getenv("DUMP") != nil:
cfprintf(cstderr, "alloc %p: %d\n", result, size);

proc alloc0(size: Natural): pointer =
result = alloc0(allocator, size)
if c_getenv("DUMP") != nil:
cfprintf(cstderr, "alloc %p: %d\n", result, size);

proc dealloc(p: pointer) =
if c_getenv("DUMP") != nil:
cfprintf(cstderr, "dealloc %p\n", p);
dealloc(allocator, p)

proc realloc(p: pointer, newSize: Natural): pointer =
Expand Down
86 changes: 0 additions & 86 deletions lib/system/allocators.nim

This file was deleted.

4 changes: 2 additions & 2 deletions lib/system/memalloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ when hasAlloc:
## The freed memory must belong to its allocating thread!
## Use `deallocShared <#deallocShared,pointer>`_ to deallocate from a shared heap.

proc allocShared*(size: Natural): pointer {.noconv, rtl, benign, raises: [], tags: [].}
proc allocShared*(size: Natural): pointer {.noconv, compilerproc, rtl, benign, raises: [], tags: [].}
## Allocates a new memory block on the shared heap with at
## least ``size`` bytes.
##
Expand Down Expand Up @@ -196,7 +196,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``.
##
Expand Down
40 changes: 17 additions & 23 deletions lib/system/seqs_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@


# 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
allocated: int

NimSeqPayload[T] = object
cap: int
allocator: Allocator
allocated: int
data: UncheckedArray[T]

NimSeqV2*[T] = object
Expand All @@ -26,22 +31,16 @@ type

const nimSeqVersion {.core.} = 2

template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator)
template payloadSize(cap): int = cap * sizeof(T) + sizeof(NimSeqPayloadBase)

# 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.allocated = 1
p.cap = cap
result = p
else:
Expand All @@ -53,30 +52,25 @@ 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:
result = newSeqPayload(len+addlen, elemSize)
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)
var p = cast[ptr NimSeqPayloadBase](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))
if p.allocated == 0:
var q = cast[ptr NimSeqPayloadBase](allocShared0(headerSize + elemSize * cap))
copyMem(q +! headerSize, p +! headerSize, len * elemSize)
q.allocator = allocator
q.allocated = 1
q.cap = cap
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
var q = cast[ptr NimSeqPayloadBase](reallocShared(p, headerSize + elemSize * cap))
q.allocated = 1
q.cap = cap
result = q

Expand Down
50 changes: 22 additions & 28 deletions lib/system/strs_v2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

## Default new string implementation used by Nim's core.

import allocators

type
NimStrPayloadBase = object
cap: int
allocated: int

NimStrPayload {.core.} = object
cap: int
allocator: Allocator
allocated: int
data: UncheckedArray[char]

NimStringV2 {.core.} = object
Expand All @@ -23,13 +25,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.allocated == 0

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
Expand All @@ -41,18 +43,15 @@ 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.allocated = 1
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 = cast[ptr NimStrPayload](reallocShared(s.p, contentSize(cap)))
s.p.cap = cap

proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl.} =
Expand All @@ -65,9 +64,8 @@ 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.allocated = 1
p.cap = len
if len > 0:
# we are about to append, so there is no need to copy the \0 terminator:
Expand Down Expand Up @@ -98,19 +96,17 @@ 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.allocated = 1
p.cap = space
result = NimStringV2(len: 0, p: p)

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.allocated = 1
p.cap = len
result = NimStringV2(len: len, p: p)

Expand All @@ -131,23 +127,21 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
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()
# 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.allocated = 1
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.allocated == 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)))
s.p.allocator = allocator
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
s.p.allocated = 1
s.p.cap = s.len
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
Loading

0 comments on commit 6751721

Please sign in to comment.